ATLAS Offline Software
Loops.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #ifndef XAOD_ANALYSIS
6 #ifndef TRUTHUTILS_LOOPS_H
7 #define TRUTHUTILS_LOOPS_H
8 #include <algorithm>
9 #include <vector>
10 #include <memory>
11 
12 namespace MC {
13 template <class Evt, class Prt, class Vtx>
14 class Loops {
15 public:
16 
18  Loops() {}
19 
21  Loops(const Evt* evt) {
22  findLoops(evt,true);
23  }
24 
26  bool isLoop(const Prt& p) const {
27  return std::find(m_loop_particles.begin(), m_loop_particles.end(), p) != m_loop_particles.end();
28  }
29 
31  bool isLoop(const Vtx& v) const {
32  return std::find(m_loop_vertices.begin(), m_loop_vertices.end(), v) != m_loop_vertices.end();
33  }
34 
36  const std::vector<Prt>& loop_particles() const {
37  return m_loop_particles;
38  }
39 
41  const std::vector<Vtx>& loop_vertices() const {
42  return m_loop_vertices;
43  }
44 
47  int findLoops(const Evt* evt, bool force) {
48  // If the event is empty, return -1 (an error code, basically)
49  if (!evt) return -1;
50  // If we have already indexed the event and are not forced to do it again, return
51  if (evt == m_evt && !force) return 0;
52 
53  // Update the local event pointer. This is now the most recent event that has been indexed.
54  m_evt = evt;
55  // Clear the lists of particles and vertices. These will now refer to this event.
56  m_loop_particles.clear();
57  m_loop_vertices.clear();
58 
59  // Create a map, keeping track of whether particles are in loops.
60  // 0 for "unknown", 1 for "in a loop", -1 for "not in a loop"
61  std::map<Prt, int> incycle;
62 
63  // Easiest case to deal with: if a particle has no production or end vertex, it is not in a loop
64  for (const auto & p: *m_evt){
65  if (!p->end_vertex()||!p->production_vertex()){
66  incycle[p] = -1;
67  } else {
68  incycle[p] = 0;
69  }
70  }
71 
72  // Now begin interating through particles to try to find loops
73  size_t minincycle = m_evt->particles_size();
74  for (;;) {
75  // Number of particles still unknown in the current iteration
76  size_t unknown = 0;
77  for (const auto & p: *m_evt) {
78 
79  // If the particle was already identified as in/not in a loop, skip it
80  if (incycle[p] != 0) continue;
81  // Otherwise it is unknown on this iteration
82  unknown++;
83 
84  // Start from the end vertex of the particle
85  auto ev = p->end_vertex();
86  if (ev) {
87  // If the end vertex of a particle exclusively has particles not in loops
88  // then this particle cannot be in a loop either
89  bool goodo = true;
90  for (auto& po: *ev) goodo = goodo && (incycle[po] == -1);
91  if (goodo) incycle[p] = -1;
92  }
93 
94  // Now start from the production vertex of the particle
95  auto pv = p->production_vertex();
96  if (pv) {
97  // If the production vertex of a particle exclusively has particles not
98  // in loops, then this particle cannot be in a loop either
99  bool goodi = true;
100 #ifdef HEPMC3
101  for (auto& pi: ev->particles_in()) goodi = goodi && (incycle[pi] == -1);
102 #else
103  for (auto ip = ev->particles_in_const_begin();
104  ip != ev->particles_in_const_end();
105  ++ip)
106  {
107  goodi = goodi && (incycle[*ip] == -1);
108  }
109 #endif
110  if (goodi) incycle[p] = -1;
111  }
112  }
113  // If the number of unknown particles has not changed, we are done iterating
114  if (minincycle == unknown) break;
115  // If the number of unknown particles has changed, update at iterate again
116  minincycle = std::min(minincycle, unknown);
117  } // Outer loop - iterate until all particles have been dealt with
118 
119  // Any remaining particles that have not been identified are a part of a loop
120  // Add them to our list of looping particles
121  for (const auto & p: *m_evt){
122  if (incycle[p] == 0) incycle[p] = 1;
123  if (incycle[p] == 1) m_loop_particles.push_back(p);
124  }
125 
126  // Now loop over all vertices.
127 #ifdef HEPMC3
128  for (auto & v: m_evt->vertices()) {
129 #else
130  for (auto iv = m_evt->vertices_begin(); iv != m_evt->vertices_end(); ++iv) {
131  auto v = *iv;
132 #endif
133  bool push = false;
134  // First check incoming particles.
135  // If any incoming are in loops, consider this vertex to be in a loop.
136 #ifdef HEPMC3
137  for ( auto& pin: v->particles_in()){
138  if (incycle[pin] == 1) {
139 #else
140  for ( auto ipin = v->particles_in_const_begin();
141  ipin != v->particles_in_const_end();
142  ++ipin){
143  if (incycle[*ipin] == 1) {
144 #endif
145  push = true;
146  break;
147  }
148  } // End of loop over incoming particles
149  // In case we have not yet identified the vertex as being in a loop
150  // then check the outgoing particles from the vertex.
151  // If any outgoing are in loops, consider this vertex to be in a loop.
152  if(!push) {
153  for ( const auto& pou: *v) {
154  if (incycle[pou] == 1) {
155  push = true;
156  break;
157  }
158  }
159  }
160  // Update the records if this vertex is in a loop.
161  if (push) m_loop_vertices.push_back(v);
162  } // End of loop over vertices
163 
164  // All finished. Return success.
165  return 0;
166  } // End of the findLoops function
167 
168 private:
169 
171  const Evt* m_evt = nullptr;
172 
174  std::vector<Prt> m_loop_particles;
175 
177  std::vector<Vtx> m_loop_vertices;
178 };
179 }
180 #endif
181 #endif
MC::Loops::isLoop
bool isLoop(const Vtx &v) const
Is this vertex in a loop?
Definition: Loops.h:31
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:138
Vtx
calibdata.force
bool force
Definition: calibdata.py:18
MC::Loops::m_loop_vertices
std::vector< Vtx > m_loop_vertices
List of all vertices in m_evt that are in loops.
Definition: Loops.h:177
min
constexpr double min()
Definition: ap_fixedTest.cxx:26
LArG4FSStartPointFilter.evt
evt
Definition: LArG4FSStartPointFilter.py:42
MC
Definition: HepMCHelpers.h:19
pi
#define pi
Definition: TileMuonFitter.cxx:65
MC::Loops::Loops
Loops()
Default constructor.
Definition: Loops.h:18
MC::Loops::m_loop_particles
std::vector< Prt > m_loop_particles
List of all particles in m_evt that are in loops.
Definition: Loops.h:174
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
ev
int ev
Definition: globals.cxx:25
find_tgc_unfilled_channelids.ip
ip
Definition: find_tgc_unfilled_channelids.py:3
MC::Loops::m_evt
const Evt * m_evt
Local pointer to the event passed in the constructor or most recent call to findLoops.
Definition: Loops.h:171
Muon::nsw::unknown
@ unknown
Definition: NSWTriggerElink.h:36
MC::Loops::loop_particles
const std::vector< Prt > & loop_particles() const
Accessor: return the full list of particles in loops.
Definition: Loops.h:36
MC::Loops::isLoop
bool isLoop(const Prt &p) const
Is this particle in a loop?
Definition: Loops.h:26
python.PyAthena.v
v
Definition: PyAthena.py:154
MC::Loops::loop_vertices
const std::vector< Vtx > & loop_vertices() const
Accessor: return the full list of vertices in loops.
Definition: Loops.h:41
MC::Loops
Definition: Loops.h:14
python.changerun.pv
pv
Definition: changerun.py:79
MC::Loops::findLoops
int findLoops(const Evt *evt, bool force)
Function that does the work to identify loops Pass the event of interest.
Definition: Loops.h:47
MC::Loops::Loops
Loops(const Evt *evt)
Constructor passing the event; immediately index the event that is passed.
Definition: Loops.h:21