Belle II Software light-2607-kasei
MCParticleGraph.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <mdst/dataobjects/MCParticleGraph.h>
10
11#include <framework/datastore/StoreArray.h>
12#include <framework/logging/Logger.h>
13
14#include <boost/graph/graph_traits.hpp>
15#include <boost/graph/adjacency_list.hpp>
16#include <boost/graph/depth_first_search.hpp>
17
18#include <limits>
19#include <vector>
20#include <queue>
21
22
23using namespace std;
24using namespace Belle2;
25
27struct cycle_detector : public boost::dfs_visitor<> {
35 template <class Edge, class Graph> void back_edge(Edge, Graph&) { throw MCParticleGraph::CyclicReferenceError(); }
36};
37
38
49
50public:
51
59 ParticleSorter(MemoryPool<MCParticleGraph::GraphParticle>& particles, TClonesArray* plist, bool setVertex, bool setTime):
60 m_index(0), m_particles(particles), m_plist(plist), m_setVertex(setVertex), m_setTime(setTime) {}
61
67 void setStartIndex(int index) { m_index = index; }
68
73 template <class Graph> void sort(Graph& g)
74 {
75 //Set seen flag for all vertices to false
76 m_seen.clear();
77 m_seen.resize(num_vertices(g), false);
78
79 //Create a dummy GraphParticle, needed only to find all primary particles
81
82 //Add all direct children of the 0th vertex to the queue.
83 //This are the primary particles
84 find_daughters(0, g, dummy);
85
86 //Go through the queue and write out each particle.
87 //Daughters of particles will be added to the queue by find_daughters
88 while (!m_vqueue.empty()) {
89 unsigned int cur = m_vqueue.front();
90 m_vqueue.pop();
91 finish_vertex(cur, g);
92 }
93 }
94
95
101 template <class Vertex, class Graph> void finish_vertex(Vertex v, Graph& g)
102 {
104
105 //Reset daughter information, will be filled by find_daughters
106 p.setFirstDaughter(0);
107 p.setLastDaughter(0);
108 //Find all direct daughters
109 find_daughters(v, g, p);
110
111 //If stable particle, set decaytime to infinity
112 if (out_degree(v, g) == 0 && m_setTime) {
113 p.setDecayTime(numeric_limits<double>::infinity());
114 }
115 //If given a pointer to a TClonesArray, create MCParticle at the appropriate index position
116 if (m_plist) {
117 new (m_plist->AddrAt(p.getIndex() - 1)) MCParticle(m_plist, p);
118 }
119 }
120
121
128 template <class Vertex, class Graph> void find_daughters(Vertex v, Graph& g, MCParticleGraph::GraphParticle& mother)
129 {
130 //References to the daughter information of the mother for easier access
131 int& d1 = mother.m_firstDaughter;
132 // writes through this reference modify mother.m_lastDaughter, which cppcheck does not track
133 // cppcheck-suppress unreadVariable
134 int& d2 = mother.m_lastDaughter;
135
136 typename boost::graph_traits<Graph>::out_edge_iterator j, j_end;
137 for (tie(j, j_end) = out_edges(v, g); j != j_end; ++j) {
138 //Get daughter particle from list
139 Vertex nv = target(*j, g);
140 MCParticleGraph::GraphParticle& daughter = *m_particles[nv - 1];
141
142 if (daughter.m_ignore) {
143 //daughter ignored, search its children and treat them as direct children of mother
144 //if we haven't seen this particle yet, set its index to that of its last unignored parent
145 if (!m_seen[nv]) daughter.setIndex(mother.getIndex());
146 find_daughters(nv, g, mother);
147 } else {
148 //If we didn't see this particle already, set its index and add it to the queue for writing out
149 if (!m_seen[nv]) {
150 daughter.setIndex(++m_index);
151 m_vqueue.push(nv);
152 }
153 //Set daughter information of mother. If 0, no daughters yet so just take current daughter as only
154 //daughter. Otherwise allow extension of daughter information in both directions.
155 if (d1 == 0) {
156 d1 = daughter.getIndex();
157 d2 = d1;
158 } else if ((d2 + 1) == daughter.getIndex()) {
159 ++d2;
160 } else if ((d1 - 1) == daughter.getIndex()) {
161 --d1;
162 } else {
163 //Daughter indices are not continuous, cannot continue
164 throw MCParticleGraph::NonContinousDaughtersError();
165 }
166 //Set Vertex and time information if requested
167 setVertexTime(mother, daughter);
168 daughter.m_mother = mother.getIndex();
169 }
170 //Mark particle as seen
171 m_seen[nv] = true;
172 }
173 }
174
175
182 {
183 //Only set vertex information if both particles have a valid vertex set
184 m.setValidVertex(m.hasValidVertex() && d.hasValidVertex());
185 if (m.hasValidVertex() && d.getProductionTime() >= m.getDecayTime()) {
186 if (m_setVertex) {
187 m.setDecayVertex(d.getProductionVertex());
188 }
189 if (m_setTime) {
190 m.setDecayTime(d.getProductionTime());
191 }
192 }
193 }
194
195
196protected:
197
200 TClonesArray*
204 vector<bool>
206 std::queue<unsigned int> m_vqueue;
207};
208
209
210void MCParticleGraph::generateList(const string& name, int options)
211{
212 StoreArray<MCParticle> MCParticles(name);
213
214 //Make Graph and connect all primary vertices (particles without mother)
215 //to an artificial 0ths vertex to be able to find them easily
216 typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> Graph;
217 int num_particles(0);
218 //Determine number of not ignored particles and add an edge from 0ths vertex to any primary
219 //particle
220 for (unsigned int i = 0; i < m_particles.size(); ++i) {
221 if (!m_particles[i]->m_ignore) ++num_particles;
222 if (m_particles[i]->m_primary) m_decays.insert(DecayLine(0, i + 1));
223 }
224 Graph g(m_decays.begin(), m_decays.end(), m_particles.size() + 1);
225
226 //Check for cyclic dependency
227 if (options & c_checkCyclic) {
228 cycle_detector vis;
229 depth_first_search(g, visitor(vis));
230 }
231
232 //Fill TClonesArray in correct order
233 if (options & c_clearParticles) MCParticles.getPtr()->Clear();
234 MCParticles.getPtr()->Expand(num_particles + MCParticles.getEntries());
235 MCParticleGraph::ParticleSorter psorter(m_particles, MCParticles.getPtr(), options & c_setDecayVertex, options & c_setDecayTime);
236 psorter.setStartIndex(MCParticles.getEntries());
237 psorter.sort(g);
238}
239
240void MCParticleGraph::loadList(const string& name)
241{
242 StoreArray<MCParticle> MCParticles(name);
243 if (!MCParticles) {
244 B2ERROR("MCParticle Collection is not valid, cannot load into Graph");
245 return;
246 }
247
248 unsigned numParticles = MCParticles.getEntries();
249 unsigned particleOffset = size();
250 //Here we assume that the MCParticle collection is somehow ordered: All
251 //particles which are product of a decay come in the list after the mother,
252 //thus having a higher index. This is true for all lists generated by the
253 //MCParticleGraph and also for the standard lists produced by Evtgen and
254 //similar generators.
255 for (unsigned i = 0; i < numParticles; ++i) {
256 GraphParticle& newParticle = addParticle();
257 const MCParticle& oldParticle = *MCParticles[i];
258 //Copy all values
259 newParticle = oldParticle;
260 //If this particle has a mother we just add the decay to this mother
261 const MCParticle* oldMother = oldParticle.getMother();
262 if (oldMother != nullptr) {
263 unsigned motherIndex = oldMother->getArrayIndex() + particleOffset;
264 if (motherIndex >= size())
265 B2FATAL("MCParticle collection \"" << name << "\" not sorted correctly: mother index larger than daughter. Cannot load into Graph");
266 newParticle.comesFrom((*this)[oldMother->getArrayIndex() + particleOffset]);
267 }
268 }
269}
Class to represent Particle data in graph.
void comesFrom(GraphParticle &mother)
Tells the graph that this particle is a decay product of mother.
Class to go over all the particles in the Graph an sort them in a sensible way.
void setVertexTime(MCParticleGraph::GraphParticle &m, const MCParticleGraph::GraphParticle &d)
Set the vertex and time information of the mother particle.
ParticleSorter(MemoryPool< MCParticleGraph::GraphParticle > &particles, TClonesArray *plist, bool setVertex, bool setTime)
ParticleSorter constructor.
MemoryPool< MCParticleGraph::GraphParticle > & m_particles
Reference to the list of particles which should be sorted.
void find_daughters(Vertex v, Graph &g, MCParticleGraph::GraphParticle &mother)
Find the daughters of the given vertex.
void finish_vertex(Vertex v, Graph &g)
Go through the daughters of the vertex.
bool m_setTime
True if the production time information should be saved.
std::queue< unsigned int > m_vqueue
The list of the vertices that will be visited.
vector< bool > m_seen
Vector of the particles that were already seen while sorting the graph.
void setStartIndex(int index)
Set the starting index for the particle graph.
int m_index
The latest index given to a particle.
bool m_setVertex
True if the vertex information should be saved.
TClonesArray * m_plist
The final array of sorted particles which is stored in the DataStore.
void sort(Graph &g)
Sort the particles and generate MCParticle list.
@ c_setDecayVertex
Set the decay vertex to the production vertex of the last daughter (ordered by production time)
@ c_setDecayTime
Set decay time to the largest production time of the daughters.
@ c_checkCyclic
Check for cyclic dependencies.
@ c_clearParticles
Clear the particle list before adding the graph.
size_t size() const
Return the number of particles in the graph.
std::pair< unsigned int, unsigned int > DecayLine
Type representing a decay in the graph.
void loadList(const std::string &name="")
Load the MCParticle list given by name into the Graph.
std::set< DecayLine > m_decays
internal set of decay lines
MemoryPool< GraphParticle > m_particles
internal list of particles
void generateList(const std::string &name="", int options=c_setNothing)
Generates the MCParticle list and stores it in the StoreArray with the given name.
A Class to store the Monte Carlo particle information.
Definition MCParticle.h:32
int m_lastDaughter
1-based index of last daughter particle in collection, 0 if no daughters
Definition MCParticle.h:549
int getIndex() const
Get 1-based index of the particle in the corresponding MCParticle list.
Definition MCParticle.h:219
int m_firstDaughter
1-based index of first daughter particle in collection, 0 if no daughters
Definition MCParticle.h:548
int getArrayIndex() const
Get 0-based index of the particle in the corresponding MCParticle list.
Definition MCParticle.h:234
ROOT::Math::XYZVector getProductionVertex() const
Return production vertex position.
Definition MCParticle.h:178
bool hasValidVertex() const
Indication whether vertex and time information is useful or just default.
Definition MCParticle.h:142
float getProductionTime() const
Return production time in ns.
Definition MCParticle.h:148
Class to provide a constant access time memory pool for one kind of objects.
Definition MemoryPool.h:33
Accessor to arrays stored in the data store.
Definition StoreArray.h:113
TClonesArray * getPtr() const
Raw access to the underlying TClonesArray.
Definition StoreArray.h:311
int getEntries() const
Get the number of objects in the array.
Definition StoreArray.h:216
MCParticle * getMother() const
Returns a pointer to the mother particle.
Definition MCParticle.h:591
GraphParticle & addParticle()
Add new particle to the graph.
Abstract base class for different kinds of events.
STL namespace.
Simple struct to check boost graph for cyclic references.
void back_edge(Edge, Graph &)
This method is invoked on back edges in the graph.