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