Belle II Software  release-05-02-19
ParticleLoaderModule.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2010-2019 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Marko Staric, Anze Zupanc *
7  * Sam Cunliffe, Torben Ferber *
8  * Frank Meier *
9  * *
10  * This software is provided "as is" without any warranty. *
11  **************************************************************************/
12 
13 // Own include
14 #include <analysis/modules/ParticleLoader/ParticleLoaderModule.h>
15 
16 // framework - DataStore
17 #include <framework/datastore/StoreArray.h>
18 #include <framework/datastore/StoreObjPtr.h>
19 
20 // framework aux
21 #include <framework/logging/Logger.h>
22 #include <framework/core/ModuleParam.templateDetails.h>
23 
24 // dataobjects
25 #include <mdst/dataobjects/V0.h>
26 #include <mdst/dataobjects/ECLCluster.h>
27 #include <mdst/dataobjects/KLMCluster.h>
28 #include <mdst/dataobjects/MCParticle.h>
29 #include <mdst/dataobjects/Track.h>
30 #include <mdst/dataobjects/PIDLikelihood.h>
31 
32 #include <analysis/dataobjects/Particle.h>
33 #include <analysis/dataobjects/ParticleList.h>
34 #include <analysis/dataobjects/ParticleExtraInfoMap.h>
35 #include <analysis/dataobjects/EventExtraInfo.h>
36 
37 // utilities
38 #include <analysis/DecayDescriptor/ParticleListName.h>
39 #include <analysis/utility/PCmsLabTransform.h>
40 
41 #include <utility>
42 
43 using namespace std;
44 
45 namespace Belle2 {
51  //-----------------------------------------------------------------
52  // Register module
53  //-----------------------------------------------------------------
54 
55  REG_MODULE(ParticleLoader)
56 
57  //-----------------------------------------------------------------
58  // Implementation
59  //-----------------------------------------------------------------
60 
62 
63  {
64  setDescription("Loads MDST dataobjects as Particle objects to the StoreArray<Particle> and collects them in specified ParticleList.");
65  setPropertyFlags(c_ParallelProcessingCertified);
66 
67  // Add parameters
68  std::vector<std::tuple<std::string, std::string>> emptyDecayStringsAndCuts;
69 
70  addParam("decayStringsWithCuts", m_decayStringsWithCuts,
71  "List of (decayString, Variable::Cut) tuples that specify all output ParticleLists to be created by the module. Only Particles that pass specified selection criteria are added to the ParticleList (see :ref:`DecayString` and `cut_strings_selections`).",
72  emptyDecayStringsAndCuts);
73 
74  addParam("useMCParticles", m_useMCParticles,
75  "Use MCParticles instead of reconstructed MDST dataobjects (tracks, ECL, KLM, clusters, V0s, ...)", false);
76 
77  addParam("useROEs", m_useROEs,
78  "Use ROE instead of reconstructed MDST dataobjects (tracks, ECL, KLM, clusters, V0s, ...)", false);
79 
80  addParam("roeMaskName", m_roeMaskName,
81  "ROE mask name to load", std::string(""));
82 
83  addParam("sourceParticleListName", m_sourceParticleListName,
84  "Particle list name from which we need to get ROEs", std::string(""));
85 
86  addParam("useMissing", m_useMissing,
87  "If true, the Particle List will be filled with missing momentum from the ROE and signal particle.", false);
88 
89  addParam("writeOut", m_writeOut,
90  "If true, the output ParticleList will be saved by RootOutput. If false, it will be ignored when writing the file.", false);
91 
92  addParam("addDaughters", m_addDaughters,
93  "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",
94  false);
95 
96  addParam("skipNonPrimaryDaughters", m_skipNonPrimaryDaughters,
97  "If true, the secondary MC daughters will be skipped, default is false",
98  false);
99 
100  addParam("trackHypothesis", m_trackHypothesis,
101  "Track hypothesis to use when loading the particle. By default, use the particle's own hypothesis.",
102  0);
103 
104  addParam("enforceFitHypothesis", m_enforceFitHypothesis,
105  "If true, a Particle is only created if a track fit with the particle hypothesis passed to the ParticleLoader is available.",
106  m_enforceFitHypothesis);
107  }
108 
109  void ParticleLoaderModule::initialize()
110  {
111  B2INFO("ParticleLoader's Summary of Actions:");
112 
113  StoreArray<Particle> particles;
114  StoreArray<MCParticle> mcparticles;
115  StoreArray<PIDLikelihood> pidlikelihoods;
116  StoreArray<TrackFitResult> trackfitresults;
118  StoreObjPtr<EventExtraInfo> eventExtraInfo;
119 
120  particles.registerInDataStore();
121  extraInfoMap.registerInDataStore();
122  eventExtraInfo.registerInDataStore();
123  //register relations if these things exists
124  if (mcparticles.isOptional()) {
125  particles.registerRelationTo(mcparticles);
126  }
127  if (pidlikelihoods.isOptional()) {
128  particles.registerRelationTo(pidlikelihoods);
129  }
130  if (trackfitresults.isOptional()) {
131  particles.registerRelationTo(trackfitresults);
132  }
133 
134  if (m_useMCParticles) {
135  mcparticles.isRequired();
136  }
137 
138  if (m_decayStringsWithCuts.empty()) {
139  B2WARNING("Obsolete usage of the ParticleLoader module (load all MDST objects as all possible Particle object types). Specify the particle type via decayStringsWithCuts module parameter instead.");
140  } else {
141  for (auto decayStringCutTuple : m_decayStringsWithCuts) {
142 
143  // parsing of the input tuple (DecayString, Cut)
144  string decayString = get<0>(decayStringCutTuple);
145  std::string cutParameter = get<1>(decayStringCutTuple);
146 
147  // obtain the output particle lists from the decay string
148  bool valid = m_decaydescriptor.init(decayString);
149  if (!valid)
150  B2ERROR("ParticleLoaderModule::initialize Invalid input DecayString: " << decayString);
151 
152  // Mother particle
153  const DecayDescriptorParticle* mother = m_decaydescriptor.getMother();
154 
155  int pdgCode = mother->getPDGCode();
156  string listName = mother->getFullName();
157 
158  // special case. if the list is called "all" it may not have a
159  // corresponding cut string this can introduce very dangerous bugs
160  string listLabel = mother->getLabel();
161  if (listLabel == "all")
162  if (cutParameter != "")
163  B2FATAL("You have tried to create a list " << listName << " with cuts! This is *very* error prone, so it is now forbidden.");
164 
165  if (not isValidPDGCode(pdgCode) and (m_useMCParticles == false and m_useROEs == false))
166  B2ERROR("Invalid particle type requested to be loaded. Set a valid decayString module parameter.");
167 
168  // if we're not loading MCParticles and we are loading K0S, Lambdas, or photons --> ee then this decaystring is a V0
169  bool mdstSourceIsV0 = false;
170  if (!m_useMCParticles &&
171  (abs(pdgCode) == abs(Const::Kshort.getPDGCode()) || abs(pdgCode) == abs(Const::Lambda.getPDGCode())
172  || (abs(pdgCode) == abs(Const::photon.getPDGCode()) && m_addDaughters == true)))
173  mdstSourceIsV0 = true;
174 
175  int nProducts = m_decaydescriptor.getNDaughters();
176  if (mdstSourceIsV0 == false) {
177  if (nProducts > 0) {
178  if (!m_useROEs) {
179  B2ERROR("ParticleLoaderModule::initialize Invalid input DecayString " << decayString
180  << ". DecayString should not contain any daughters, only the mother particle.");
181  } else {
182  B2INFO("ParticleLoaderModule: Replacing the source particle list name by " <<
183  m_decaydescriptor.getDaughter(0)->getMother()->getFullName()
184  << " all other daughters will be ignored.");
185  m_sourceParticleListName = m_decaydescriptor.getDaughter(0)->getMother()->getFullName();
186  }
187  }
188  } else {
189  if (nProducts != 2)
190  B2ERROR("ParticleLoaderModule::initialize Invalid input DecayString " << decayString
191  << ". MDST source of the particle list is V0, DecayString should contain exactly two daughters, as well as the mother particle.");
192  else {
193  if (m_decaydescriptor.getDaughter(0)->getMother()->getPDGCode() * m_decaydescriptor.getDaughter(1)->getMother()->getPDGCode() > 0)
194  B2ERROR("MDST source of the particle list is V0, the two daughters should have opposite charge");
195  }
196  }
197 
198  string antiListName = ParticleListName::antiParticleListName(listName);
199  bool isSelfConjugatedParticle = (listName == antiListName);
200 
201  StoreObjPtr<ParticleList> particleList(listName);
202  if (!particleList.isOptional()) {
203  //if it doesn't exist:
204 
205  DataStore::EStoreFlags flags = m_writeOut ? DataStore::c_WriteOut : DataStore::c_DontWriteOut;
206  particleList.registerInDataStore(flags);
207  if (!isSelfConjugatedParticle) {
208  StoreObjPtr<ParticleList> antiParticleList(antiListName);
209  antiParticleList.registerInDataStore(flags);
210  }
211  } else {
212  // TODO: test that this actually works
213  B2WARNING("The ParticleList with name " << listName << " already exists in the DataStore. Nothing to do.");
214  continue;
215  }
216 
217  std::shared_ptr<Variable::Cut> cut = std::shared_ptr<Variable::Cut>(Variable::Cut::compile(cutParameter));
218 
219  // add PList to corresponding collection of Lists
220  B2INFO(" o) creating (anti-)ParticleList with name: " << listName << " (" << antiListName << ")");
221  if (m_useROEs) {
222  B2INFO(" -> MDST source: RestOfEvents");
223  m_ROE2Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle, cut);
224  } else if (m_useMCParticles) {
225  B2INFO(" -> MDST source: MCParticles");
226  m_MCParticles2Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle, cut);
227  } else {
228  bool chargedFSP = Const::chargedStableSet.contains(Const::ParticleType(abs(pdgCode)));
229  if (chargedFSP) {
230  B2INFO(" -> MDST source: Tracks");
231  m_Tracks2Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle, cut);
232  }
233 
234  if (abs(pdgCode) == abs(Const::photon.getPDGCode())) {
235  if (m_addDaughters == false) {
236  B2INFO(" -> MDST source: ECLClusters");
237  m_ECLClusters2Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle, cut);
238  } else {
239  B2INFO(" -> MDST source: V0");
240  m_V02Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle, cut);
241  }
242  }
243 
244  if (abs(pdgCode) == abs(Const::Kshort.getPDGCode())) {
245  B2INFO(" -> MDST source: V0");
246  m_V02Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle, cut);
247  }
248 
249  if (abs(pdgCode) == abs(Const::Klong.getPDGCode()) || abs(pdgCode) == abs(Const::neutron.getPDGCode())) {
250  B2INFO(" -> MDST source: exclusively KLMClusters or exclusively ECLClusters (matching between those not used)");
251  m_KLMClusters2Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle, cut);
252  m_ECLClusters2Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle, cut);
253  }
254 
255  if (abs(pdgCode) == abs(Const::Lambda.getPDGCode())) {
256  B2INFO(" -> MDST source: V0");
257  m_V02Plists.emplace_back(pdgCode, listName, antiListName, isSelfConjugatedParticle, cut);
258  }
259  }
260  B2INFO(" -> With cuts : " << cutParameter);
261  }
262  }
263 
264 
265  m_chargeZeroTrackCounts = std::vector<int>(m_Tracks2Plists.size(), 0);
266  m_sameChargeDaughtersV0Counts = std::vector<int>(m_V02Plists.size(), 0);
267  }
268 
269  void ParticleLoaderModule::event()
270  {
271  StoreArray<Particle> particles;
272  StoreObjPtr<ParticleExtraInfoMap> particleExtraInfoMap;
273  if (not particleExtraInfoMap) {
274  particleExtraInfoMap.create();
275  }
276 
277  if (m_useROEs)
278  roeToParticles();
279  else if (m_useMCParticles)
280  mcParticlesToParticles();
281  else {
282  tracksToParticles();
283  eclClustersToParticles();
284  klmClustersToParticles();
285  v0sToParticles();
286  }
287  }
288 
289  void ParticleLoaderModule::terminate()
290  {
291  // report track errors integrated
292  for (size_t i = 0; i < m_Tracks2Plists.size(); i++)
293  if (m_chargeZeroTrackCounts[i] > 0) {
294  auto track2Plist = m_Tracks2Plists[i];
295  B2WARNING("There were " << m_chargeZeroTrackCounts[i]
296  << " tracks skipped because of zero charge for "
297  << get<c_PListName>(track2Plist));
298  }
299  // report V0 errors integrated
300  for (size_t i = 0; i < m_V02Plists.size(); i++)
301  if (m_sameChargeDaughtersV0Counts[i] > 0) {
302  auto v02Plist = m_V02Plists[i];
303  B2WARNING("There were " << m_sameChargeDaughtersV0Counts[i]
304  << " v0s skipped because of same charge daughters for "
305  << get<c_PListName>(v02Plist));
306  }
307  }
308 
309  void ParticleLoaderModule::roeToParticles()
310  {
311  if (m_ROE2Plists.empty()) // nothing to do
312  return;
313  // Multiple particle lists are not supported
314  auto roe2Plist = m_ROE2Plists[0];
315  string listName = get<c_PListName>(roe2Plist);
316  string antiListName = get<c_AntiPListName>(roe2Plist);
317  int pdgCode = get<c_PListPDGCode>(roe2Plist);
318  bool isSelfConjugatedParticle = get<c_IsPListSelfConjugated>(roe2Plist);
319 
320  StoreObjPtr<ParticleList> plist(listName);
321  plist.create();
322  plist->initialize(pdgCode, listName);
323 
324  if (!isSelfConjugatedParticle) {
325  StoreObjPtr<ParticleList> antiPlist(antiListName);
326  antiPlist.create();
327  antiPlist->initialize(-1 * pdgCode, antiListName);
328  antiPlist->bindAntiParticleList(*(plist));
329  }
330  if (m_sourceParticleListName != "") {
331  // Take related ROEs from a particle list
332  StoreObjPtr<ParticleList> pList(m_sourceParticleListName);
333  if (!pList.isValid())
334  B2FATAL("ParticleList " << m_sourceParticleListName << " could not be found or is not valid!");
335  for (unsigned int i = 0; i < pList->getListSize(); i++) {
336  RestOfEvent* roe = pList->getParticle(i)->getRelatedTo<RestOfEvent>("ALL");
337  if (!roe) {
338  B2ERROR("ParticleList " << m_sourceParticleListName << " has no associated ROEs!");
339  } else {
340  addROEToParticleList(roe, pdgCode);
341  }
342  }
343 
344  } else {
345  // Take all ROE if no particle list provided
347  for (int i = 0; i < roes.getEntries(); i++) {
348  addROEToParticleList(roes[i]);
349  }
350  }
351  }
352 
353  void ParticleLoaderModule::addROEToParticleList(RestOfEvent* roe, int pdgCode, bool isSelfConjugatedParticle)
354  {
355 
356  Particle* newPart = nullptr;
357  if (!m_useMissing) {
358  // Convert ROE to particle
359  newPart = roe->convertToParticle(m_roeMaskName, pdgCode, isSelfConjugatedParticle);
360  } else {
361  // Create a particle from missing momentum
362  StoreArray<Particle> particles;
363  auto* signalSideParticle = roe->getRelatedFrom<Particle>();
365  TLorentzVector boost4Vector = T.getBeamFourMomentum();
366 
367  TLorentzVector signal4Vector = signalSideParticle->get4Vector();
368  TLorentzVector roe4Vector = roe->get4Vector(m_roeMaskName);
369  TLorentzVector missing4Vector;
370  missing4Vector.SetVect(boost4Vector.Vect() - (signal4Vector.Vect() + roe4Vector.Vect()));
371  missing4Vector.SetE(missing4Vector.Vect().Mag());
372  newPart = particles.appendNew(missing4Vector, pdgCode);
373 
374  }
375  for (auto roe2Plist : m_ROE2Plists) {
376  string listName = get<c_PListName>(roe2Plist);
377  auto& cut = get<c_CutPointer>(roe2Plist);
378  StoreObjPtr<ParticleList> plist(listName);
379  if (cut->check(newPart))
380  plist->addParticle(newPart);
381  }
382 
383  }
384 
385 
386  void ParticleLoaderModule::v0sToParticles()
387  {
388  if (m_V02Plists.empty()) // nothing to do
389  return;
390 
391  // create all lists
392  for (auto v02Plist : m_V02Plists) {
393  string listName = get<c_PListName>(v02Plist);
394  string antiListName = get<c_AntiPListName>(v02Plist);
395  int pdgCode = get<c_PListPDGCode>(v02Plist);
396  bool isSelfConjugatedParticle = get<c_IsPListSelfConjugated>(v02Plist);
397 
398  StoreObjPtr<ParticleList> plist(listName);
399  plist.create();
400  plist->initialize(pdgCode, listName);
401 
402  if (!isSelfConjugatedParticle) {
403  StoreObjPtr<ParticleList> antiPlist(antiListName);
404  antiPlist.create();
405  antiPlist->initialize(-1 * pdgCode, antiListName);
406 
407  antiPlist->bindAntiParticleList(*(plist));
408  }
409  }
410 
411  StoreArray<V0> V0s;
412  StoreArray<Particle> particles;
413 
414  // check if the order of the daughters in the decay string (decided by the user) is the same of the v0 daughers order (fixed)
415  bool matchingDaughtersOrder = true;
416  if (m_decaydescriptor.getDaughter(0)->getMother()->getPDGCode() < 0
417  && m_decaydescriptor.getDaughter(1)->getMother()->getPDGCode() > 0)
418  matchingDaughtersOrder = false;
419 
420  // load reconstructed V0s as Kshorts (pi-pi+ combination), Lambdas (p+pi- combinations), and converted photons (e-e+ combinations)
421  for (int i = 0; i < V0s.getEntries(); i++) {
422  const V0* v0 = V0s[i];
423  Const::ParticleType v0Type = v0->getV0Hypothesis();
424 
425  // inner loop over the ParticleLists
426  for (size_t ilist = 0; ilist < m_V02Plists.size(); ilist++) {
427  auto v02Plist = m_V02Plists[ilist];
428  int listPDGCode = get<c_PListPDGCode>(v02Plist);
429 
430  if (abs(listPDGCode) != abs(v0Type.getPDGCode()))
431  continue;
432 
433  // check if the charge of the 2 V0's daughters is opposite
434  if (v0->getTrackFitResults().first->getChargeSign() == v0->getTrackFitResults().second->getChargeSign()) {
435  B2DEBUG(19, "V0 with same charge daughters skipped!");
436  m_sameChargeDaughtersV0Counts[ilist]++;
437  continue;
438  }
439 
440  Const::ChargedStable pTypeP(Const::pion);
441  Const::ChargedStable pTypeM(Const::pion);
442  Particle::EFlavorType v0FlavorType = Particle::c_Unflavored;
443 
444  if (v0Type.getPDGCode() == Const::Kshort.getPDGCode()) { // K0s -> pi+ pi-
445  pTypeP = Const::pion;
446  pTypeM = Const::pion;
447  } else if (v0Type.getPDGCode() == Const::Lambda.getPDGCode()) { // Lambda -> p+ pi-
448  pTypeP = Const::proton;
449  pTypeM = Const::pion;
450  v0FlavorType = Particle::c_Flavored; // K0s are not flavoured, lambdas are
451  } else if (v0Type.getPDGCode() == Const::antiLambda.getPDGCode()) { // anti-Lambda -> pi+ anti-p-
452  pTypeP = Const::pion;
453  pTypeM = Const::proton;
454  v0FlavorType = Particle::c_Flavored;
455  } else if (v0Type.getPDGCode() == Const::photon.getPDGCode()) { // gamma -> e+ e-
456  pTypeP = Const::electron;
457  pTypeM = Const::electron;
458  } else {
459  B2WARNING("Unknown V0 hypothesis!");
460  }
461 
462  // check if, given the initial user's decay descriptor, the current v0 is a particle or an anti-particle.
463  // in the V0 the order of the daughters is fixed, first the positive and then the negative; to be coherent with the decay desctiptor, when creating
464  // one particle list and one anti-particle, the v0 daughters' order has to be switched only in one case
465  bool correctOrder = matchingDaughtersOrder;
466  if (abs(v0Type.getPDGCode()) == abs(m_decaydescriptor.getMother()->getPDGCode())
467  && v0Type.getPDGCode() != m_decaydescriptor.getMother()->getPDGCode())
468  correctOrder = !correctOrder;
469 
470  std::pair<Track*, Track*> v0Tracks = v0->getTracks();
471  std::pair<TrackFitResult*, TrackFitResult*> v0TrackFitResults = v0->getTrackFitResults();
472 
473  Particle daugP((v0Tracks.first)->getArrayIndex(), v0TrackFitResults.first, pTypeP);
474  Particle daugM((v0Tracks.second)->getArrayIndex(), v0TrackFitResults.second, pTypeM);
475 
476  const PIDLikelihood* pidP = (v0Tracks.first)->getRelated<PIDLikelihood>();
477  const PIDLikelihood* pidM = (v0Tracks.second)->getRelated<PIDLikelihood>();
478 
479  const auto& mcParticlePWithWeight = (v0Tracks.first)->getRelatedToWithWeight<MCParticle>();
480  const auto& mcParticleMWithWeight = (v0Tracks.second)->getRelatedToWithWeight<MCParticle>();
481 
482  // add V0 daughters to the Particle StoreArray
483  Particle* newDaugP;
484  Particle* newDaugM;
485 
486  if (correctOrder) {
487  newDaugP = particles.appendNew(daugP);
488  newDaugM = particles.appendNew(daugM);
489  } else {
490  newDaugM = particles.appendNew(daugM);
491  newDaugP = particles.appendNew(daugP);
492  }
493 
494  // if there are PIDLikelihoods and MCParticles then also add relations to the particles
495  if (pidP)
496  newDaugP->addRelationTo(pidP);
497  if (mcParticlePWithWeight.first)
498  newDaugP->addRelationTo(mcParticlePWithWeight.first, mcParticlePWithWeight.second);
499  newDaugP->addRelationTo(v0TrackFitResults.first);
500 
501  if (pidM)
502  newDaugM->addRelationTo(pidM);
503  if (mcParticleMWithWeight.first)
504  newDaugM->addRelationTo(mcParticleMWithWeight.first, mcParticleMWithWeight.second);
505  newDaugM->addRelationTo(v0TrackFitResults.second);
506 
507  // sum the 4-momenta of the daughters and construct a particle object
508  TLorentzVector v0Momentum = newDaugP->get4Vector() + newDaugM->get4Vector();
509  Particle v0P(v0Momentum, v0Type.getPDGCode(), v0FlavorType,
510  Particle::EParticleSourceObject::c_V0, v0->getArrayIndex());
511 
512  // add the daughters of the V0 (in the correct order) and don't update
513  // the type to c_Composite (i.e. maintain c_V0)
514  if (correctOrder) {
515  v0P.appendDaughter(newDaugP, false);
516  v0P.appendDaughter(newDaugM, false);
517  } else {
518  v0P.appendDaughter(newDaugM, false);
519  v0P.appendDaughter(newDaugP, false);
520  }
521 
522  // append the particle to the Particle StoreArray and check that we pass
523  // any cuts before adding the new particle to the ParticleList
524  Particle* newPart = particles.appendNew(v0P);
525  string listName = get<c_PListName>(v02Plist);
526  auto& cut = get<c_CutPointer>(v02Plist);
527  StoreObjPtr<ParticleList> plist(listName);
528 
529  if (cut->check(newPart))
530  plist->addParticle(newPart);
531  }
532  }
533  }
534 
535  void ParticleLoaderModule::tracksToParticles()
536  {
537  if (m_Tracks2Plists.empty()) // nothing to do
538  return;
539 
540  // create and initialize the particle lists
541  for (auto track2Plist : m_Tracks2Plists) {
542  string listName = get<c_PListName>(track2Plist);
543  string antiListName = get<c_AntiPListName>(track2Plist);
544  int pdgCode = get<c_PListPDGCode>(track2Plist);
545  bool isSelfConjugatedParticle = get<c_IsPListSelfConjugated>(track2Plist);
546 
547  StoreObjPtr<ParticleList> plist(listName);
548  plist.create();
549  plist->initialize(pdgCode, listName);
550 
551  // if cc exists then also create and bind that list
552  if (!isSelfConjugatedParticle) {
553  StoreObjPtr<ParticleList> antiPlist(antiListName);
554  antiPlist.create();
555  antiPlist->initialize(-1 * pdgCode, antiListName);
556 
557  antiPlist->bindAntiParticleList(*(plist));
558  }
559  }
560 
561  // grab the StoreArray for tracks and particles
562  StoreArray<Track> Tracks;
563  StoreArray<Particle> particles;
564 
565  // the outer loop over all tracks from which Particles
566  // are created, and get sorted in the particle lists
567  for (int i = 0; i < Tracks.getEntries(); i++) {
568  const Track* track = Tracks[i];
569  const PIDLikelihood* pid = track->getRelated<PIDLikelihood>();
570  const auto& mcParticleWithWeight = track->getRelatedToWithWeight<MCParticle>();
571 
572  // inner loop over the ParticleLists
573  for (size_t ilist = 0; ilist < m_Tracks2Plists.size(); ilist++) {
574  auto track2Plist = m_Tracks2Plists[ilist];
575  string listName = get<c_PListName>(track2Plist);
576  auto& cut = get<c_CutPointer>(track2Plist);
577  StoreObjPtr<ParticleList> plist(listName);
578 
579  // if no track hypothesis is requested, use the particle's own
580  int pdgCode;
581  if (m_trackHypothesis == 0)
582  pdgCode = get<c_PListPDGCode>(track2Plist);
583  else pdgCode = m_trackHypothesis;
584  Const::ChargedStable type(abs(pdgCode));
585 
586  // load the TrackFitResult for the requested particle or if not available use
587  // the one with the closest mass
588  const TrackFitResult* trackFit = track->getTrackFitResultWithClosestMass(type);
589 
590  if (!trackFit) { // should never happen with the "closest mass" getter - leave as a sanity check
591  B2WARNING("Track returned null TrackFitResult pointer for ChargedStable::getPDGCode() = " << type.getPDGCode());
592  continue;
593  }
594 
595  if (m_enforceFitHypothesis && (trackFit->getParticleType().getPDGCode() != type.getPDGCode())) {
596  // the required hypothesis does not exist for this track, skip it
597  continue;
598  }
599 
600  // charge zero tracks can appear, filter them and
601  // count number of tracks filtered out
602  int charge = trackFit->getChargeSign();
603  if (charge == 0) {
604  B2DEBUG(19, "Track with charge = 0 skipped!");
605  m_chargeZeroTrackCounts[ilist]++;
606  continue;
607  }
608 
609  // create particle and add it to the Particle list.
610  Particle particle(track->getArrayIndex(), trackFit, type);
611 
612  if (particle.getParticleSource() == Particle::c_Track) { // should always hold but...
613 
614  Particle* newPart = particles.appendNew(particle);
615  if (pid)
616  newPart->addRelationTo(pid);
617  if (mcParticleWithWeight.first)
618  newPart->addRelationTo(mcParticleWithWeight.first, mcParticleWithWeight.second);
619  newPart->addRelationTo(trackFit);
620 
621  if (cut->check(newPart))
622  plist->addParticle(newPart);
623 
624  } // sanity check correct particle type
625  } // particle lists
626  } // loop over tracks
627  }
628 
629  void ParticleLoaderModule::eclClustersToParticles()
630  {
631  if (m_ECLClusters2Plists.empty()) // nothing to do
632  return;
633 
634  // create and register all ParticleLists
635  for (auto eclCluster2Plist : m_ECLClusters2Plists) {
636  string listName = get<c_PListName>(eclCluster2Plist);
637  string antiListName = get<c_AntiPListName>(eclCluster2Plist);
638  int pdgCode = get<c_PListPDGCode>(eclCluster2Plist);
639  bool isSelfConjugatedParticle = get<c_IsPListSelfConjugated>(eclCluster2Plist);
640 
641  StoreObjPtr<ParticleList> plist(listName);
642  if (!plist) { // create the list only if the klmClustersToParticles function has not already created it
643  plist.create();
644  plist->initialize(pdgCode, listName);
645 
646  // create anti-particle list if necessary
647  if (!isSelfConjugatedParticle) {
648  StoreObjPtr<ParticleList> antiPlist(antiListName);
649  antiPlist.create();
650  antiPlist->initialize(-1 * pdgCode, antiListName);
651 
652  antiPlist->bindAntiParticleList(*(plist));
653  }
654  }
655  }
656 
657  // StoreArrays needed to load eclclusters as particles
658  // (and mcmatching)
659  StoreArray<ECLCluster> ECLClusters;
660  StoreArray<Particle> particles;
661  StoreArray<MCParticle> mcParticles;
662 
663  // outer loop over all ECLClusters
664  for (int i = 0; i < ECLClusters.getEntries(); i++) {
665  const ECLCluster* cluster = ECLClusters[i];
666 
667  // ECLClusters can be reconstructed under different hypotheses, for
668  // example photons or neutral hadrons, we only load particles from these
669  // for now
670  if (!cluster->isNeutral()) continue;
671  if (not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons)
672  and not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron))
673  continue;
674 
675  // ECLCluster can be matched to multiple MCParticles
676  // order the relations by weights and set Particle -> multiple MCParticle relation
677  // preserve the weight
678  RelationVector<MCParticle> mcRelations = cluster->getRelationsTo<MCParticle>();
679  // order relations by weights
680  std::vector<std::pair<int, double>> weightsAndIndices;
681  for (unsigned int iMCParticle = 0; iMCParticle < mcRelations.size(); iMCParticle++) {
682  const MCParticle* relMCParticle = mcRelations[iMCParticle];
683  double weight = mcRelations.weight(iMCParticle);
684  if (relMCParticle)
685  weightsAndIndices.emplace_back(relMCParticle->getArrayIndex(), weight);
686  }
687  // sort descending by weight
688  std::sort(weightsAndIndices.begin(), weightsAndIndices.end(),
689  [](const std::pair<int, double>& left, const std::pair<int, double>& right) {
690  return left.second > right.second;
691  });
692 
693  // inner loop over ParticleLists: fill each relevant list with Particles
694  // created from ECLClusters
695  for (auto eclCluster2Plist : m_ECLClusters2Plists) {
696  string listName = get<c_PListName>(eclCluster2Plist);
697  int listPdgCode = get<c_PListPDGCode>(eclCluster2Plist);
698  Const::ParticleType thisType(listPdgCode);
699 
700  // don't fill photon list with clusters that don't have
701  // the nPhotons hypothesis (ECL people call this N1)
702  if (listPdgCode == Const::photon.getPDGCode()
703  and not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons))
704  continue;
705 
706  // don't fill a KLong list with clusters that don't have the neutral
707  // hadron hypothesis set (ECL people call this N2)
708  if (listPdgCode == Const::Klong.getPDGCode()
709  and not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron))
710  continue;
711 
712  // don't fill a neutron list with clusters that don't have the neutral
713  // hadron hypothesis set (ECL people call this N2)
714  if (abs(listPdgCode) == Const::neutron.getPDGCode()
715  and not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron))
716  continue;
717 
718  // create particle and check it before adding to list
719  Particle particle(cluster, thisType);
720  if (particle.getParticleSource() != Particle::c_ECLCluster) {
721  B2FATAL("Particle created from ECLCluster does not have ECLCluster type.");
722  continue;
723  }
724  Particle* newPart = particles.appendNew(particle);
725 
726  // set relations to mcparticles
727  for (auto& weightsAndIndex : weightsAndIndices) {
728  const MCParticle* relMCParticle = mcParticles[weightsAndIndex.first];
729  double weight = weightsAndIndex.second;
730 
731  // TODO: study this further and avoid hard-coded values
732  // set the relation only if the MCParticle(reconstructed Particle)'s
733  // energy contribution to this cluster amounts to at least 30(20)%
734  if (relMCParticle)
735  if (weight / newPart->getECLClusterEnergy() > 0.20
736  && weight / relMCParticle->getEnergy() > 0.30)
737  newPart->addRelationTo(relMCParticle, weight);
738  }
739 
740 
741  // add particle to list if it passes the selection criteria
742  auto& cut = get<c_CutPointer>(eclCluster2Plist);
743  StoreObjPtr<ParticleList> plist(listName);
744  if (cut->check(newPart))
745  plist->addParticle(newPart);
746 
747  } // loop over particle lists to be filled by ECLClusters
748  } // loop over cluster
749  }
750 
751  void ParticleLoaderModule::klmClustersToParticles()
752  {
753  if (m_KLMClusters2Plists.empty()) // nothing to do
754  return;
755 
756  // create all lists
757  for (auto klmCluster2Plist : m_KLMClusters2Plists) {
758  string listName = get<c_PListName>(klmCluster2Plist);
759  string antiListName = get<c_AntiPListName>(klmCluster2Plist);
760  int pdgCode = get<c_PListPDGCode>(klmCluster2Plist);
761  bool isSelfConjugatedParticle = get<c_IsPListSelfConjugated>(klmCluster2Plist);
762 
763  StoreObjPtr<ParticleList> plist(listName);
764  if (!plist) { // create the list only if the eclClustersToParticle has not already created it
765  plist.create();
766  plist->initialize(pdgCode, listName);
767 
768  if (!isSelfConjugatedParticle) {
769  StoreObjPtr<ParticleList> antiPlist(antiListName);
770  antiPlist.create();
771  antiPlist->initialize(-1 * pdgCode, antiListName);
772 
773  antiPlist->bindAntiParticleList(*(plist));
774  }
775  }
776  }
777 
778  StoreArray<KLMCluster> KLMClusters;
779  StoreArray<Particle> particles;
780 
781  // load reconstructed neutral KLM cluster's as Klongs or neutrons
782  for (int i = 0; i < KLMClusters.getEntries(); i++) {
783  const KLMCluster* cluster = KLMClusters[i];
784 
785  if (std::isnan(cluster->getMomentumMag())) {
786  B2WARNING("Skipping KLMCluster because of nan momentum.");
787  continue;
788  }
789 
790  const MCParticle* mcParticle = cluster->getRelated<MCParticle>();
791 
792  for (auto klmCluster2Plist : m_KLMClusters2Plists) {
793  string listName = get<c_PListName>(klmCluster2Plist);
794  int pdgCode = get<c_PListPDGCode>(klmCluster2Plist);
795 
796  // create particle and check its type before adding it to list
797  Particle particle(cluster, pdgCode);
798  if (particle.getParticleSource() != Particle::c_KLMCluster) {
799  B2FATAL("Particle created from KLMCluster does not have KLMCluster type.");
800  }
801  Particle* newPart = particles.appendNew(particle);
802 
803  if (mcParticle)
804  newPart->addRelationTo(mcParticle);
805 
806  // add particle to list if it passes the selection criteria
807  auto& cut = get<c_CutPointer>(klmCluster2Plist);
808  StoreObjPtr<ParticleList> plist(listName);
809 
810  if (cut->check(newPart))
811  plist->addParticle(newPart);
812  }
813  }
814  }
815 
816  void ParticleLoaderModule::mcParticlesToParticles()
817  {
818  if (m_MCParticles2Plists.empty()) // nothing to do
819  return;
820 
821  // create all lists
822  for (auto mcParticle2Plist : m_MCParticles2Plists) {
823  string listName = get<c_PListName>(mcParticle2Plist);
824  string antiListName = get<c_AntiPListName>(mcParticle2Plist);
825  int pdgCode = get<c_PListPDGCode>(mcParticle2Plist);
826  bool isSelfConjugatedParticle = get<c_IsPListSelfConjugated>(mcParticle2Plist);
827 
828  StoreObjPtr<ParticleList> plist(listName);
829  plist.create();
830  plist->initialize(pdgCode, listName);
831 
832  if (!isSelfConjugatedParticle) {
833  StoreObjPtr<ParticleList> antiPlist(antiListName);
834  antiPlist.create();
835  antiPlist->initialize(-1 * pdgCode, antiListName);
836 
837  antiPlist->bindAntiParticleList(*(plist));
838  }
839  }
840 
841  StoreArray<MCParticle> MCParticles;
842  StoreArray<Particle> particles;
843 
844  for (int i = 0; i < MCParticles.getEntries(); i++) {
845  const MCParticle* mcParticle = MCParticles[i];
846 
847  for (auto mcParticle2Plist : m_MCParticles2Plists) {
848  int pdgCode = get<c_PListPDGCode>(mcParticle2Plist);
849 
850  if (abs(pdgCode) != abs(mcParticle->getPDG()))
851  continue;
852 
853  Particle particle(mcParticle);
854  Particle* newPart = particles.appendNew(particle);
855  newPart->addRelationTo(mcParticle);
856 
857  //append the whole bottom part of the decay tree to this particle
858  if (m_addDaughters) appendDaughtersRecursive(newPart);
859 
860  string listName = get<c_PListName>(mcParticle2Plist);
861  auto& cut = get<c_CutPointer>(mcParticle2Plist);
862  StoreObjPtr<ParticleList> plist(listName);
863 
864  if (cut->check(newPart))
865  plist->addParticle(newPart);
866  }
867  }
868  }
869 
870  bool ParticleLoaderModule::isValidPDGCode(const int pdgCode)
871  {
872  bool result = false;
873 
874  // is particle type = charged final state particle?
875  if (Const::chargedStableSet.find(abs(pdgCode)) != Const::invalidParticle)
876  return true;
877 
878  if (abs(pdgCode) == abs(Const::photon.getPDGCode()))
879  return true;
880 
881  if (abs(pdgCode) == abs(Const::Kshort.getPDGCode()))
882  return true;
883 
884  if (abs(pdgCode) == abs(Const::Klong.getPDGCode()))
885  return true;
886 
887  if (abs(pdgCode) == abs(Const::Lambda.getPDGCode()))
888  return true;
889 
890  if (abs(pdgCode) == abs(Const::neutron.getPDGCode()))
891  return true;
892 
893  return result;
894  }
895 
896  void ParticleLoaderModule::appendDaughtersRecursive(Particle* mother)
897  {
898  StoreArray<Particle> particles;
899  auto* mcmother = mother->getRelated<MCParticle>();
900 
901  if (!mcmother)
902  return;
903 
904  vector<MCParticle*> mcdaughters = mcmother->getDaughters();
905 
906  for (auto& mcdaughter : mcdaughters) {
907  if (!mcdaughter->hasStatus(MCParticle::c_PrimaryParticle) and m_skipNonPrimaryDaughters) continue;
908  Particle particle(mcdaughter);
909  Particle* daughter = particles.appendNew(particle);
910  daughter->addRelationTo(mcdaughter);
911  mother->appendDaughter(daughter, false);
912 
913  if (mcdaughter->getNDaughters() > 0)
914  appendDaughtersRecursive(daughter);
915  }
916  }
917 
918 
920 } // end Belle2 namespace
Belle2::RelationVector::size
size_t size() const
Get number of relations.
Definition: RelationVector.h:98
Belle2::MCParticle::getEnergy
float getEnergy() const
Return particle energy in GeV.
Definition: MCParticle.h:158
Belle2::RestOfEvent::get4Vector
TLorentzVector get4Vector(const std::string &maskName="") const
Get 4-momentum vector all (no mask) or a subset (use mask) of all Tracks and ECLClusters in ROE.
Definition: RestOfEvent.cc:283
Belle2::V0
Object holding information for V0s.
Definition: V0.h:40
Belle2::ECLCluster
ECL cluster data.
Definition: ECLCluster.h:39
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::V0::getTracks
std::pair< Track *, Track * > getTracks() const
Get pair of yhe Tracks, that are part of the V0 particle.
Definition: V0.h:50
Belle2::DataStore::EStoreFlags
EStoreFlags
Flags describing behaviours of objects etc.
Definition: DataStore.h:71
Belle2::DecayDescriptorParticle
Represents a particle in the DecayDescriptor.
Definition: DecayDescriptorParticle.h:37
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::Const::ParticleType::getPDGCode
int getPDGCode() const
PDG code.
Definition: Const.h:349
Belle2::RestOfEvent
This is a general purpose class for collecting reconstructed MDST data objects that are not used in r...
Definition: RestOfEvent.h:59
Belle2::PIDLikelihood
Class to collect log likelihoods from TOP, ARICH, dEdx, ECL and KLM aimed for output to mdst includes...
Definition: PIDLikelihood.h:37
Belle2::MCParticle::getArrayIndex
int getArrayIndex() const
Get 0-based index of the particle in the corresponding MCParticle list.
Definition: MCParticle.h:255
Belle2::TrackFitResult
Values of the result of a track fit with a given particle hypothesis.
Definition: TrackFitResult.h:59
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2::RestOfEvent::convertToParticle
Particle * convertToParticle(const std::string &maskName="", int pdgCode=0, bool isSelfConjugated=true)
Converts ROE to Particle and adds it to StoreArray.
Definition: RestOfEvent.cc:516
Belle2::RelationVector
Class for type safe access to objects that are referred to in relations.
Definition: DataStore.h:38
Belle2::TrackFitResult::getParticleType
Const::ParticleType getParticleType() const
Getter for ParticleType of the mass hypothesis of the track fit.
Definition: TrackFitResult.h:154
Belle2::Particle::EFlavorType
EFlavorType
describes flavor type, see getFlavorType().
Definition: Particle.h:95
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::V0::getTrackFitResults
std::pair< TrackFitResult *, TrackFitResult * > getTrackFitResults() const
Get pair of the TrackFitResults, that are part of the V0 particle.
Definition: V0.h:63
Belle2::PCmsLabTransform::getBeamFourMomentum
TLorentzVector getBeamFourMomentum() const
Returns LAB four-momentum of e+e-.
Definition: PCmsLabTransform.h:65
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::RelationsInterface::getArrayIndex
int getArrayIndex() const
Returns this object's array index (in StoreArray), or -1 if not found.
Definition: RelationsObject.h:387
Belle2::KLMCluster
KLM cluster data.
Definition: KLMCluster.h:38
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::ParticleLoaderModule
Loads MDST dataobjects as Particle objects to the StoreArray<Particle> and collects them in specified...
Definition: ParticleLoaderModule.h:75
Belle2::PCmsLabTransform
Class to hold Lorentz transformations from/to CMS and boost vector.
Definition: PCmsLabTransform.h:37
Belle2::Const::ParticleType
The ParticleType class for identifying different particle types.
Definition: Const.h:284
Belle2::RelationVector::weight
float weight(int index) const
Get weight with index.
Definition: RelationVector.h:120
Belle2::Const::ChargedStable
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:465
Belle2::Track
Class that bundles various TrackFitResults.
Definition: Track.h:35
Belle2::MCParticle
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:43
Belle2::StoreArray< Particle >
Belle2::Particle::get4Vector
TLorentzVector get4Vector() const
Returns Lorentz vector.
Definition: Particle.h:464
Belle2::Particle::getECLClusterEnergy
double getECLClusterEnergy() const
Returns the energy of the ECLCluster for the particle.
Definition: Particle.cc:844
Belle2::V0::getV0Hypothesis
Const::ParticleType getV0Hypothesis() const
Get the hypothesis under which the V0 particle was created.
Definition: V0.cc:30
Belle2::StoreArray::getEntries
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:226
Belle2::TrackFitResult::getChargeSign
short getChargeSign() const
Return track charge (1 or -1).
Definition: TrackFitResult.h:160
Belle2::RelationsInterface::getRelatedFrom
FROM * getRelatedFrom(const std::string &name="", const std::string &namedRelation="") const
Get the object from which this object has a relation.
Definition: RelationsObject.h:265
Belle2::StoreObjPtr::isValid
bool isValid() const
Check whether the object was created.
Definition: StoreObjPtr.h:120