Belle II Software  release-05-01-25
MCTruthVariables.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2018-2019 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Sam Cunliffe *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <analysis/variables/MCTruthVariables.h>
12 #include <analysis/VariableManager/Manager.h>
13 #include <analysis/dataobjects/Particle.h>
14 #include <analysis/dataobjects/TauPairDecay.h>
15 #include <analysis/utility/MCMatching.h>
16 #include <analysis/utility/ReferenceFrame.h>
17 
18 #include <mdst/dataobjects/MCParticle.h>
19 #include <mdst/dataobjects/ECLCluster.h>
20 
21 #include <framework/datastore/StoreArray.h>
22 #include <framework/datastore/StoreObjPtr.h>
23 #include <framework/dataobjects/EventMetaData.h>
24 #include <framework/gearbox/Const.h>
25 #include <framework/logging/Logger.h>
26 #include <framework/core/Environment.h>
27 #include <framework/database/DBObjPtr.h>
28 #include <framework/dbobjects/BeamParameters.h>
29 
30 #include <queue>
31 
32 namespace Belle2 {
37  namespace Variable {
38 
39  double isSignal(const Particle* part)
40  {
41  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
42  if (mcparticle == nullptr)
43  return std::numeric_limits<double>::quiet_NaN();
44 
45  int status = MCMatching::getMCErrors(part, mcparticle);
46 
47  return (status == MCMatching::c_Correct) ? 1.0 : 0.0;
48  }
49 
50  double isSignalAcceptWrongFSPs(const Particle* part)
51  {
52  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
53  if (mcparticle == nullptr)
54  return std::numeric_limits<double>::quiet_NaN();
55 
56  int status = MCMatching::getMCErrors(part, mcparticle);
57  //remove the following bits
58  status &= (~MCMatching::c_MisID);
59  status &= (~MCMatching::c_AddedWrongParticle);
60 
61  return (status == MCMatching::c_Correct) ? 1.0 : 0.0;
62  }
63 
64  double isPrimarySignal(const Particle* part)
65  {
66  if (isSignal(part) > 0.5 and particleMCPrimaryParticle(part) > 0.5)
67  return 1.0;
68  else
69  return 0.0;
70  }
71 
72  double isMisidentified(const Particle* part)
73  {
74  const MCParticle* mcp = part->getRelatedTo<MCParticle>();
75  if (!mcp) return std::numeric_limits<double>::quiet_NaN();
76  int st = MCMatching::getMCErrors(part, mcp);
77  return double((st & MCMatching::c_MisID) != 0);
78  }
79 
80  double isWrongCharge(const Particle* part)
81  {
82  const MCParticle* mcp = part->getRelatedTo<MCParticle>();
83  if (!mcp) return std::numeric_limits<double>::quiet_NaN();
84  int pch = part->getCharge(),
85  mch = mcp->getCharge();
86  return double((pch != mch));
87  }
88 
89  double isCloneTrack(const Particle* particle)
90  {
91  // neutrals and composites don't make sense
92  if (!Const::chargedStableSet.contains(Const::ParticleType(abs(particle->getPDGCode()))))
93  return std::numeric_limits<double>::quiet_NaN();
94  // get mcparticle weight (mcmatch weight)
95  auto mcpww = particle->getRelatedToWithWeight<MCParticle>();
96  if (!mcpww.first) return std::numeric_limits<double>::quiet_NaN();
97  return double(mcpww.second < 0);
98  }
99 
100  double isOrHasCloneTrack(const Particle* particle)
101  {
102  // use std::queue to check daughters-- granddaughters etc recursively
103  std::queue<const Particle*> qq;
104  qq.push(particle);
105  while (!qq.empty()) {
106  auto d = qq.front(); // get daughter
107  qq.pop(); // remove the daughter from the queue
108  if (isCloneTrack(d) == 1.0) return 1.0;
109  size_t nDau = d->getNDaughters(); // number of daughters of daughters
110  for (size_t iDau = 0; iDau < nDau; iDau++)
111  qq.push(d->getDaughter(iDau));
112  }
113  return 0.0;
114  }
115 
116  double genNthMotherPDG(const Particle* part, const std::vector<double>& args)
117  {
118  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
119  if (mcparticle == nullptr)
120  return 0.0;
121 
122  unsigned int nLevels;
123  if (args.empty())
124  nLevels = 0;
125  else
126  nLevels = args[0];
127 
128  const MCParticle* curMCParticle = mcparticle;
129  for (unsigned int i = 0; i <= nLevels; i++) {
130  const MCParticle* curMCMother = curMCParticle->getMother();
131  if (curMCMother == nullptr)
132  return 0.0;
133  curMCParticle = curMCMother;
134  }
135  int m_pdg = curMCParticle->getPDG();
136  return m_pdg;
137  }
138 
139  double genNthMotherIndex(const Particle* part, const std::vector<double>& args)
140  {
141  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
142  if (mcparticle == nullptr)
143  return 0.0;
144 
145  unsigned int nLevels;
146  if (args.empty())
147  nLevels = 0;
148  else
149  nLevels = args[0];
150 
151  const MCParticle* curMCParticle = mcparticle;
152  for (unsigned int i = 0; i <= nLevels; i++) {
153  const MCParticle* curMCMother = curMCParticle->getMother();
154  if (curMCMother == nullptr)
155  return 0.0;
156  curMCParticle = curMCMother;
157  }
158  int m_id = curMCParticle->getArrayIndex();
159  return m_id;
160  }
161 
162  double genMotherPDG(const Particle* part)
163  {
164  const std::vector<double> args = {};
165  return genNthMotherPDG(part, args);
166  }
167 
168  double genMotherP(const Particle* part)
169  {
170  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
171  if (mcparticle == nullptr)
172  return std::numeric_limits<double>::quiet_NaN();
173 
174  const MCParticle* mcmother = mcparticle->getMother();
175  if (mcmother == nullptr)
176  return std::numeric_limits<double>::quiet_NaN();
177 
178  double p = mcmother->getMomentum().Mag();
179  return p;
180  }
181 
182  double genMotherIndex(const Particle* part)
183  {
184  const std::vector<double> args = {};
185  return genNthMotherIndex(part, args);
186  }
187 
188  double genParticleIndex(const Particle* part)
189  {
190  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
191  if (!mcparticle)
192  return -1.0;
193 
194  double m_ID = mcparticle->getArrayIndex();
195  return m_ID;
196  }
197 
198  double isSignalAcceptMissingNeutrino(const Particle* part)
199  {
200  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
201  if (mcparticle == nullptr)
202  return std::numeric_limits<double>::quiet_NaN();
203 
204  int status = MCMatching::getMCErrors(part, mcparticle);
205  //remove the following bits
206  status &= (~MCMatching::c_MissNeutrino);
207 
208  return (status == MCMatching::c_Correct) ? 1.0 : 0.0;
209  }
210 
211  double isSignalAcceptMissingMassive(const Particle* part)
212  {
213  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
214  if (mcparticle == nullptr)
215  return std::numeric_limits<double>::quiet_NaN();
216 
217  int status = MCMatching::getMCErrors(part, mcparticle);
218  //remove the following bits
219  status &= (~MCMatching::c_MissMassiveParticle);
220  status &= (~MCMatching::c_MissKlong);
221 
222  return (status == MCMatching::c_Correct) ? 1.0 : 0.0;
223  }
224 
225  double isSignalAcceptMissingGamma(const Particle* part)
226  {
227  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
228  if (mcparticle == nullptr)
229  return std::numeric_limits<double>::quiet_NaN();
230 
231  int status = MCMatching::getMCErrors(part, mcparticle);
232  //remove the following bits
233  status &= (~MCMatching::c_MissGamma);
234 
235  return (status == MCMatching::c_Correct) ? 1.0 : 0.0;
236  }
237 
238  double isSignalAcceptMissing(const Particle* part)
239  {
240  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
241  if (mcparticle == nullptr)
242  return std::numeric_limits<double>::quiet_NaN();
243 
244  int status = MCMatching::getMCErrors(part, mcparticle);
245  //remove the following bits
246  status &= (~MCMatching::c_MissGamma);
247  status &= (~MCMatching::c_MissMassiveParticle);
248  status &= (~MCMatching::c_MissKlong);
249  status &= (~MCMatching::c_MissNeutrino);
250 
251  return (status == MCMatching::c_Correct) ? 1.0 : 0.0;
252  }
253 
254  double isSignalAcceptBremsPhotons(const Particle* part)
255  {
256  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
257  if (mcparticle == nullptr)
258  return 0.0;
259 
260  int status = MCMatching::getMCErrors(part, mcparticle);
261  //remove the following bits
262  status &= (~MCMatching::c_AddedRecoBremsPhoton);
263 
264  return (status == MCMatching::c_Correct) ? 1.0 : 0.0;
265  }
266 
267  double particleMCMatchPDGCode(const Particle* part)
268  {
269  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
270  if (mcparticle == nullptr)
271  return std::numeric_limits<double>::quiet_NaN();
272 
273  return mcparticle->getPDG();
274  }
275 
276  double particleMCErrors(const Particle* part)
277  {
278  return MCMatching::getMCErrors(part);
279  }
280 
281  double particleNumberOfMCMatch(const Particle* particle)
282  {
283  RelationVector<MCParticle> mcRelations =
284  particle->getRelationsTo<MCParticle>();
285  return double(mcRelations.size());
286  }
287 
288  double particleMCMatchWeight(const Particle* particle)
289  {
290  auto relWithWeight = particle->getRelatedToWithWeight<MCParticle>();
291 
292  if (relWithWeight.first) {
293  return relWithWeight.second;
294  } else {
295  return std::numeric_limits<double>::quiet_NaN();
296  }
297  }
298 
299  double particleMCMatchDecayTime(const Particle* part)
300  {
301  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
302  if (mcparticle == nullptr)
303  return std::numeric_limits<double>::quiet_NaN();
304 
305  return mcparticle->getDecayTime();
306  }
307 
308  double particleMCMatchLifeTime(const Particle* part)
309  {
310  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
311  if (mcparticle == nullptr)
312  return std::numeric_limits<double>::quiet_NaN();
313 
314  return mcparticle->getLifetime();
315  }
316 
317  double particleMCMatchPX(const Particle* part)
318  {
319  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
320  if (mcparticle == nullptr)
321  return std::numeric_limits<double>::quiet_NaN();
322 
323  const auto& frame = ReferenceFrame::GetCurrent();
324  TLorentzVector mcpP4 = mcparticle->get4Vector();
325  return frame.getMomentum(mcpP4).Px();
326  }
327 
328  double particleMCMatchPY(const Particle* part)
329  {
330  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
331  if (mcparticle == nullptr)
332  return std::numeric_limits<double>::quiet_NaN();
333 
334  const auto& frame = ReferenceFrame::GetCurrent();
335  TLorentzVector mcpP4 = mcparticle->get4Vector();
336  return frame.getMomentum(mcpP4).Py();
337  }
338 
339  double particleMCMatchPZ(const Particle* part)
340  {
341  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
342  if (mcparticle == nullptr)
343  return std::numeric_limits<double>::quiet_NaN();
344 
345  const auto& frame = ReferenceFrame::GetCurrent();
346  TLorentzVector mcpP4 = mcparticle->get4Vector();
347  return frame.getMomentum(mcpP4).Pz();
348  }
349 
350  double particleMCMatchPT(const Particle* part)
351  {
352  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
353  if (mcparticle == nullptr)
354  return std::numeric_limits<double>::quiet_NaN();
355 
356  const auto& frame = ReferenceFrame::GetCurrent();
357  TLorentzVector mcpP4 = mcparticle->get4Vector();
358  return frame.getMomentum(mcpP4).Pt();
359  }
360 
361  double particleMCMatchE(const Particle* part)
362  {
363  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
364  if (mcparticle == nullptr)
365  return std::numeric_limits<double>::quiet_NaN();
366 
367  const auto& frame = ReferenceFrame::GetCurrent();
368  TLorentzVector mcpP4 = mcparticle->get4Vector();
369  return frame.getMomentum(mcpP4).E();
370  }
371 
372  double particleMCMatchP(const Particle* part)
373  {
374  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
375  if (mcparticle == nullptr)
376  return std::numeric_limits<double>::quiet_NaN();
377 
378  const auto& frame = ReferenceFrame::GetCurrent();
379  TLorentzVector mcpP4 = mcparticle->get4Vector();
380  return frame.getMomentum(mcpP4).P();
381  }
382 
383  double particleMCMatchTheta(const Particle* part)
384  {
385  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
386  if (mcparticle == nullptr)
387  return std::numeric_limits<double>::quiet_NaN();
388 
389  const auto& frame = ReferenceFrame::GetCurrent();
390  TLorentzVector mcpP4 = mcparticle->get4Vector();
391  return frame.getMomentum(mcpP4).Theta();
392  }
393 
394  double particleMCMatchPhi(const Particle* part)
395  {
396  const MCParticle* mcparticle = part->getRelatedTo<MCParticle>();
397  if (mcparticle == nullptr)
398  return std::numeric_limits<double>::quiet_NaN();
399 
400  const auto& frame = ReferenceFrame::GetCurrent();
401  TLorentzVector mcpP4 = mcparticle->get4Vector();
402  return frame.getMomentum(mcpP4).Phi();
403  }
404 
405  double particleMCRecoilMass(const Particle* part)
406  {
407  StoreArray<MCParticle> mcparticles;
408  if (mcparticles.getEntries() < 1)
409  return std::numeric_limits<double>::quiet_NaN();
410 
411  TLorentzVector pInitial = mcparticles[0]->get4Vector();
412  TLorentzVector pDaughters;
413  const std::vector<Particle*> daughters = part->getDaughters();
414  for (auto daughter : daughters) {
415  const MCParticle* mcD = daughter->getRelatedTo<MCParticle>();
416  if (mcD == nullptr)
417  return std::numeric_limits<double>::quiet_NaN();
418 
419  pDaughters += mcD->get4Vector();
420  }
421 
422  return (pInitial - pDaughters).M();
423  }
424 
425  double mcParticleSecondaryPhysicsProcess(const Particle* p)
426  {
427  const MCParticle* mcp = p->getMCParticle();
428  if (mcp) {
429  return mcp->getSecondaryPhysicsProcess();
430  } else {
431  return std::numeric_limits<double>::quiet_NaN();
432  }
433  }
434 
435  double mcParticleStatus(const Particle* p)
436  {
437  const MCParticle* mcp = p->getMCParticle();
438  if (mcp) {
439  return mcp->getStatus();
440  } else {
441  return std::numeric_limits<double>::quiet_NaN();
442  }
443  }
444 
445  double particleMCPrimaryParticle(const Particle* p)
446  {
447  const MCParticle* mcp = p->getMCParticle();
448  if (mcp) {
449  unsigned int bitmask = MCParticle::c_PrimaryParticle;
450  if (mcp->hasStatus(bitmask))
451  return 1;
452  else
453  return 0;
454  } else {
455  return std::numeric_limits<double>::quiet_NaN();
456  }
457  }
458 
459  double particleMCVirtualParticle(const Particle* p)
460  {
461  const MCParticle* mcp = p->getMCParticle();
462  if (mcp) {
463  unsigned int bitmask = MCParticle::c_IsVirtual;
464  if (mcp->hasStatus(bitmask))
465  return 1;
466  else
467  return 0;
468  } else {
469  return std::numeric_limits<double>::quiet_NaN();
470  }
471  }
472 
473  double particleMCInitialParticle(const Particle* p)
474  {
475  const MCParticle* mcp = p->getMCParticle();
476  if (mcp) {
477  unsigned int bitmask = MCParticle::c_Initial;
478  if (mcp->hasStatus(bitmask))
479  return 1;
480  else
481  return 0;
482  } else {
483  return std::numeric_limits<double>::quiet_NaN();
484  }
485  }
486 
487  double particleMCISRParticle(const Particle* p)
488  {
489  const MCParticle* mcp = p->getMCParticle();
490  if (mcp) {
491  unsigned int bitmask = MCParticle::c_IsISRPhoton;
492  if (mcp->hasStatus(bitmask))
493  return 1;
494  else
495  return 0;
496  } else {
497  return std::numeric_limits<double>::quiet_NaN();
498  }
499  }
500 
501  double particleMCFSRParticle(const Particle* p)
502  {
503  const MCParticle* mcp = p->getMCParticle();
504  if (mcp) {
505  unsigned int bitmask = MCParticle::c_IsFSRPhoton;
506  if (mcp->hasStatus(bitmask))
507  return 1;
508  else
509  return 0;
510  } else {
511  return std::numeric_limits<double>::quiet_NaN();
512  }
513  }
514 
515  double particleMCPhotosParticle(const Particle* p)
516  {
517  const MCParticle* mcp = p->getMCParticle();
518  if (mcp) {
519  unsigned int bitmask = MCParticle::c_IsPHOTOSPhoton;
520  if (mcp->hasStatus(bitmask))
521  return 1;
522  else
523  return 0;
524  } else {
525  return std::numeric_limits<double>::quiet_NaN();
526  }
527  }
528 
529  double generatorEventWeight(const Particle*)
530  {
531  StoreObjPtr<EventMetaData> evtMetaData;
532  if (!evtMetaData)
533  return std::numeric_limits<double>::quiet_NaN();
534  return evtMetaData->getGeneratedWeight();
535  }
536 
537  int tauPlusMcMode(const Particle*)
538  {
539  StoreObjPtr<TauPairDecay> tauDecay;
540  if (!tauDecay) {
541  B2WARNING("Cannot find tau decay ID, did you forget to run TauDecayMarkerModule?");
542  return std::numeric_limits<int>::quiet_NaN();
543  }
544  int tauPlusId = tauDecay->getTauPlusIdMode();
545  return tauPlusId;
546  }
547 
548  int tauMinusMcMode(const Particle*)
549  {
550  StoreObjPtr<TauPairDecay> tauDecay;
551  if (!tauDecay) {
552  B2WARNING("Cannot find tau decay ID, did you forget to run TauDecayMarkerModule?");
553  return std::numeric_limits<int>::quiet_NaN();
554  }
555  int tauMinusId = tauDecay->getTauMinusIdMode();
556  return tauMinusId;
557  }
558 
559  int tauPlusMcProng(const Particle*)
560  {
561  StoreObjPtr<TauPairDecay> tauDecay;
562  if (!tauDecay) {
563  B2WARNING("Cannot find tau prong, did you forget to run TauDecayMarkerModule?");
564  return std::numeric_limits<int>::quiet_NaN();
565  }
566  int tauPlusMcProng = tauDecay->getTauPlusMcProng();
567  return tauPlusMcProng;
568  }
569 
570  int tauMinusMcProng(const Particle*)
571  {
572  StoreObjPtr<TauPairDecay> tauDecay;
573  if (!tauDecay) {
574  B2WARNING("Cannot find tau prong, did you forget to run TauDecayMarkerModule?");
575  return std::numeric_limits<int>::quiet_NaN();
576  }
577  int tauMinusMcProng = tauDecay->getTauMinusMcProng();
578  return tauMinusMcProng;
579  }
580 
581 
582 
583  double isReconstructible(const Particle* p)
584  {
585  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
586  return -1.0;
587  const MCParticle* mcp = p->getRelated<MCParticle>();
588  if (!mcp)
589  return std::numeric_limits<float>::quiet_NaN();
590 
591  // If charged: make sure it was seen in the SVD.
592  // If neutral: make sure it was seen in the ECL.
593  if (abs(mcp->getCharge()) > 0)
594  return seenInSVD(p);
595  else
596  return seenInECL(p);
597  }
598 
599  double seenInPXD(const Particle* p)
600  {
601  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
602  return -1.0;
603  const MCParticle* mcp = p->getRelated<MCParticle>();
604  if (!mcp)
605  return std::numeric_limits<float>::quiet_NaN();
606  return (double)mcp->hasSeenInDetector(Const::PXD);
607  }
608 
609  double seenInSVD(const Particle* p)
610  {
611  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
612  return -1.0;
613  const MCParticle* mcp = p->getRelated<MCParticle>();
614  if (!mcp)
615  return std::numeric_limits<float>::quiet_NaN();
616  return (double)mcp->hasSeenInDetector(Const::SVD);
617  }
618 
619  double seenInCDC(const Particle* p)
620  {
621  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
622  return -1.0;
623  const MCParticle* mcp = p->getRelated<MCParticle>();
624  if (!mcp)
625  return std::numeric_limits<float>::quiet_NaN();
626  return (double)mcp->hasSeenInDetector(Const::CDC);
627  }
628 
629  double seenInTOP(const Particle* p)
630  {
631  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
632  return -1.0;
633  const MCParticle* mcp = p->getRelated<MCParticle>();
634  if (!mcp)
635  return std::numeric_limits<float>::quiet_NaN();
636  return (double)mcp->hasSeenInDetector(Const::TOP);
637  }
638 
639  double seenInECL(const Particle* p)
640  {
641  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
642  return -1.0;
643  const MCParticle* mcp = p->getRelated<MCParticle>();
644  if (!mcp)
645  return std::numeric_limits<float>::quiet_NaN();
646  return (double)mcp->hasSeenInDetector(Const::ECL);
647  }
648 
649  double seenInARICH(const Particle* p)
650  {
651  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
652  return -1.0;
653  const MCParticle* mcp = p->getRelated<MCParticle>();
654  if (!mcp)
655  return std::numeric_limits<float>::quiet_NaN();
656  return (double)mcp->hasSeenInDetector(Const::ARICH);
657  }
658 
659  double seenInKLM(const Particle* p)
660  {
661  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
662  return -1.0;
663  const MCParticle* mcp = p->getRelated<MCParticle>();
664  if (!mcp)
665  return std::numeric_limits<float>::quiet_NaN();
666  return (double)mcp->hasSeenInDetector(Const::KLM);
667  }
668 
669  int genNStepsToDaughter(const Particle* p, const std::vector<double>& arguments)
670  {
671  if (arguments.size() != 1)
672  B2FATAL("Wrong number of arguments for genNStepsToDaughter");
673 
674  const MCParticle* mcp = p->getRelated<MCParticle>();
675  if (!mcp) {
676  B2WARNING("No MCParticle is associated to the particle");
677  return std::numeric_limits<int>::quiet_NaN();
678  }
679 
680  int nChildren = p->getNDaughters();
681  if (arguments[0] >= nChildren) {
682  return std::numeric_limits<int>::quiet_NaN();
683  }
684 
685  const Particle* daugP = p->getDaughter(arguments[0]);
686  const MCParticle* daugMCP = daugP->getRelated<MCParticle>();
687  if (!daugMCP) {
688  // This is a strange case.
689  // The particle, p, has the related MC particle, but i-th daughter does not have the related MC Particle.
690  B2WARNING("No MCParticle is associated to the i-th daughter");
691  return std::numeric_limits<int>::quiet_NaN();
692  }
693 
694  if (nChildren == 1) {
695  return 1;
696  } else {
697  int motherIndex = mcp->getIndex();
698 
699  std::vector<int> genMothers;
700  MCMatching::fillGenMothers(daugMCP, genMothers);
701  auto match = std::find(genMothers.begin(), genMothers.end(), motherIndex);
702 
703  return match - genMothers.begin();
704  }
705  }
706 
707  int genNMissingDaughter(const Particle* p, const std::vector<double>& arguments)
708  {
709  if (arguments.size() < 1)
710  B2FATAL("Wrong number of arguments for genNMissingDaughter");
711 
712  const std::vector<int> PDGcodes(arguments.begin(), arguments.end());
713 
714  const MCParticle* mcp = p->getRelated<MCParticle>();
715  if (!mcp) {
716  B2WARNING("No MCParticle is associated to the particle");
717  return std::numeric_limits<int>::quiet_NaN();
718  }
719 
720  return MCMatching::countMissingParticle(p, mcp, PDGcodes);
721  }
722 
723  double getHEREnergy(const Particle*)
724  {
725  static DBObjPtr<BeamParameters> beamParamsDB;
726  return (beamParamsDB->getHER()).E();
727  }
728 
729  double getLEREnergy(const Particle*)
730  {
731  static DBObjPtr<BeamParameters> beamParamsDB;
732  return (beamParamsDB->getLER()).E();
733  }
734 
735  double getCrossingAngle(const Particle*)
736  {
737  static DBObjPtr<BeamParameters> beamParamsDB;
738  return (beamParamsDB->getHER()).Vect().Angle(-1.0 * (beamParamsDB->getLER()).Vect());
739  }
740 
741  double particleClusterMatchWeight(const Particle* particle)
742  {
743  /* Get the weight of the *cluster* mc match for the mcparticle matched to
744  * this particle.
745  *
746  * Note that for track-based particles this is different from the mc match
747  * of the particle (which it inherits from the mc match of the track)
748  */
749  const MCParticle* matchedToParticle = particle->getMCParticle();
750  if (!matchedToParticle) return std::numeric_limits<float>::quiet_NaN();
751  int matchedToIndex = matchedToParticle->getArrayIndex();
752 
753  const ECLCluster* cluster = particle->getECLCluster();
754  if (!cluster) return std::numeric_limits<float>::quiet_NaN();
755 
756  auto mcps = cluster->getRelationsTo<MCParticle>();
757  if (mcps.size() == 0) return std::numeric_limits<float>::quiet_NaN();
758 
759  for (unsigned int i = 0; i < mcps.size(); ++i)
760  if (mcps[i]->getArrayIndex() == matchedToIndex)
761  return mcps.weight(i);
762 
763  return -1.0;
764  }
765 
766  double particleClusterBestMCMatchWeight(const Particle* particle)
767  {
768  /* Get the weight of the best mc match of the cluster associated to
769  * this particle.
770  *
771  * Note for electrons (or any track-based particle) this may not be
772  * the same thing as the mc match of the particle (which is taken
773  * from the track).
774  *
775  * For photons (or any ECL-based particle) this will be the same as the
776  * mcMatchWeight
777  */
778  const ECLCluster* cluster = particle->getECLCluster();
779  if (!cluster) return std::numeric_limits<float>::quiet_NaN();
780 
781  /* loop over all mcparticles related to this cluster, find the largest
782  * weight by std::sort-ing the doubles
783  */
784  auto mcps = cluster->getRelationsTo<MCParticle>();
785  if (mcps.size() == 0) return std::numeric_limits<float>::quiet_NaN();
786 
787  std::vector<double> weights;
788  for (unsigned int i = 0; i < mcps.size(); ++i)
789  weights.emplace_back(mcps.weight(i));
790 
791  // sort descending by weight
792  std::sort(weights.begin(), weights.end());
793  std::reverse(weights.begin(), weights.end());
794  return weights[0];
795  }
796 
797  double particleClusterBestMCPDGCode(const Particle* particle)
798  {
799  /* Get the PDG code of the best mc match of the cluster associated to this
800  * particle.
801  *
802  * Note for electrons (or any track-based particle) this may not be the
803  * same thing as the mc match of the particle (which is taken from the track).
804  *
805  * For photons (or any ECL-based particle) this will be the same as the mcPDG
806  */
807  const ECLCluster* cluster = particle->getECLCluster();
808  if (!cluster) return std::numeric_limits<float>::quiet_NaN();
809 
810  auto mcps = cluster->getRelationsTo<MCParticle>();
811  if (mcps.size() == 0) return std::numeric_limits<float>::quiet_NaN();
812 
813  std::vector<std::pair<double, int>> weightsAndIndices;
814  for (unsigned int i = 0; i < mcps.size(); ++i)
815  weightsAndIndices.emplace_back(mcps.weight(i), i);
816 
817  // sort descending by weight
818  std::sort(
819  weightsAndIndices.begin(), weightsAndIndices.end(),
820  [](const std::pair<double, int>& l, const std::pair<double, int>& r) {
821  return l.first > r.first;
822  });
823  return mcps.object(weightsAndIndices[0].second)->getPDG();
824  }
825 
826  double isMC(const Particle*)
827  {
828  return Environment::Instance().isMC();
829  }
830 
831  VARIABLE_GROUP("MC matching and MC truth");
832  REGISTER_VARIABLE("isSignal", isSignal,
833  "1.0 if Particle is correctly reconstructed (SIGNAL), 0.0 otherwise. \n"
834  "It behaves according to DecayStringGrammar.");
835  REGISTER_VARIABLE("isSignalAcceptWrongFSPs", isSignalAcceptWrongFSPs,
836  "1.0 if Particle is almost correctly reconstructed (SIGNAL), 0.0 otherwise.\n"
837  "Misidentification of charged FSP is allowed.");
838  REGISTER_VARIABLE("isPrimarySignal", isPrimarySignal,
839  "1.0 if Particle is correctly reconstructed (SIGNAL) and primary, 0.0 otherwise");
840  REGISTER_VARIABLE("isSignalAcceptBremsPhotons", isSignalAcceptBremsPhotons,
841  "1.0 if Particle is correctly reconstructed (SIGNAL), 0.0 otherwise.\n"
842  "Particles with gamma daughters attached through the bremsstrahlung recovery modules are allowed.");
843  REGISTER_VARIABLE("genMotherPDG", genMotherPDG,
844  "Check the PDG code of a particles MC mother particle");
845  REGISTER_VARIABLE("genMotherPDG(i)", genNthMotherPDG,
846  "Check the PDG code of a particles n-th MC mother particle by providing an argument. 0 is first mother, 1 is grandmother etc. :noindex:");
847 
848  REGISTER_VARIABLE("genMotherID", genMotherIndex,
849  "Check the array index of a particles generated mother");
850  REGISTER_VARIABLE("genMotherID(i)", genNthMotherIndex,
851  "Check the array index of a particle n-th MC mother particle by providing an argument. 0 is first mother, 1 is grandmother etc. :noindex:");
852  // genMotherPDG and genMotherID are overloaded (each are two C++ functions
853  // sharing one variable name) so one of the two needs to be made the indexed
854  // variable in sphinx
855 
856  REGISTER_VARIABLE("genMotherP", genMotherP,
857  "Generated momentum of a particles MC mother particle");
858  REGISTER_VARIABLE("genParticleID", genParticleIndex,
859  "Check the array index of a particle's related MCParticle");
860  REGISTER_VARIABLE("isSignalAcceptMissingNeutrino",
861  isSignalAcceptMissingNeutrino,
862  "same as isSignal, but also accept missing neutrino");
863  REGISTER_VARIABLE("isSignalAcceptMissingMassive",
864  isSignalAcceptMissingMassive,
865  "same as isSignal, but also accept missing massive particle");
866  REGISTER_VARIABLE("isSignalAcceptMissingGamma",
867  isSignalAcceptMissingGamma,
868  "same as isSignal, but also accept missing gamma, such as B -> K* gamma, pi0 -> gamma gamma");
869  REGISTER_VARIABLE("isSignalAcceptMissing",
870  isSignalAcceptMissing,
871  "same as isSignal, but also accept missing particle");
872  REGISTER_VARIABLE("isMisidentified", isMisidentified,
873  "return 1 if the particle is misidentified: one or more of the final state particles have the wrong PDG code assignment (including wrong charge), 0 in all other cases.");
874  REGISTER_VARIABLE("isWrongCharge", isWrongCharge,
875  "return 1 if the charge of the particle is wrongly assigned, 0 in all other cases");
876  REGISTER_VARIABLE("isCloneTrack", isCloneTrack,
877  "Return 1 if the charged final state particle comes from a cloned track, 0 if not a clone. Returns NAN if neutral, composite, or MCParticle not found (like for data or if not MCMatched)");
878  REGISTER_VARIABLE("isOrHasCloneTrack", isOrHasCloneTrack,
879  "Return 1 if the particle is a clone track or has a clone track as a daughter, 0 otherwise.");
880  REGISTER_VARIABLE("mcPDG", particleMCMatchPDGCode,
881  "The PDG code of matched MCParticle, 0 if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
882  REGISTER_VARIABLE("mcErrors", particleMCErrors,
883  "The bit pattern indicating the quality of MC match (see MCMatching::MCErrorFlags)");
884  REGISTER_VARIABLE("mcMatchWeight", particleMCMatchWeight,
885  "The weight of the Particle -> MCParticle relation (only for the first Relation = largest weight).");
886  REGISTER_VARIABLE("nMCMatches", particleNumberOfMCMatch,
887  "The number of relations of this Particle to MCParticle.");
888  REGISTER_VARIABLE("mcDecayTime", particleMCMatchDecayTime,
889  "The decay time of matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
890  REGISTER_VARIABLE("mcLifeTime", particleMCMatchLifeTime,
891  "The life time of matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
892  REGISTER_VARIABLE("mcPX", particleMCMatchPX,
893  "The px of matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
894  REGISTER_VARIABLE("mcPY", particleMCMatchPY,
895  "The py of matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
896  REGISTER_VARIABLE("mcPZ", particleMCMatchPZ,
897  "The pz of matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
898  REGISTER_VARIABLE("mcPT", particleMCMatchPT,
899  "The pt of matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
900  REGISTER_VARIABLE("mcE", particleMCMatchE,
901  "The energy of matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
902  REGISTER_VARIABLE("mcP", particleMCMatchP,
903  "The total momentum of matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
904  REGISTER_VARIABLE("mcPhi", particleMCMatchPhi,
905  "The phi of matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
906  REGISTER_VARIABLE("mcTheta", particleMCMatchTheta,
907  "The theta of matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
908  REGISTER_VARIABLE("mcRecoilMass", particleMCRecoilMass,
909  "The mass recoiling against the particles attached as particle's daughters calculated using MC truth values.");
910 
911 
912  REGISTER_VARIABLE("mcSecPhysProc", mcParticleSecondaryPhysicsProcess,
913  "Returns the secondary physics process flag.");
914  REGISTER_VARIABLE("mcParticleStatus", mcParticleStatus,
915  "Returns status bits of related MCParticle or NaN if MCParticle relation is not set.");
916  REGISTER_VARIABLE("mcPrimary", particleMCPrimaryParticle,
917  "Returns 1 if Particle is related to primary MCParticle, 0 if Particle is related to non - primary MCParticle, "
918  "NaN if Particle is not related to MCParticle.");
919  REGISTER_VARIABLE("mcVirtual", particleMCVirtualParticle,
920  "Returns 1 if Particle is related to virtual MCParticle, 0 if Particle is related to non - virtual MCParticle, "
921  "NaN if Particle is not related to MCParticle.")
922  REGISTER_VARIABLE("mcInitial", particleMCInitialParticle,
923  "Returns 1 if Particle is related to initial MCParticle, 0 if Particle is related to non - initial MCParticle, "
924  "NaN if Particle is not related to MCParticle.")
925  REGISTER_VARIABLE("mcISR", particleMCISRParticle,
926  "Returns 1 if Particle is related to ISR MCParticle, 0 if Particle is related to non - ISR MCParticle, "
927  "NaN if Particle is not related to MCParticle.")
928  REGISTER_VARIABLE("mcFSR", particleMCFSRParticle,
929  "Returns 1 if Particle is related to FSR MCParticle, 0 if Particle is related to non - FSR MCParticle ,"
930  "NaN if Particle is not related to MCParticle.")
931  REGISTER_VARIABLE("mcPhotos", particleMCPhotosParticle,
932  "Returns 1 if Particle is related to Photos MCParticle, 0 if Particle is related to non - Photos MCParticle, "
933  "NaN if Particle is not related to MCParticle.")
934  REGISTER_VARIABLE("generatorEventWeight", generatorEventWeight,
935  "[Eventbased] Returns the event weight produced by the event generator")
936 
937  REGISTER_VARIABLE("genNStepsToDaughter(i)", genNStepsToDaughter,
938  "Returns number of steps to i-th daughter from the particle at generator level. "
939  "NaN if no MCParticle is associated to the particle or i-th daughter. "
940  "NaN if i-th daughter does not exist.");
941  REGISTER_VARIABLE("genNMissingDaughter(PDG)", genNMissingDaughter,
942  "Returns the number of missing daughters having assigned PDG codes. "
943  "NaN if no MCParticle is associated to the particle.")
944  REGISTER_VARIABLE("Eher", getHEREnergy, R"DOC(
945 [Eventbased] The nominal HER energy used by the generator.
946 
947 .. warning:: This variable does not make sense for data.
948 )DOC");
949  REGISTER_VARIABLE("Eler", getLEREnergy, R"DOC(
950 [Eventbased] The nominal LER energy used by the generator.
951 
952 .. warning:: This variable does not make sense for data.
953 )DOC");
954  REGISTER_VARIABLE("XAngle", getCrossingAngle, R"DOC(
955 [Eventbased] The nominal beam crossing angle from generator level beam kinematics.
956 
957 .. warning:: This variable does not make sense for data.
958 )DOC");
959 
960  VARIABLE_GROUP("Generated tau decay information");
961  REGISTER_VARIABLE("tauPlusMCMode", tauPlusMcMode,
962  "Decay ID for the positive tau lepton in a tau pair generated event.")
963  REGISTER_VARIABLE("tauMinusMCMode", tauMinusMcMode,
964  "Decay ID for the negative tau lepton in a tau pair generated event.")
965  REGISTER_VARIABLE("tauPlusMCProng", tauPlusMcProng,
966  "Prong for the positive tau lepton in a tau pair generated event.")
967  REGISTER_VARIABLE("tauMinusMCProng", tauMinusMcProng,
968  "Prong for the negative tau lepton in a tau pair generated event.")
969 
970  VARIABLE_GROUP("MC particle seen in subdetectors");
971  REGISTER_VARIABLE("isReconstructible", isReconstructible,
972  "checks charged particles were seen in the SVD and neutrals in the ECL, returns 1.0 if so, 0.0 if not, -1.0 for composite particles. Useful for generator studies, not for reconstructed particles.");
973  REGISTER_VARIABLE("seenInPXD", seenInPXD,
974  "returns 1.0 if the MC particle was seen in the PXD, 0.0 if not, -1.0 for composite particles. Useful for generator studies, not for reconstructed particles.");
975  REGISTER_VARIABLE("seenInSVD", seenInSVD,
976  "returns 1.0 if the MC particle was seen in the SVD, 0.0 if not, -1.0 for composite particles. Useful for generator studies, not for reconstructed particles.");
977  REGISTER_VARIABLE("seenInCDC", seenInCDC,
978  "returns 1.0 if the MC particle was seen in the CDC, 0.0 if not, -1.0 for composite particles. Useful for generator studies, not for reconstructed particles.");
979  REGISTER_VARIABLE("seenInTOP", seenInTOP,
980  "returns 1.0 if the MC particle was seen in the TOP, 0.0 if not, -1.0 for composite particles. Useful for generator studies, not for reconstructed particles.");
981  REGISTER_VARIABLE("seenInECL", seenInECL,
982  "returns 1.0 if the MC particle was seen in the ECL, 0.0 if not, -1.0 for composite particles. Useful for generator studies, not for reconstructed particles.");
983  REGISTER_VARIABLE("seenInARICH", seenInARICH,
984  "returns 1.0 if the MC particle was seen in the ARICH, 0.0 if not, -1.0 for composite particles. Useful for generator studies, not for reconstructed particles.");
985  REGISTER_VARIABLE("seenInKLM", seenInKLM,
986  "returns 1.0 if the MC particle was seen in the KLM, 0.0 if not, -1.0 for composite particles. Useful for generator studies, not for reconstructed particles.");
987 
988  VARIABLE_GROUP("MC Matching for ECLClusters");
989  REGISTER_VARIABLE("clusterMCMatchWeight", particleClusterMatchWeight,
990  "Returns the weight of the ECLCluster -> MCParticle relation for the MCParticle matched to the particle. "
991  "Returns NaN if: no cluster is related to the particle, the particle is not MC matched, or if there are no mcmatches for the cluster. "
992  "Returns -1 if the cluster *was* matched to particles, but not the match of the particle provided.");
993  REGISTER_VARIABLE("clusterBestMCMatchWeight", particleClusterBestMCMatchWeight,
994  "returns the weight of the ECLCluster -> MCParticle relation for the relation with the largest weight.");
995  REGISTER_VARIABLE("clusterBestMCPDG", particleClusterBestMCPDGCode,
996  "returns the PDG code of the MCParticle for the ECLCluster -> MCParticle relation with the largest weight.");
997  REGISTER_VARIABLE("isMC", isMC,
998  "[Eventbased] Returns 1 if run on MC and 0 for data.");
999 
1000  }
1002 }
Belle2::MCMatching::countMissingParticle
static int countMissingParticle(const Belle2::Particle *particle, const Belle2::MCParticle *mcParticle, const std::vector< int > &daughterPDG)
Count the number of missing daughters of the 'particle'.
Definition: MCMatching.cc:561
Belle2::MCParticle::c_IsPHOTOSPhoton
@ c_IsPHOTOSPhoton
bit 8: Particle is an radiative photon from PHOTOS
Definition: MCParticle.h:74
Belle2::MCParticle::c_IsFSRPhoton
@ c_IsFSRPhoton
bit 7: Particle is from finial state radiation
Definition: MCParticle.h:72
Belle2::MCParticle::c_IsVirtual
@ c_IsVirtual
bit 4: Particle is virtual and not going to Geant4.
Definition: MCParticle.h:66
Belle2::MCParticle::c_IsISRPhoton
@ c_IsISRPhoton
bit 6: Particle is from initial state radiation
Definition: MCParticle.h:70
Belle2::Const::chargedStableSet
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:494
Belle2::RelationsInterface::getRelated
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or from which this object has a relation.
Definition: RelationsObject.h:280
Belle2::Environment::isMC
bool isMC() const
Do we have generated, not real data?
Definition: Environment.cc:57
Belle2::MCMatching::fillGenMothers
static void fillGenMothers(const Belle2::MCParticle *mcP, std::vector< int > &genMCPMothers)
Fills vector with array (1-based) indices of all generator ancestors of given MCParticle.
Definition: MCMatching.cc:64
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::MCParticle::c_Initial
@ c_Initial
bit 5: Particle is initial such as e+ or e- and not going to Geant4
Definition: MCParticle.h:68
Belle2::MCMatching::c_MisID
@ c_MisID
One of the charged final state particles is mis-identified.
Definition: MCMatching.h:54
Belle2::RelationsInterface::getArrayIndex
int getArrayIndex() const
Returns this object's array index (in StoreArray), or -1 if not found.
Definition: RelationsObject.h:387
Belle2::ReferenceFrame::GetCurrent
static const ReferenceFrame & GetCurrent()
Get current rest frame.
Definition: ReferenceFrame.cc:28
Belle2::Environment::Instance
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:31
Belle2::MCMatching::getMCErrors
static int getMCErrors(const Belle2::Particle *particle, const Belle2::MCParticle *mcParticle=nullptr)
Returns quality indicator of the match as a bit pattern where the individual bits indicate the the ty...
Definition: MCMatching.cc:282
Belle2::MCParticle::c_PrimaryParticle
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Definition: MCParticle.h:58
Belle2::MCMatching::c_Correct
@ c_Correct
This Particle and all its daughters are perfectly reconstructed.
Definition: MCMatching.h:46