Belle II Software  light-2205-abys
ParticleLoaderModule.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 // Own include
10 #include <analysis/modules/ParticleLoader/ParticleLoaderModule.h>
11 
12 // framework aux
13 #include <framework/logging/Logger.h>
14 #include <framework/core/ModuleParam.templateDetails.h>
15 
16 // utilities
17 #include <analysis/DecayDescriptor/ParticleListName.h>
18 #include <analysis/utility/PCmsLabTransform.h>
19 
20 #include <utility>
21 
22 using namespace std;
23 using namespace Belle2;
24 
25 //-----------------------------------------------------------------
26 // Register module
27 //-----------------------------------------------------------------
28 
29 REG_MODULE(ParticleLoader);
30 
31 //-----------------------------------------------------------------
32 // Implementation
33 //-----------------------------------------------------------------
34 
35 ParticleLoaderModule::ParticleLoaderModule() : Module()
36 
37 {
38  setDescription("Loads MDST dataobjects as Particle objects to the StoreArray<Particle> and collects them in specified ParticleList.");
40 
41  // Add parameters
42  addParam("decayStrings", m_decayStrings,
43  "List of decay strings (see :ref:`DecayString` for syntax) that specify all output ParticleLists to be created by the module.",
44  {});
45 
46  addParam("useMCParticles", m_useMCParticles,
47  "Use MCParticles instead of reconstructed MDST dataobjects (tracks, ECL, KLM, clusters, V0s, ...)", false);
48 
49  addParam("useROEs", m_useROEs,
50  "Use ROE instead of reconstructed MDST dataobjects (tracks, ECL, KLM, clusters, V0s, ...)", false);
51 
52  addParam("roeMaskName", m_roeMaskName,
53  "ROE mask name to load", std::string(RestOfEvent::c_defaultMaskName));
54 
55  addParam("sourceParticleListName", m_sourceParticleListName,
56  "Particle list name from which we need to get ROEs", std::string(""));
57 
58  addParam("useMissing", m_useMissing,
59  "If true, the Particle List will be filled with missing momentum from the ROE and signal particle.", false);
60 
61  addParam("writeOut", m_writeOut,
62  "If true, the output ParticleList will be saved by RootOutput. If false, it will be ignored when writing the file.", false);
63 
64  addParam("skipNonPrimary", m_skipNonPrimary,
65  "If true, the secondary MC particle will be skipped, default is false",
66  false);
67 
68  addParam("addDaughters", m_addDaughters,
69  "If true, the particles from the bottom part of the selected particle's decay chain will also be created in the datastore and mother-daughter relations are recursively set",
70  false);
71 
72  addParam("skipNonPrimaryDaughters", m_skipNonPrimaryDaughters,
73  "If true, the secondary MC daughters will be skipped, default is false",
74  false);
75 
76  addParam("trackHypothesis", m_trackHypothesis,
77  "Track hypothesis to use when loading the particle. By default, use the particle's own hypothesis.",
78  0);
79 
80  addParam("enforceFitHypothesis", m_enforceFitHypothesis,
81  "If true, a Particle is only created if a track fit with the particle hypothesis passed to the ParticleLoader is available.",
83 }
84 
86 {
87  B2INFO("ParticleLoader's Summary of Actions:");
88 
89  m_particles.registerInDataStore();
90  m_particleExtraInfoMap.registerInDataStore();
91  m_eventExtraInfo.registerInDataStore();
92  //register relations if these things exists
93  if (m_mcparticles.isOptional()) {
94  m_particles.registerRelationTo(m_mcparticles);
95  }
96  if (m_pidlikelihoods.isOptional()) {
97  m_particles.registerRelationTo(m_pidlikelihoods);
98  }
99  if (m_trackfitresults.isOptional()) {
100  m_particles.registerRelationTo(m_trackfitresults);
101  }
102 
103  if (m_useMCParticles) {
104  m_mcparticles.isRequired();
105  }
106 
107  if (m_decayStrings.empty()) {
108  B2WARNING("Obsolete usage of the ParticleLoader module (load all MDST objects as all possible Particle object types). Specify the particle type via decayStrings module parameter instead.");
109  } else {
110  for (auto decayString : m_decayStrings) {
111 
112  // obtain the output particle lists from the decay string
113  bool valid = m_decaydescriptor.init(decayString);
114  if (!valid)
115  B2ERROR("ParticleLoaderModule::initialize Invalid input DecayString: " << decayString);
116 
117  // Mother particle
119  int nProducts = m_decaydescriptor.getNDaughters();
120 
121  int pdgCode = mother->getPDGCode();
122  // The default list name is "all"
123  string listName = mother->getName() + ":all";
124  // ROE particles get the full name
125  if (m_useROEs) listName = mother->getFullName();
126  // MC particles get the label "MC"
127  else if (m_useMCParticles) listName = mother->getName() + ":MC";
128  // V0s get the label "V0"
129  else if (nProducts > 0) listName = mother->getName() + ":V0";
130 
131  string antiListName = ParticleListName::antiParticleListName(listName);
132  bool isSelfConjugatedParticle = (listName == antiListName);
133 
134  StoreObjPtr<ParticleList> particleList(listName);
135  // if the particle list doesn't exist, we have to register it
136  if (!particleList.isOptional()) {
138  particleList.registerInDataStore(flags);
139  if (!isSelfConjugatedParticle) {
140  StoreObjPtr<ParticleList> antiParticleList(antiListName);
141  antiParticleList.registerInDataStore(flags);
142  }
143  }
144 
145  if (not isValidPDGCode(pdgCode) and (m_useMCParticles == false and m_useROEs == false))
146  B2ERROR("Invalid particle type requested to be loaded. Set a valid decayString module parameter.");
147 
148  // if we're not loading MCParticles and we are loading K0S, Lambdas, or photons --> ee then this decaystring is a V0
149  bool mdstSourceIsV0 = false;
150  if (!m_useMCParticles &&
151  (abs(pdgCode) == abs(Const::Kshort.getPDGCode()) || abs(pdgCode) == abs(Const::Lambda.getPDGCode())
152  || (abs(pdgCode) == abs(Const::photon.getPDGCode()) && m_addDaughters == true)))
153  mdstSourceIsV0 = true;
154 
155  if (mdstSourceIsV0 == false) {
156  if (nProducts > 0) {
157  if (!m_useROEs) {
158  B2ERROR("ParticleLoaderModule::initialize Invalid input DecayString " << decayString
159  << ". DecayString should not contain any daughters, only the mother particle.");
160  } else {
161  B2INFO("ParticleLoaderModule: Replacing the source particle list name by " <<
163  << " all other daughters will be ignored.");
165  }
166  }
167  } else {
168  if (nProducts != 2)
169  B2ERROR("ParticleLoaderModule::initialize Invalid input DecayString " << decayString
170  << ". MDST source of the particle list is V0, DecayString should contain exactly two daughters, as well as the mother particle.");
171  else {
173  B2ERROR("MDST source of the particle list is V0, the two daughters should have opposite charge");
174  }
175  }
176 
177  // add PList to corresponding collection of Lists
178  B2INFO(" o) creating (anti-)ParticleList with name: " << listName << " (" << antiListName << ")");
179  if (m_useROEs) {
180  B2INFO(" -> MDST source: RestOfEvents");
181  m_ROE2Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle);
182  } else if (m_useMCParticles) {
183  B2INFO(" -> MDST source: MCParticles");
184  m_MCParticles2Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle);
185  } else {
186  bool chargedFSP = Const::chargedStableSet.contains(Const::ParticleType(abs(pdgCode)));
187  if (chargedFSP) {
188  B2INFO(" -> MDST source: Tracks");
189  m_Tracks2Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle);
190  }
191 
192  if (abs(pdgCode) == abs(Const::photon.getPDGCode())) {
193  if (m_addDaughters == false) {
194  m_ECLKLMClusters2Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle);
195  B2INFO(" -> MDST source: ECLClusters and KLMClusters");
196  } else {
197  B2INFO(" -> MDST source: V0");
198  m_V02Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle);
199  }
200  }
201 
202  if (abs(pdgCode) == abs(Const::Kshort.getPDGCode())) {
203  B2INFO(" -> MDST source: V0");
204  m_V02Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle);
205  }
206 
207  if (abs(pdgCode) == abs(Const::Klong.getPDGCode()) || abs(pdgCode) == abs(Const::neutron.getPDGCode())) {
208  B2INFO(" -> MDST source: exclusively KLMClusters or exclusively ECLClusters (matching between those not used)");
209  m_ECLKLMClusters2Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle);
210  }
211 
212  if (abs(pdgCode) == abs(Const::Lambda.getPDGCode())) {
213  B2INFO(" -> MDST source: V0");
214  m_V02Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle);
215  }
216  }
217  }
218  }
219 
220 
221  m_chargeZeroTrackCounts = std::vector<int>(m_Tracks2Plists.size(), 0);
222  m_sameChargeDaughtersV0Counts = std::vector<int>(m_V02Plists.size(), 0);
223 }
224 
226 {
227  if (not m_particleExtraInfoMap) {
228  m_particleExtraInfoMap.create();
229  }
230 
231  if (m_useROEs)
232  roeToParticles();
233  else if (m_useMCParticles)
235  else {
238  v0sToParticles();
239  }
240 }
241 
243 {
244  // report track errors integrated
245  for (size_t i = 0; i < m_Tracks2Plists.size(); i++)
246  if (m_chargeZeroTrackCounts[i] > 0) {
247  auto track2Plist = m_Tracks2Plists[i];
248  B2WARNING("There were " << m_chargeZeroTrackCounts[i]
249  << " tracks skipped because of zero charge for "
250  << get<c_PListName>(track2Plist));
251  }
252  // report V0 errors integrated
253  for (size_t i = 0; i < m_V02Plists.size(); i++)
254  if (m_sameChargeDaughtersV0Counts[i] > 0) {
255  auto v02Plist = m_V02Plists[i];
256  B2WARNING("There were " << m_sameChargeDaughtersV0Counts[i]
257  << " v0s skipped because of same charge daughters for "
258  << get<c_PListName>(v02Plist));
259  }
260 }
261 
263 {
264  if (m_ROE2Plists.empty()) // nothing to do
265  return;
266  // Multiple particle lists are not supported
267  auto roe2Plist = m_ROE2Plists[0];
268  string listName = get<c_PListName>(roe2Plist);
269  string antiListName = get<c_AntiPListName>(roe2Plist);
270  int pdgCode = get<c_PListPDGCode>(roe2Plist);
271  bool isSelfConjugatedParticle = get<c_IsPListSelfConjugated>(roe2Plist);
272 
273  StoreObjPtr<ParticleList> plist(listName);
274  // since a particle list in the ParticleLoader always contains all possible objects
275  // we check whether it already exists in this path and can skip any further steps if it does
276  if (plist.isValid())
277  return;
278  plist.create();
279  plist->initialize(pdgCode, listName);
280 
281  if (!isSelfConjugatedParticle) {
282  StoreObjPtr<ParticleList> antiPlist(antiListName);
283  antiPlist.create();
284  antiPlist->initialize(-1 * pdgCode, antiListName);
285  antiPlist->bindAntiParticleList(*(plist));
286  }
287  if (m_sourceParticleListName != "") {
288  // Take related ROEs from a particle list
290  if (!pList.isValid())
291  B2FATAL("ParticleList " << m_sourceParticleListName << " could not be found or is not valid!");
292  for (unsigned int i = 0; i < pList->getListSize(); i++) {
293  RestOfEvent* roe = pList->getParticle(i)->getRelatedTo<RestOfEvent>("ALL");
294  if (!roe) {
295  B2ERROR("ParticleList " << m_sourceParticleListName << " has no associated ROEs!");
296  } else {
297  addROEToParticleList(roe, i, pdgCode, isSelfConjugatedParticle);
298  }
299  }
300 
301  } else {
302  // Take all ROE if no particle list provided
303  for (int i = 0; i < m_roes.getEntries(); i++) {
305  }
306  }
307 }
308 
309 void ParticleLoaderModule::addROEToParticleList(RestOfEvent* roe, int mdstIndex, int pdgCode, bool isSelfConjugatedParticle)
310 {
311 
312  Particle* newPart = nullptr;
313  if (!m_useMissing) {
314  // Convert ROE to particle
315  newPart = roe->convertToParticle(m_roeMaskName, pdgCode, isSelfConjugatedParticle);
316  } else {
317  // Create a particle from missing momentum
318  auto* signalSideParticle = roe->getRelatedFrom<Particle>();
320  ROOT::Math::PxPyPzEVector boost4Vector = T.getBeamFourMomentum();
321 
322  ROOT::Math::PxPyPzEVector signal4Vector = signalSideParticle->get4Vector();
323  ROOT::Math::PxPyPzEVector roe4Vector = roe->get4Vector(m_roeMaskName);
324  ROOT::Math::PxPyPzEVector missing4Vector = boost4Vector - signal4Vector - roe4Vector;
325  auto isFlavored = (isSelfConjugatedParticle) ? Particle::EFlavorType::c_Unflavored : Particle::EFlavorType::c_Flavored;
326  newPart = m_particles.appendNew(missing4Vector, pdgCode, isFlavored, Particle::EParticleSourceObject::c_Undefined, mdstIndex);
327 
328  }
329  for (auto roe2Plist : m_ROE2Plists) {
330  string listName = get<c_PListName>(roe2Plist);
331  StoreObjPtr<ParticleList> plist(listName);
332  plist->addParticle(newPart);
333  }
334 }
335 
336 
338 {
339  if (m_V02Plists.empty()) // nothing to do
340  return;
341 
342  // check if the order of the daughters in the decay string (decided by the user) is the same as the v0 daughters' order (fixed)
343  bool matchingDaughtersOrder = true;
346  matchingDaughtersOrder = false;
347 
348  // loop over all ParticleLists
349  for (size_t ilist = 0; ilist < m_V02Plists.size(); ilist++) {
350  auto v02Plist = m_V02Plists[ilist];
351  string listName = get<c_PListName>(v02Plist);
352  string antiListName = get<c_AntiPListName>(v02Plist);
353  int pdgCode = get<c_PListPDGCode>(v02Plist);
354  bool isSelfConjugatedParticle = get<c_IsPListSelfConjugated>(v02Plist);
355 
356  StoreObjPtr<ParticleList> plist(listName);
357  // since a particle list in the ParticleLoader always contains all possible objects
358  // we check whether it already exists in this path and can skip any further steps if it does
359  if (plist.isValid())
360  continue;
361  plist.create();
362  plist->initialize(pdgCode, listName);
363 
364  if (!isSelfConjugatedParticle) {
365  StoreObjPtr<ParticleList> antiPlist(antiListName);
366  antiPlist.create();
367  antiPlist->initialize(-1 * pdgCode, antiListName);
368 
369  antiPlist->bindAntiParticleList(*(plist));
370  }
371 
372  // load reconstructed V0s as Kshorts (pi-pi+ combination), Lambdas (p+pi- combinations), and converted photons (e-e+ combinations)
373  for (int i = 0; i < m_v0s.getEntries(); i++) {
374  const V0* v0 = m_v0s[i];
375  Const::ParticleType v0Type = v0->getV0Hypothesis();
376 
377  if (abs(pdgCode) != abs(v0Type.getPDGCode()))
378  continue;
379 
380  // check if the charge of the 2 V0's daughters is opposite
381  if (v0->getTrackFitResults().first->getChargeSign() == v0->getTrackFitResults().second->getChargeSign()) {
382  B2DEBUG(19, "V0 with same charge daughters skipped!");
384  continue;
385  }
386 
390 
391  if (v0Type.getPDGCode() == Const::Kshort.getPDGCode()) { // K0s -> pi+ pi-
392  pTypeP = Const::pion;
393  pTypeM = Const::pion;
394  } else if (v0Type.getPDGCode() == Const::Lambda.getPDGCode()) { // Lambda -> p+ pi-
395  pTypeP = Const::proton;
396  pTypeM = Const::pion;
397  v0FlavorType = Particle::c_Flavored; // K0s are not flavoured, lambdas are
398  } else if (v0Type.getPDGCode() == Const::antiLambda.getPDGCode()) { // anti-Lambda -> pi+ anti-p-
399  pTypeP = Const::pion;
400  pTypeM = Const::proton;
401  v0FlavorType = Particle::c_Flavored;
402  } else if (v0Type.getPDGCode() == Const::photon.getPDGCode()) { // gamma -> e+ e-
403  pTypeP = Const::electron;
404  pTypeM = Const::electron;
405  } else {
406  B2WARNING("Unknown V0 hypothesis!");
407  }
408 
409  // check if, given the initial user's decay descriptor, the current v0 is a particle or an anti-particle.
410  // in the V0 the order of the daughters is fixed, first the positive and then the negative; to be coherent with the decay descriptor, when creating
411  // one particle list and one anti-particle, the v0 daughters' order has to be switched only in one case
412  bool correctOrder = matchingDaughtersOrder;
413  if (abs(v0Type.getPDGCode()) == abs(m_decaydescriptor.getMother()->getPDGCode())
414  && v0Type.getPDGCode() != m_decaydescriptor.getMother()->getPDGCode())
415  correctOrder = !correctOrder;
416 
417  std::pair<Track*, Track*> v0Tracks = v0->getTracks();
418  std::pair<TrackFitResult*, TrackFitResult*> v0TrackFitResults = v0->getTrackFitResults();
419 
420  Particle daugP((v0Tracks.first)->getArrayIndex(), v0TrackFitResults.first, pTypeP);
421  Particle daugM((v0Tracks.second)->getArrayIndex(), v0TrackFitResults.second, pTypeM);
422 
423  const PIDLikelihood* pidP = (v0Tracks.first)->getRelated<PIDLikelihood>();
424  const PIDLikelihood* pidM = (v0Tracks.second)->getRelated<PIDLikelihood>();
425 
426  const auto& mcParticlePWithWeight = (v0Tracks.first)->getRelatedToWithWeight<MCParticle>();
427  const auto& mcParticleMWithWeight = (v0Tracks.second)->getRelatedToWithWeight<MCParticle>();
428 
429  // add V0 daughters to the Particle StoreArray
430  Particle* newDaugP;
431  Particle* newDaugM;
432 
433  if (correctOrder) {
434  newDaugP = m_particles.appendNew(daugP);
435  newDaugM = m_particles.appendNew(daugM);
436  } else {
437  newDaugM = m_particles.appendNew(daugM);
438  newDaugP = m_particles.appendNew(daugP);
439  }
440 
441  // if there are PIDLikelihoods and MCParticles then also add relations to the particles
442  if (pidP)
443  newDaugP->addRelationTo(pidP);
444  if (mcParticlePWithWeight.first)
445  newDaugP->addRelationTo(mcParticlePWithWeight.first, mcParticlePWithWeight.second);
446  newDaugP->addRelationTo(v0TrackFitResults.first);
447 
448  if (pidM)
449  newDaugM->addRelationTo(pidM);
450  if (mcParticleMWithWeight.first)
451  newDaugM->addRelationTo(mcParticleMWithWeight.first, mcParticleMWithWeight.second);
452  newDaugM->addRelationTo(v0TrackFitResults.second);
453 
454  // sum the 4-momenta of the daughters and construct a particle object
455  ROOT::Math::PxPyPzEVector v0Momentum = newDaugP->get4Vector() + newDaugM->get4Vector();
456  Particle v0P(v0Momentum, v0Type.getPDGCode(), v0FlavorType,
457  Particle::EParticleSourceObject::c_V0, v0->getArrayIndex());
458 
459  // add the daughters of the V0 (in the correct order) and don't update
460  // the type to c_Composite (i.e. maintain c_V0)
461  if (correctOrder) {
462  v0P.appendDaughter(newDaugP, false);
463  v0P.appendDaughter(newDaugM, false);
464  } else {
465  v0P.appendDaughter(newDaugM, false);
466  v0P.appendDaughter(newDaugP, false);
467  }
468 
469  // append the particle to the Particle StoreArray and add the new particle to the ParticleList
470  Particle* newPart = m_particles.appendNew(v0P);
471  plist->addParticle(newPart);
472  }
473  }
474 }
475 
477 {
478  if (m_Tracks2Plists.empty()) // nothing to do
479  return;
480 
481  // loop over all requested particle lists
482  for (size_t ilist = 0; ilist < m_Tracks2Plists.size(); ilist++) {
483  auto track2Plist = m_Tracks2Plists[ilist];
484  string listName = get<c_PListName>(track2Plist);
485  string antiListName = get<c_AntiPListName>(track2Plist);
486  int pdgCode = get<c_PListPDGCode>(track2Plist);
487  bool isSelfConjugatedParticle = get<c_IsPListSelfConjugated>(track2Plist);
488 
489  StoreObjPtr<ParticleList> plist(listName);
490  // since a particle list in the ParticleLoader always contains all possible objects
491  // we check whether it already exists in this path and can skip any further steps if it does
492  if (plist.isValid())
493  continue;
494  plist.create();
495  plist->initialize(pdgCode, listName);
496 
497  // if cc exists then also create and bind that list
498  if (!isSelfConjugatedParticle) {
499  StoreObjPtr<ParticleList> antiPlist(antiListName);
500  antiPlist.create();
501  antiPlist->initialize(-1 * pdgCode, antiListName);
502 
503  antiPlist->bindAntiParticleList(*(plist));
504  }
505 
506  // the inner loop over all tracks from which Particles
507  // are created, and get sorted in the particle lists
508  for (int i = 0; i < m_tracks.getEntries(); i++) {
509  const Track* track = m_tracks[i];
510  const PIDLikelihood* pid = track->getRelated<PIDLikelihood>();
511  const auto& mcParticleWithWeight = track->getRelatedToWithWeight<MCParticle>();
512 
513  // if a special track hypothesis is requested, use it
514  if (m_trackHypothesis != 0) pdgCode = m_trackHypothesis;
515  Const::ChargedStable type(abs(pdgCode));
516 
517  // load the TrackFitResult for the requested particle or if not available use
518  // the one with the closest mass
519  const TrackFitResult* trackFit = track->getTrackFitResultWithClosestMass(type);
520 
521  if (!trackFit) { // should never happen with the "closest mass" getter - leave as a sanity check
522  B2WARNING("Track returned null TrackFitResult pointer for ChargedStable::getPDGCode() = " << type.getPDGCode());
523  continue;
524  }
525 
526  if (m_enforceFitHypothesis && (trackFit->getParticleType().getPDGCode() != type.getPDGCode())) {
527  // the required hypothesis does not exist for this track, skip it
528  continue;
529  }
530 
531  // charge zero tracks can appear, filter them and
532  // count number of tracks filtered out
533  int charge = trackFit->getChargeSign();
534  if (charge == 0) {
535  B2DEBUG(19, "Track with charge = 0 skipped!");
536  m_chargeZeroTrackCounts[ilist]++;
537  continue;
538  }
539 
540  // create particle and add it to the Particle list.
541  Particle particle(track->getArrayIndex(), trackFit, type);
542 
543  if (particle.getParticleSource() == Particle::c_Track) { // should always hold but...
544 
545  Particle* newPart = m_particles.appendNew(particle);
546  if (pid)
547  newPart->addRelationTo(pid);
548  if (mcParticleWithWeight.first)
549  newPart->addRelationTo(mcParticleWithWeight.first, mcParticleWithWeight.second);
550  newPart->addRelationTo(trackFit);
551 
552  plist->addParticle(newPart);
553 
554  } // sanity check correct particle type
555  } // loop over tracks
556  } // particle lists
557 }
558 
560 {
561  if (m_ECLKLMClusters2Plists.empty()) // nothing to do
562  return;
563 
564  // loop over all ParticleLists
565  for (auto eclKLMCluster2Plist : m_ECLKLMClusters2Plists) {
566  string listName = get<c_PListName>(eclKLMCluster2Plist);
567  string antiListName = get<c_AntiPListName>(eclKLMCluster2Plist);
568  int pdgCode = get<c_PListPDGCode>(eclKLMCluster2Plist);
569  bool isSelfConjugatedParticle = get<c_IsPListSelfConjugated>(eclKLMCluster2Plist);
570 
571  StoreObjPtr<ParticleList> plist(listName);
572  // since a particle list in the ParticleLoader always contains all possible objects
573  // we check whether it already exists in this path and can skip any further steps if it does
574  if (plist.isValid())
575  continue;
576  plist.create();
577  plist->initialize(pdgCode, listName);
578 
579  // create anti-particle list if necessary
580  if (!isSelfConjugatedParticle) {
581  StoreObjPtr<ParticleList> antiPlist(antiListName);
582  antiPlist.create();
583  antiPlist->initialize(-1 * pdgCode, antiListName);
584 
585  antiPlist->bindAntiParticleList(*(plist));
586  }
587 
588  // load reconstructed neutral ECL clusters as photons or Klongs or neutrons
589  for (int i = 0; i < m_eclclusters.getEntries(); i++) {
590  const ECLCluster* cluster = m_eclclusters[i];
591 
592  // ECLClusters can be reconstructed under different hypotheses, for
593  // example photons or neutral hadrons, we only load particles from these
594  // for now
595  if (!cluster->isNeutral()) continue;
596  if (not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons)
597  and not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron))
598  continue;
599 
600  // ECLCluster can be matched to multiple MCParticles
601  // order the relations by weights and set Particle -> multiple MCParticle relation
602  // preserve the weight
603  RelationVector<MCParticle> mcRelations = cluster->getRelationsTo<MCParticle>();
604  // order relations by weights
605  std::vector<std::pair<int, double>> weightsAndIndices;
606  for (unsigned int iMCParticle = 0; iMCParticle < mcRelations.size(); iMCParticle++) {
607  const MCParticle* relMCParticle = mcRelations[iMCParticle];
608  double weight = mcRelations.weight(iMCParticle);
609  if (relMCParticle)
610  weightsAndIndices.emplace_back(relMCParticle->getArrayIndex(), weight);
611  }
612  // sort descending by weight
613  std::sort(weightsAndIndices.begin(), weightsAndIndices.end(),
614  [](const std::pair<int, double>& left, const std::pair<int, double>& right) {
615  return left.second > right.second;
616  });
617 
618  Const::ParticleType thisType(pdgCode);
619 
620  // don't fill photon list with clusters that don't have
621  // the nPhotons hypothesis (ECL people call this N1)
622  if (pdgCode == Const::photon.getPDGCode()
623  and not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons))
624  continue;
625 
626  // don't fill a KLong list with clusters that don't have the neutral
627  // hadron hypothesis set (ECL people call this N2)
628  if (pdgCode == Const::Klong.getPDGCode()
629  and not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron))
630  continue;
631 
632  // don't fill a neutron list with clusters that don't have the neutral
633  // hadron hypothesis set (ECL people call this N2)
634  if (abs(pdgCode) == Const::neutron.getPDGCode()
635  and not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron))
636  continue;
637 
638  // create particle and check it before adding to list
639  Particle particle(cluster, thisType);
640  if (particle.getParticleSource() != Particle::c_ECLCluster) {
641  B2FATAL("Particle created from ECLCluster does not have ECLCluster type.");
642  continue;
643  }
644  Particle* newPart = m_particles.appendNew(particle);
645 
646  // set relations to mcparticles
647  for (auto& weightsAndIndex : weightsAndIndices) {
648  const MCParticle* relMCParticle = m_mcparticles[weightsAndIndex.first];
649  double weight = weightsAndIndex.second;
650 
651  // TODO: study this further and avoid hard-coded values
652  // set the relation only if the MCParticle(reconstructed Particle)'s
653  // energy contribution to this cluster amounts to at least 30(20)%
654  if (relMCParticle)
655  if (weight / newPart->getECLClusterEnergy() > 0.20
656  && weight / relMCParticle->getEnergy() > 0.30)
657  newPart->addRelationTo(relMCParticle, weight);
658  }
659 
660  // add particle to list
661  plist->addParticle(newPart);
662  }
663 
664  // load reconstructed KLM clusters as Klongs or neutrons or photons
665  for (int i = 0; i < m_klmclusters.getEntries(); i++) {
666  const KLMCluster* cluster = m_klmclusters[i];
667 
668  if (std::isnan(cluster->getMomentumMag())) {
669  B2DEBUG(19, "Skipping KLMCluster because its momentum is NaN. "
670  "This can happen if the timing calibration is missing or wrong, so that the velocity is calculated to be negative.");
671  continue;
672  }
673 
674  const MCParticle* mcParticle = cluster->getRelated<MCParticle>();
675 
676  // create particle and check its type before adding it to list
677  Particle particle(cluster, pdgCode);
678  if (particle.getParticleSource() != Particle::c_KLMCluster) {
679  B2FATAL("Particle created from KLMCluster does not have KLMCluster type.");
680  }
681  Particle* newPart = m_particles.appendNew(particle);
682 
683  if (mcParticle)
684  newPart->addRelationTo(mcParticle);
685 
686  // add particle to list
687  plist->addParticle(newPart);
688  }
689  } // loop over particle lists
690 }
691 
693 {
694  if (m_MCParticles2Plists.empty()) // nothing to do
695  return;
696 
697  // create all lists
698  for (auto mcParticle2Plist : m_MCParticles2Plists) {
699  string listName = get<c_PListName>(mcParticle2Plist);
700  string antiListName = get<c_AntiPListName>(mcParticle2Plist);
701  int pdgCode = get<c_PListPDGCode>(mcParticle2Plist);
702  bool isSelfConjugatedParticle = get<c_IsPListSelfConjugated>(mcParticle2Plist);
703 
704  StoreObjPtr<ParticleList> plist(listName);
705  // since a particle list in the ParticleLoader always contains all possible objects
706  // we check whether it already exists in this path and can skip any further steps if it does
707  if (plist.isValid())
708  continue;
709  plist.create();
710  plist->initialize(pdgCode, listName);
711 
712  if (!isSelfConjugatedParticle) {
713  StoreObjPtr<ParticleList> antiPlist(antiListName);
714  antiPlist.create();
715  antiPlist->initialize(-1 * pdgCode, antiListName);
716 
717  antiPlist->bindAntiParticleList(*(plist));
718  }
719 
720  for (int i = 0; i < m_mcparticles.getEntries(); i++) {
721  const MCParticle* mcParticle = m_mcparticles[i];
722 
723  if (abs(pdgCode) != abs(mcParticle->getPDG()))
724  continue;
725 
727  continue;
728 
729  Particle particle(mcParticle);
730  Particle* newPart = m_particles.appendNew(particle);
731  newPart->addRelationTo(mcParticle);
732 
733  //append the whole bottom part of the decay tree to this particle
735 
736  plist->addParticle(newPart);
737  }
738  }
739 }
740 
742 {
743  bool result = false;
744 
745  // is particle type = charged final state particle?
746  if (Const::chargedStableSet.find(abs(pdgCode)) != Const::invalidParticle)
747  return true;
748 
749  if (abs(pdgCode) == abs(Const::photon.getPDGCode()))
750  return true;
751 
752  if (abs(pdgCode) == abs(Const::Kshort.getPDGCode()))
753  return true;
754 
755  if (abs(pdgCode) == abs(Const::Klong.getPDGCode()))
756  return true;
757 
758  if (abs(pdgCode) == abs(Const::Lambda.getPDGCode()))
759  return true;
760 
761  if (abs(pdgCode) == abs(Const::neutron.getPDGCode()))
762  return true;
763 
764  return result;
765 }
766 
768 {
769  auto* mcmother = mother->getRelated<MCParticle>();
770 
771  if (!mcmother)
772  return;
773 
774  vector<MCParticle*> mcdaughters = mcmother->getDaughters();
775 
776  for (auto& mcdaughter : mcdaughters) {
777  if (!mcdaughter->hasStatus(MCParticle::c_PrimaryParticle) and m_skipNonPrimaryDaughters) continue;
778  Particle particle(mcdaughter);
779  Particle* daughter = m_particles.appendNew(particle);
780  daughter->addRelationTo(mcdaughter);
781  mother->appendDaughter(daughter, false);
782 
783  if (mcdaughter->getNDaughters() > 0)
784  appendDaughtersRecursive(daughter);
785  }
786 }
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:470
bool contains(const ParticleType &p) const
Returns true if and only if the set contains 'p'.
Definition: UnitConst.cc:390
The ParticleType class for identifying different particle types.
Definition: Const.h:289
int getPDGCode() const
PDG code.
Definition: Const.h:354
static const ParticleType neutron
neutron particle
Definition: Const.h:556
static const ParticleType Lambda
Lambda particle.
Definition: Const.h:559
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:499
static const ChargedStable pion
charged pion particle
Definition: Const.h:542
static const ParticleType Klong
K^0_L particle.
Definition: Const.h:558
static const ParticleType antiLambda
Anti-Lambda particle.
Definition: Const.h:560
static const ChargedStable proton
proton particle
Definition: Const.h:544
static const ParticleType invalidParticle
Invalid particle, used internally.
Definition: Const.h:561
static const ParticleType Kshort
K^0_S particle.
Definition: Const.h:557
static const ParticleType photon
photon particle
Definition: Const.h:554
static const ChargedStable electron
electron particle
Definition: Const.h:540
EStoreFlags
Flags describing behaviours of objects etc.
Definition: DataStore.h:69
@ c_WriteOut
Object/array should be saved by output modules.
Definition: DataStore.h:70
@ c_DontWriteOut
Object/array should be NOT saved by output modules.
Definition: DataStore.h:71
Represents a particle in the DecayDescriptor.
int getPDGCode() const
Return PDG code.
std::string getFullName() const
returns the full name of the particle full_name = name:label
std::string getName() const
evt.pdl name of the particle.
bool init(const std::string &str)
Initialise the DecayDescriptor from given string.
const DecayDescriptorParticle * getMother() const
return mother.
int getNDaughters() const
return number of direct daughters.
const DecayDescriptor * getDaughter(int i) const
return i-th daughter (0 based index).
ECL cluster data.
Definition: ECLCluster.h:27
@ c_nPhotons
CR is split into n photons (N1)
@ c_neutralHadron
CR is reconstructed as a neutral hadron (N2)
KLM cluster data.
Definition: KLMCluster.h:28
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:34
float getEnergy() const
Return particle energy in GeV.
Definition: MCParticle.h:149
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Definition: MCParticle.h:49
std::vector< Belle2::MCParticle * > getDaughters() const
Get vector of all daughter particles, empty vector if none.
Definition: MCParticle.cc:52
bool hasStatus(unsigned short int bitmask) const
Return if specific status bit is set.
Definition: MCParticle.h:131
int getArrayIndex() const
Get 0-based index of the particle in the corresponding MCParticle list.
Definition: MCParticle.h:246
int getPDG() const
Return PDG code of particle.
Definition: MCParticle.h:114
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
Class to hold Lorentz transformations from/to CMS and boost vector.
ROOT::Math::PxPyPzEVector getBeamFourMomentum() const
Returns LAB four-momentum of e+e-.
Class to collect log likelihoods from TOP, ARICH, dEdx, ECL and KLM aimed for output to mdst includes...
Definition: PIDLikelihood.h:26
std::vector< PList > m_ECLKLMClusters2Plists
Collection of PLists that will collect Particles created from ECLClusters and KLMClusters.
void mcParticlesToParticles()
Loads specified MCParticles as Particle to StoreArray<Particle>
void v0sToParticles()
Loads V0 object as Particle of specified type to StoreArray<Particle> and adds it to the ParticleList...
StoreArray< TrackFitResult > m_trackfitresults
StoreArray of TrackFitResults.
std::vector< std::string > m_decayStrings
Input decay strings specifying the particles being created/loaded.
void roeToParticles()
Loads ROE object as Particle of specified type to StoreArray<Particle> and adds it to the ParticleLis...
virtual void initialize() override
Initialize the Module.
int m_trackHypothesis
pdg code for track hypothesis that should be used to create the particle
StoreArray< KLMCluster > m_klmclusters
StoreArray of KLMCluster.
std::vector< int > m_sameChargeDaughtersV0Counts
internally used to count the number of V0s with same charge daughters
StoreArray< V0 > m_v0s
StoreArray of V0s.
void addROEToParticleList(RestOfEvent *roe, int mdstIndex, int pdgCode=0, bool isSelfConjugatedParticle=true)
Helper method to load ROE object as Particle.
virtual void event() override
Event processor.
std::string m_sourceParticleListName
Particle list name from which we need to get related ROEs.
bool isValidPDGCode(const int pdgCode)
returns true if the PDG code determined from the decayString is valid
StoreArray< MCParticle > m_mcparticles
StoreArray of MCParticles.
StoreArray< Particle > m_particles
StoreArray of Particles.
std::string m_roeMaskName
ROE mask name to load.
virtual void terminate() override
Terminate the Module.
void tracksToParticles()
Loads Track object as Particle to StoreArray<Particle> and adds it to the ParticleList.
StoreObjPtr< ParticleExtraInfoMap > m_particleExtraInfoMap
object pointer to extra info map
bool m_addDaughters
toggle addition of the bottom part of the particle's decay chain
StoreArray< PIDLikelihood > m_pidlikelihoods
StoreArray of PIDLikelihoods.
bool m_skipNonPrimaryDaughters
toggle skip of secondary MC daughters
StoreArray< Track > m_tracks
StoreArray of Tracks.
bool m_enforceFitHypothesis
If true, a Particle is only created if a track fit with the particle hypothesis passed to the Particl...
std::vector< PList > m_ROE2Plists
Collection of PLists that will collect Particles created from V0.
StoreArray< RestOfEvent > m_roes
StoreArray of ROEs.
void appendDaughtersRecursive(Particle *mother)
recursively append bottom of a particle's decay chain (daughters of mother, granddaughters of daughte...
std::vector< PList > m_MCParticles2Plists
Collection of PLists that will collect Particles created from MCParticles.
std::vector< PList > m_V02Plists
Collection of PLists that will collect Particles created from V0.
DecayDescriptor m_decaydescriptor
Decay descriptor for parsing the user specified DecayString.
bool m_writeOut
toggle particle list btw.
std::vector< int > m_chargeZeroTrackCounts
internally used to count number of tracks with charge zero
std::vector< PList > m_Tracks2Plists
Collection of PLists that will collect Particles created from Tracks.
StoreObjPtr< EventExtraInfo > m_eventExtraInfo
object pointer to event extra info
StoreArray< ECLCluster > m_eclclusters
StoreArray of ECLCluster.
bool m_skipNonPrimary
toggle skip of secondary MC particle
bool m_useROEs
Switch to load ROE as Particle.
bool m_useMissing
Use missing momentum to build a particle.
void eclAndKLMClustersToParticles()
Loads ECLCluster and KLMCluster object as Particle to StoreArray<Particle> and adds it to the Particl...
bool m_useMCParticles
Load MCParticle as Particle instead of the corresponding MDST dataobject.
Class to store reconstructed particles.
Definition: Particle.h:74
ROOT::Math::PxPyPzEVector get4Vector() const
Returns Lorentz vector.
Definition: Particle.h:488
EParticleSourceObject getParticleSource() const
Returns particle source as defined with enum EParticleSourceObject.
Definition: Particle.h:427
EFlavorType
describes flavor type, see getFlavorType().
Definition: Particle.h:92
@ c_Unflavored
Is its own antiparticle or we don't know whether it is a particle/antiparticle.
Definition: Particle.h:93
@ c_Flavored
Is either particle or antiparticle.
Definition: Particle.h:94
double getECLClusterEnergy() const
Returns the energy of the ECLCluster for the particle.
Definition: Particle.cc:911
void appendDaughter(const Particle *daughter, const bool updateType=true)
Appends index of daughter to daughters index array.
Definition: Particle.cc:700
Class for type safe access to objects that are referred to in relations.
size_t size() const
Get number of relations.
float weight(int index) const
Get weight with index.
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).
int getArrayIndex() const
Returns this object's array index (in StoreArray), or -1 if not found.
FROM * getRelatedFrom(const std::string &name="", const std::string &namedRelation="") const
Get the object from which this object has a relation.
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or from which this object has a relation.
This is a general purpose class for collecting reconstructed MDST data objects that are not used in r...
Definition: RestOfEvent.h:57
ROOT::Math::PxPyPzEVector get4Vector(const std::string &maskName=c_defaultMaskName) const
Get 4-momentum vector all (no mask) or a subset (use mask) of all Tracks and ECLClusters in ROE.
Definition: RestOfEvent.cc:306
static constexpr const char * c_defaultMaskName
Default mask name.
Definition: RestOfEvent.h:60
Particle * convertToParticle(const std::string &maskName=c_defaultMaskName, int pdgCode=0, bool isSelfConjugated=true)
Converts ROE to Particle and adds it to StoreArray.
Definition: RestOfEvent.cc:443
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
bool create(bool replace=false)
Create a default object in the data store.
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
bool isValid() const
Check whether the object was created.
Definition: StoreObjPtr.h:110
Values of the result of a track fit with a given particle hypothesis.
short getChargeSign() const
Return track charge (1 or -1).
Const::ParticleType getParticleType() const
Getter for ParticleType of the mass hypothesis of the track fit.
Class that bundles various TrackFitResults.
Definition: Track.h:25
Object holding information for V0s.
Definition: V0.h:30
std::pair< TrackFitResult *, TrackFitResult * > getTrackFitResults() const
Get pair of the TrackFitResults, that are part of the V0 particle.
Definition: V0.h:53
std::pair< Track *, Track * > getTracks() const
Get pair of yhe Tracks, that are part of the V0 particle.
Definition: V0.h:40
Const::ParticleType getV0Hypothesis() const
Get the hypothesis under which the V0 particle was created.
Definition: V0.cc:28
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
std::string antiParticleListName(const std::string &listName)
Returns name of anti-particle-list corresponding to listName.
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:23