Belle II Software  release-05-02-19
MCDecayFinderModule.cc
1 /**************************************************************************
2 * BASF2 (Belle Analysis Framework 2) *
3 * Copyright(C) 2010 - Belle II Collaboration *
4 * *
5 * Author: The Belle II Collaboration *
6 * Contributors: Christian Oswald, Marko Staric, Phillip Urquijo, Yo Sato *
7 * *
8 * This software is provided "as is" without any warranty. *
9 **************************************************************************/
10 
11 #include <analysis/modules/MCDecayFinder/MCDecayFinderModule.h>
12 #include <analysis/dataobjects/ParticleList.h>
13 #include <analysis/dataobjects/ParticleExtraInfoMap.h>
14 #include <framework/datastore/StoreObjPtr.h>
15 #include <framework/datastore/StoreArray.h>
16 #include <framework/gearbox/Const.h>
17 #include <mdst/dataobjects/MCParticle.h>
18 #include <analysis/DecayDescriptor/ParticleListName.h>
19 #include <analysis/utility/EvtPDLUtil.h>
20 #include <analysis/utility/MCMatching.h>
21 
22 #include <string>
23 #include <memory>
24 
25 using namespace std;
26 using namespace Belle2;
27 
28 // Register module in the framework
29 REG_MODULE(MCDecayFinder)
30 
31 MCDecayFinderModule::MCDecayFinderModule() : Module(), m_isSelfConjugatedParticle(false)
32 {
33  //Set module properties
34  setDescription("Find decays in MCParticle list matching a given DecayString and create Particles from them.");
35  //Parameter definition
36  addParam("decayString", m_strDecay, "DecayDescriptor string.");
37  addParam("listName", m_listName, "Name of the output particle list");
38  addParam("writeOut", m_writeOut,
39  "If true, the output ParticleList will be saved by RootOutput. If false, it will be ignored when writing the file.", false);
40 }
41 
42 void MCDecayFinderModule::initialize()
43 {
44  m_decaydescriptor.init(m_strDecay);
45 
46  m_antiListName = ParticleListName::antiParticleListName(m_listName);
47  m_isSelfConjugatedParticle = (m_listName == m_antiListName);
48 
49  B2DEBUG(10, "particle list name: " << m_listName);
50  B2DEBUG(10, "antiparticle list name: " << m_antiListName);
51 
52 
53  // Register output particle list, particle store and relation to MCParticles
54  StoreObjPtr<ParticleList> particleList(m_listName);
55  StoreArray<Particle> particles;
57  StoreArray<MCParticle> mcparticles;
58  mcparticles.isRequired();
59 
60  DataStore::EStoreFlags flags = m_writeOut ? DataStore::c_WriteOut : DataStore::c_DontWriteOut;
61  particleList.registerInDataStore(flags);
62  particles.registerInDataStore(flags);
63  extraInfoMap.registerInDataStore();
64  particles.registerRelationTo(mcparticles, DataStore::c_Event, flags);
65 
66  if (!m_isSelfConjugatedParticle) {
67  StoreObjPtr<ParticleList> antiParticleList(m_antiListName);
68  antiParticleList.registerInDataStore(flags);
69  }
70 }
71 
72 void MCDecayFinderModule::event()
73 {
74  // particle store (working space)
75  StoreArray<Particle> particles(m_particleStore);
76 
77  // Get output particle list
78  StoreObjPtr<ParticleList> outputList(m_listName);
79  outputList.create();
80  outputList->initialize(m_decaydescriptor.getMother()->getPDGCode(), m_listName);
81 
82  if (!m_isSelfConjugatedParticle) {
83  StoreObjPtr<ParticleList> antiOutputList(m_antiListName);
84  antiOutputList.create();
85  antiOutputList->initialize(-1 * m_decaydescriptor.getMother()->getPDGCode(), m_antiListName);
86  outputList->bindAntiParticleList(*(antiOutputList));
87  }
88 
89  // loop over all MCParticles
90  StoreArray<MCParticle> mcparticles;
91  int nMCParticles = mcparticles.getEntries();
92  for (int i = 0; i < nMCParticles; i++) {
93  for (int iCC = 0; iCC < 2; iCC++) {
94  std::unique_ptr<DecayTree<MCParticle>> decay(match(mcparticles[i], m_decaydescriptor, iCC));
95  if (decay->getObj()) {
96  B2DEBUG(19, "Match!");
97  int iIndex = write(decay.get());
98  outputList->addParticle(particles[iIndex]);
99  }
100  }
101  }
102 }
103 
104 DecayTree<MCParticle>* MCDecayFinderModule::match(const MCParticle* mcp, const DecayDescriptor* d, bool isCC)
105 {
106  // Suffixes used in this method:
107  // P = Information from MCParticle
108  // D = Information from DecayDescriptor
109 
110  // Create empty DecayTree as return value
111  auto* decay = new DecayTree<MCParticle>();
112 
113  // Load PDG codes and compare,
114  int iPDGD = d->getMother()->getPDGCode();
115  int iPDGP = mcp->getPDG();
116 
117  bool isSelfConjugatedParticle = !(EvtPDLUtil::hasAntiParticle(iPDGD));
118 
119  if (!isCC && iPDGD != iPDGP) return decay;
120  else if (isCC && (iPDGD != -iPDGP && !isSelfConjugatedParticle)) return decay;
121  else if (isCC && (iPDGD != iPDGP && isSelfConjugatedParticle)) return decay;
122  B2DEBUG(19, "PDG code matched: " << iPDGP);
123 
124  // Get number of daughters in the decay descriptor.
125  // If no daughters in decay descriptor, no more checks needed.
126  int nDaughtersD = d->getNDaughters();
127  if (nDaughtersD == 0) {
128  B2DEBUG(19, "DecayDescriptor has no Daughters, everything OK!");
129  decay->setObj(const_cast<MCParticle*>(mcp));
130  return decay;
131  }
132  // Get number of daughter recursively if missing intermediate states are accepted.
133  int nDaughtersRecursiveD = nDaughtersD;
134  if (d->isIgnoreIntermediate()) {
135  nDaughtersRecursiveD = getNDaughtersRecursive(d);
136  }
137 
138  // Get daughters of MCParticle
139  vector<const MCParticle*> daughtersP;
140  if (d->isIgnoreIntermediate()) {
141  appendParticles(mcp, daughtersP);
142  } else {
143  const vector<MCParticle*>& tmpDaughtersP = mcp->getDaughters();
144  for (auto daug : tmpDaughtersP)
145  daughtersP.push_back(daug);
146  }
147 
148  // The MCParticle must have at least as many daughters as the decaydescriptor
149  int nDaughtersP = daughtersP.size();
150  if (nDaughtersRecursiveD > nDaughtersP) {
151  B2DEBUG(10, "DecayDescriptor has more daughters than MCParticle!");
152  return decay;
153  }
154 
155  // loop over all daughters of the decay descriptor
156  for (int iDD = 0; iDD < nDaughtersD; iDD++) {
157  // check if there is an unmatched particle daughter matching this decay descriptor daughter
158  bool isMatchDaughter = false;
159  auto itDP = daughtersP.begin();
160  while (itDP != daughtersP.end()) {
161  const MCParticle* daugP = *itDP;
162  DecayTree<MCParticle>* daughter = match(daugP, d->getDaughter(iDD), isCC);
163  if (!daughter->getObj()) {
164  ++itDP;
165  continue;
166  }
167  // Matching daughter found, remove it from list of unmatched particle daughters
168  decay->append(daughter);
169  isMatchDaughter = true;
170  itDP = daughtersP.erase(itDP);
171 
172  // if the matched daughter has daughters, they are also removed from the list
173  if (d->isIgnoreIntermediate() and d->getDaughter(iDD)->getNDaughters() != 0) {
174  vector<const MCParticle*> grandDaughtersP;
175  if (d->getDaughter(iDD)->isIgnoreIntermediate()) {
176  appendParticles(daugP, grandDaughtersP);
177  } else {
178  const vector<MCParticle*>& tmpGrandDaughtersP = daugP->getDaughters();
179  for (auto grandDaugP : tmpGrandDaughtersP)
180  grandDaughtersP.push_back(grandDaugP);
181  }
182 
183  for (auto grandDaugP : grandDaughtersP) {
184  auto jtDP = itDP;
185  while (jtDP != daughtersP.end()) {
186  const MCParticle* daugP_j = *jtDP;
187  // if a grand-daughter matched a daughter, remove it.
188  if (grandDaugP == daugP_j)
189  jtDP = daughtersP.erase(jtDP);
190  else
191  ++jtDP;
192  }
193  }
194  }
195 
196  break;
197  }
198  if (!isMatchDaughter) {
199  return decay;
200  }
201  }
202 
203  // Ok, it seems that everything from the DecayDescriptor could be matched.
204  // If the decay is NOT INCLUSIVE, no unmatched MCParticles should be left
205  bool isInclusive = (d->isIgnoreMassive() and d->isIgnoreNeutrino() and d->isIgnoreGamma() and d->isIgnoreRadiatedPhotons());
206  if (!isInclusive) {
207  B2DEBUG(10, "Check for left over MCParticles!\n");
208  for (auto daugP : daughtersP) {
209  if (daugP->getPDG() == Const::photon.getPDGCode()) { // gamma
210  // if gamma is FSR or produced by PHOTOS
211  if (MCMatching::isFSR(daugP) or daugP->hasStatus(MCParticle::c_IsPHOTOSPhoton)) {
212  // if the radiated photons are ignored, we can skip the particle
213  if (d->isIgnoreRadiatedPhotons()) continue;
214  }
215  // else if missing gamma is ignored, we can skip the particle
216  else if (d->isIgnoreGamma()) continue;
217  } else if ((abs(daugP->getPDG()) == 12 or abs(daugP->getPDG()) == 14 or abs(daugP->getPDG()) == 16)) { // neutrino
218  if (d->isIgnoreNeutrino()) continue;
219  } else if (MCMatching::isFSP(daugP->getPDG())) { // other final state particle
220  if (d->isIgnoreMassive()) continue;
221  } else { // intermediate
222  if (d->isIgnoreIntermediate()) continue;
223  }
224  B2DEBUG(10, "There was an additional particle left. Found " << daugP->getPDG());
225  return decay;
226  }
227  }
228  decay->setObj(const_cast<MCParticle*>(mcp));
229  B2DEBUG(19, "Match found!");
230  return decay;
231 }
232 
233 int MCDecayFinderModule::write(DecayTree<MCParticle>* decay)
234 {
235  // Particle array for output
236  StoreArray<Particle> particles;
237  // Input MCParticle array
238  StoreArray<MCParticle> mcparticles;
239 
240  // Create new Particle in particles array
241  Particle* newParticle = particles.appendNew(decay->getObj());
242 
243  // set relation between the created Particle and the MCParticle
244  newParticle->addRelationTo(decay->getObj());
245  const int iIndex = particles.getEntries() - 1;
246 
247  // Now save also daughters of this MCParticle and set the daughter relation
248  vector< DecayTree<MCParticle>* > daughters = decay->getDaughters();
249  int nDaughers = daughters.size();
250  for (int i = 0; i < nDaughers; ++i) {
251  int iIndexDaughter = write(daughters[i]);
252  newParticle->appendDaughter(iIndexDaughter);
253  }
254  return iIndex;
255 }
256 
257 void MCDecayFinderModule::appendParticles(const MCParticle* gen, vector<const MCParticle*>& children)
258 {
259  if (MCMatching::isFSP(gen->getPDG()))
260  return; //stop at the bottom of the MC decay tree (ignore secondaries)
261 
262  const vector<MCParticle*>& genDaughters = gen->getDaughters();
263  for (auto daug : genDaughters) {
264  children.push_back(daug);
265  appendParticles(daug, children);
266  }
267 }
268 
269 int MCDecayFinderModule::getNDaughtersRecursive(const DecayDescriptor* d)
270 {
271  const int nDaughter = d->getNDaughters();
272  if (nDaughter == 0) return nDaughter;
273 
274  int nDaughterRecursive = nDaughter;
275  for (int iDaug = 0; iDaug < nDaughter; iDaug++) {
276  const DecayDescriptor* dDaug = d->getDaughter(iDaug);
277 
278  nDaughterRecursive += getNDaughtersRecursive(dDaug);
279  }
280 
281  return nDaughterRecursive;
282 }
Belle2::isFSP
bool isFSP(int pdg)
defines what is a final state particle for this purpose.
Definition: ParticleMCDecayStringModule.cc:201
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::DecayTree
This is a helper class for the MCDecayFinderModule.
Definition: DecayTree.h:30
Belle2::DataStore::EStoreFlags
EStoreFlags
Flags describing behaviours of objects etc.
Definition: DataStore.h:71
Belle2::RelationsInterface::addRelationTo
void addRelationTo(const RelationsInterface< BASE > *object, float weight=1.0, const std::string &namedRelation="") const
Add a relation from this object to another object (with caching).
Definition: RelationsObject.h:144
Belle2::MCDecayFinderModule
Find decays in MCParticle list matching a given DecayString.
Definition: MCDecayFinderModule.h:32
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::StoreObjPtr
Type-safe access to single objects in the data store.
Definition: ParticleList.h:33
Belle2::Particle::appendDaughter
void appendDaughter(const Particle *daughter, const bool updateType=true)
Appends index of daughter to daughters index array.
Definition: Particle.cc:633
Belle2::MCParticle::getPDG
int getPDG() const
Return PDG code of particle.
Definition: MCParticle.h:123
Belle2::MCParticle::getDaughters
std::vector< Belle2::MCParticle * > getDaughters() const
Get vector of all daughter particles, empty vector if none.
Definition: MCParticle.cc:51
Belle2::Particle
Class to store reconstructed particles.
Definition: Particle.h:77
Belle2::DecayDescriptor
The DecayDescriptor stores information about a decay tree or parts of a decay tree.
Definition: DecayDescriptor.h:43
Belle2::MCParticle
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:43
Belle2::StoreArray< Particle >
Belle2::StoreArray::getEntries
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:226