Belle II Software  light-2403-persian
MCTruthVariables.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 header.
10 #include <analysis/variables/MCTruthVariables.h>
11 
12 // include VariableManager
13 #include <analysis/VariableManager/Manager.h>
14 
15 #include <analysis/dataobjects/Particle.h>
16 #include <analysis/dataobjects/TauPairDecay.h>
17 #include <analysis/utility/MCMatching.h>
18 #include <analysis/utility/ReferenceFrame.h>
19 #include <analysis/utility/ValueIndexPairSorting.h>
20 
21 #include <mdst/dataobjects/MCParticle.h>
22 #include <mdst/dataobjects/ECLCluster.h>
23 #include <mdst/dataobjects/Track.h>
24 
25 
26 #include <framework/datastore/StoreArray.h>
27 #include <framework/datastore/StoreObjPtr.h>
28 #include <framework/dataobjects/EventMetaData.h>
29 #include <framework/gearbox/Const.h>
30 #include <framework/logging/Logger.h>
31 #include <framework/database/DBObjPtr.h>
32 #include <framework/dbobjects/BeamParameters.h>
33 
34 #include <queue>
35 
36 namespace Belle2 {
41  namespace Variable {
42 
43  double isSignal(const Particle* part)
44  {
45  const MCParticle* mcparticle = part->getMCParticle();
46  if (!mcparticle) return Const::doubleNaN;
47 
48  int status = MCMatching::getMCErrors(part, mcparticle);
49  return (status == MCMatching::c_Correct);
50  }
51 
52  double isSignalAcceptWrongFSPs(const Particle* part)
53  {
54  const MCParticle* mcparticle = part->getMCParticle();
55  if (!mcparticle) return Const::doubleNaN;
56 
57  int status = MCMatching::getMCErrors(part, mcparticle);
58  //remove the following bits
59  status &= (~MCMatching::c_MisID);
60  status &= (~MCMatching::c_AddedWrongParticle);
61 
62  return (status == MCMatching::c_Correct);
63  }
64 
65  double isPrimarySignal(const Particle* part)
66  {
67  return (isSignal(part) > 0.5 and particleMCPrimaryParticle(part) > 0.5);
68  }
69 
70  double isMisidentified(const Particle* part)
71  {
72  const MCParticle* mcp = part->getMCParticle();
73  if (!mcp) return Const::doubleNaN;
74  int st = MCMatching::getMCErrors(part, mcp);
75  return ((st & MCMatching::c_MisID) != 0);
76  }
77 
78  double isWrongCharge(const Particle* part)
79  {
80  const MCParticle* mcp = part->getMCParticle();
81  if (!mcp) return Const::doubleNaN;
82  return (part->getCharge() != mcp->getCharge());
83  }
84 
85  double isCloneTrack(const Particle* particle)
86  {
87  // neutrals and composites don't make sense
88  if (!Const::chargedStableSet.contains(Const::ParticleType(abs(particle->getPDGCode()))))
89  return Const::doubleNaN;
90  // get mcparticle weight (mcmatch weight)
91  const auto mcpww = particle->getRelatedToWithWeight<MCParticle>();
92  if (!mcpww.first) return Const::doubleNaN;
93  return (mcpww.second < 0);
94  }
95 
96  double isOrHasCloneTrack(const Particle* particle)
97  {
98  // use std::queue to check daughters-- granddaughters etc recursively
99  std::queue<const Particle*> qq;
100  qq.push(particle);
101  while (!qq.empty()) {
102  const auto d = qq.front(); // get daughter
103  qq.pop(); // remove the daughter from the queue
104  if (isCloneTrack(d) == 1.0) return 1.0;
105  size_t nDau = d->getNDaughters(); // number of daughters of daughters
106  for (size_t iDau = 0; iDau < nDau; ++iDau)
107  qq.push(d->getDaughter(iDau));
108  }
109  return 0.0;
110  }
111 
112  double genNthMotherPDG(const Particle* part, const std::vector<double>& args)
113  {
114  const MCParticle* mcparticle = part->getMCParticle();
115  if (!mcparticle) return 0.0;
116 
117  unsigned int nLevels = args.empty() ? 0 : args[0];
118 
119  const MCParticle* curMCParticle = mcparticle;
120  for (unsigned int i = 0; i <= nLevels; ++i) {
121  const MCParticle* curMCMother = curMCParticle->getMother();
122  if (!curMCMother) return 0.0;
123  curMCParticle = curMCMother;
124  }
125  return curMCParticle->getPDG();
126  }
127 
128  double genNthMotherIndex(const Particle* part, const std::vector<double>& args)
129  {
130  const MCParticle* mcparticle = part->getMCParticle();
131  if (!mcparticle) return 0.0;
132 
133  unsigned int nLevels = args.empty() ? 0 : args[0];
134 
135  const MCParticle* curMCParticle = mcparticle;
136  for (unsigned int i = 0; i <= nLevels; ++i) {
137  const MCParticle* curMCMother = curMCParticle->getMother();
138  if (!curMCMother) return 0.0;
139  curMCParticle = curMCMother;
140  }
141  return curMCParticle->getArrayIndex();
142  }
143 
144  double genQ2PmPd(const Particle* part, const std::vector<double>& daughter_indices)
145  {
146  const MCParticle* mcparticle = part->getMCParticle();
147  if (!mcparticle) return Const::doubleNaN;
148 
149  auto daughters = mcparticle->getDaughters();
150 
151  ROOT::Math::PxPyPzEVector p4Daughters;
152  for (auto& double_daughter : daughter_indices) {
153  unsigned long daughter = std::lround(double_daughter);
154  if (daughter >= daughters.size()) return Const::doubleNaN;
155 
156  p4Daughters += daughters[daughter]->get4Vector();
157  }
158  auto p4Mother = mcparticle->get4Vector();
159  return (p4Mother - p4Daughters).mag2();
160  }
161 
162  double genMotherPDG(const Particle* part)
163  {
164  return genNthMotherPDG(part, {});
165  }
166 
167  double genMotherP(const Particle* part)
168  {
169  const MCParticle* mcparticle = part->getMCParticle();
170  if (!mcparticle) return Const::doubleNaN;
171 
172  const MCParticle* mcmother = mcparticle->getMother();
173  if (!mcmother) return Const::doubleNaN;
174 
175  return mcmother->getMomentum().R();
176  }
177 
178  double genMotherIndex(const Particle* part)
179  {
180  return genNthMotherIndex(part, {});
181  }
182 
183  double genParticleIndex(const Particle* part)
184  {
185  const MCParticle* mcparticle = part->getMCParticle();
186  if (!mcparticle) return Const::doubleNaN;
187  return mcparticle->getArrayIndex();
188  }
189 
190  double isSignalAcceptMissingNeutrino(const Particle* part)
191  {
192  const MCParticle* mcparticle = part->getMCParticle();
193  if (!mcparticle) return Const::doubleNaN;
194 
195  int status = MCMatching::getMCErrors(part, mcparticle);
196  //remove the following bits
197  status &= (~MCMatching::c_MissNeutrino);
198 
199  return (status == MCMatching::c_Correct);
200  }
201 
202  double isSignalAcceptMissingMassive(const Particle* part)
203  {
204  const MCParticle* mcparticle = part->getMCParticle();
205  if (!mcparticle) return Const::doubleNaN;
206 
207  int status = MCMatching::getMCErrors(part, mcparticle);
208  //remove the following bits
209  status &= (~MCMatching::c_MissMassiveParticle);
210  status &= (~MCMatching::c_MissKlong);
211 
212  return (status == MCMatching::c_Correct);
213  }
214 
215  double isSignalAcceptMissingGamma(const Particle* part)
216  {
217  const MCParticle* mcparticle = part->getMCParticle();
218  if (!mcparticle) return Const::doubleNaN;
219 
220  int status = MCMatching::getMCErrors(part, mcparticle);
221  //remove the following bits
222  status &= (~MCMatching::c_MissGamma);
223 
224  return (status == MCMatching::c_Correct);
225  }
226 
227  double isSignalAcceptMissing(const Particle* part)
228  {
229  const MCParticle* mcparticle = part->getMCParticle();
230  if (!mcparticle) return Const::doubleNaN;
231 
232  int status = MCMatching::getMCErrors(part, mcparticle);
233  //remove the following bits
234  status &= (~MCMatching::c_MissGamma);
235  status &= (~MCMatching::c_MissMassiveParticle);
236  status &= (~MCMatching::c_MissKlong);
237  status &= (~MCMatching::c_MissNeutrino);
238 
239  return (status == MCMatching::c_Correct);
240  }
241 
242  double isSignalAcceptBremsPhotons(const Particle* part)
243  {
244  const MCParticle* mcparticle = part->getMCParticle();
245  if (!mcparticle) return Const::doubleNaN;
246 
247  int status = MCMatching::getMCErrors(part, mcparticle);
248  //remove the following bits
249  status &= (~MCMatching::c_AddedRecoBremsPhoton);
250 
251  return (status == MCMatching::c_Correct);
252  }
253 
254  double particleMCMatchPDGCode(const Particle* part)
255  {
256  const MCParticle* mcparticle = part->getMCParticle();
257  if (!mcparticle) return Const::doubleNaN;
258  return mcparticle->getPDG();
259  }
260 
261  double particleMCErrors(const Particle* part)
262  {
263  return MCMatching::getMCErrors(part);
264  }
265 
266  double particleNumberOfMCMatch(const Particle* particle)
267  {
268  RelationVector<MCParticle> mcRelations = particle->getRelationsTo<MCParticle>();
269  return (mcRelations.size());
270  }
271 
272  double particleMCMatchWeight(const Particle* particle)
273  {
274  auto relWithWeight = particle->getRelatedToWithWeight<MCParticle>();
275  if (!relWithWeight.first) return Const::doubleNaN;
276  return relWithWeight.second;
277  }
278 
279  double particleMCMatchDecayTime(const Particle* part)
280  {
281  const MCParticle* mcparticle = part->getMCParticle();
282  if (!mcparticle) return Const::doubleNaN;
283  return mcparticle->getDecayTime();
284  }
285 
286  double particleMCMatchLifeTime(const Particle* part)
287  {
288  const MCParticle* mcparticle = part->getMCParticle();
289  if (!mcparticle) return Const::doubleNaN;
290  return mcparticle->getLifetime();
291  }
292 
293  double particleMCMatchPX(const Particle* part)
294  {
295  const MCParticle* mcparticle = part->getMCParticle();
296  if (!mcparticle) return Const::doubleNaN;
297 
298  const auto& frame = ReferenceFrame::GetCurrent();
299  ROOT::Math::PxPyPzEVector mcpP4 = mcparticle->get4Vector();
300  return frame.getMomentum(mcpP4).Px();
301  }
302 
303  double particleMCMatchPY(const Particle* part)
304  {
305  const MCParticle* mcparticle = part->getMCParticle();
306  if (!mcparticle) return Const::doubleNaN;
307 
308  const auto& frame = ReferenceFrame::GetCurrent();
309  ROOT::Math::PxPyPzEVector mcpP4 = mcparticle->get4Vector();
310  return frame.getMomentum(mcpP4).Py();
311  }
312 
313  double particleMCMatchPZ(const Particle* part)
314  {
315  const MCParticle* mcparticle = part->getMCParticle();
316  if (!mcparticle) return Const::doubleNaN;
317 
318  const auto& frame = ReferenceFrame::GetCurrent();
319  ROOT::Math::PxPyPzEVector mcpP4 = mcparticle->get4Vector();
320  return frame.getMomentum(mcpP4).Pz();
321  }
322 
323  double particleMCMatchPT(const Particle* part)
324  {
325  const MCParticle* mcparticle = part->getMCParticle();
326  if (!mcparticle) return Const::doubleNaN;
327 
328  const auto& frame = ReferenceFrame::GetCurrent();
329  ROOT::Math::PxPyPzEVector mcpP4 = mcparticle->get4Vector();
330  return frame.getMomentum(mcpP4).Pt();
331  }
332 
333  double particleMCMatchE(const Particle* part)
334  {
335  const MCParticle* mcparticle = part->getMCParticle();
336  if (!mcparticle) return Const::doubleNaN;
337 
338  const auto& frame = ReferenceFrame::GetCurrent();
339  ROOT::Math::PxPyPzEVector mcpP4 = mcparticle->get4Vector();
340  return frame.getMomentum(mcpP4).E();
341  }
342 
343  double particleMCMatchP(const Particle* part)
344  {
345  const MCParticle* mcparticle = part->getMCParticle();
346  if (!mcparticle) return Const::doubleNaN;
347 
348  const auto& frame = ReferenceFrame::GetCurrent();
349  ROOT::Math::PxPyPzEVector mcpP4 = mcparticle->get4Vector();
350  return frame.getMomentum(mcpP4).P();
351  }
352 
353  double particleMCMatchTheta(const Particle* part)
354  {
355  const MCParticle* mcparticle = part->getMCParticle();
356  if (!mcparticle) return Const::doubleNaN;
357 
358  const auto& frame = ReferenceFrame::GetCurrent();
359  ROOT::Math::PxPyPzEVector mcpP4 = mcparticle->get4Vector();
360  return frame.getMomentum(mcpP4).Theta();
361  }
362 
363  double particleMCMatchPhi(const Particle* part)
364  {
365  const MCParticle* mcparticle = part->getMCParticle();
366  if (!mcparticle) return Const::doubleNaN;
367 
368  const auto& frame = ReferenceFrame::GetCurrent();
369  ROOT::Math::PxPyPzEVector mcpP4 = mcparticle->get4Vector();
370  return frame.getMomentum(mcpP4).Phi();
371  }
372 
373  double mcParticleNDaughters(const Particle* part)
374  {
375  const MCParticle* mcparticle = part->getMCParticle();
376 
377  if (!mcparticle) return Const::doubleNaN;
378  return mcparticle->getNDaughters();
379  }
380 
381  double particleMCRecoilMass(const Particle* part)
382  {
383  StoreArray<MCParticle> mcparticles;
384  if (mcparticles.getEntries() < 1) return Const::doubleNaN;
385 
386  ROOT::Math::PxPyPzEVector pInitial = mcparticles[0]->get4Vector();
387  ROOT::Math::PxPyPzEVector pDaughters;
388  const std::vector<Particle*> daughters = part->getDaughters();
389  for (auto daughter : daughters) {
390  const MCParticle* mcD = daughter->getMCParticle();
391  if (!mcD) return Const::doubleNaN;
392 
393  pDaughters += mcD->get4Vector();
394  }
395  return (pInitial - pDaughters).M();
396  }
397 
398  ROOT::Math::PxPyPzEVector MCInvisibleP4(const MCParticle* mcparticle)
399  {
400  ROOT::Math::PxPyPzEVector ResultP4;
401  int pdg = abs(mcparticle->getPDG());
402  bool isNeutrino = (pdg == 12 or pdg == 14 or pdg == 16);
403 
404  if (mcparticle->getNDaughters() > 0) {
405  const std::vector<MCParticle*> daughters = mcparticle->getDaughters();
406  for (auto daughter : daughters)
407  ResultP4 += MCInvisibleP4(daughter);
408  } else if (isNeutrino)
409  ResultP4 += mcparticle->get4Vector();
410 
411  return ResultP4;
412  }
413 
414  double particleMCCosThetaBetweenParticleAndNominalB(const Particle* part)
415  {
416  int particlePDG = abs(part->getPDGCode());
417  if (particlePDG != 511 and particlePDG != 521)
418  B2FATAL("The variable mcCosThetaBetweenParticleAndNominalB is only meant to be used on B mesons!");
419 
420  PCmsLabTransform T;
421  double e_Beam = T.getCMSEnergy() / 2.0; // GeV
422  double m_B = part->getPDGMass();
423 
424  // Y(4S) mass according PDG (https://pdg.lbl.gov/2020/listings/rpp2020-list-upsilon-4S.pdf)
425  const double mY4S = 10.5794; // GeV
426 
427  // if this is a continuum run, use an approximate Y(4S) CMS energy
428  if (e_Beam * e_Beam - m_B * m_B < 0) {
429  e_Beam = mY4S / 2.0;
430  }
431  double p_B = std::sqrt(e_Beam * e_Beam - m_B * m_B);
432 
433  // Calculate cosThetaBY with daughter neutrino momenta subtracted
434  const MCParticle* mcB = part->getMCParticle();
435  if (!mcB) return Const::doubleNaN;
436 
437  int mcParticlePDG = abs(mcB->getPDG());
438  if (mcParticlePDG != 511 and mcParticlePDG != 521)
439  return Const::doubleNaN;
440 
441  ROOT::Math::PxPyPzEVector p = T.rotateLabToCms() * (mcB->get4Vector() - MCInvisibleP4(mcB));
442  double e_d = p.E();
443  double m_d = p.M();
444  double p_d = p.P();
445 
446  double theta_BY = (2 * e_Beam * e_d - m_B * m_B - m_d * m_d)
447  / (2 * p_B * p_d);
448  return theta_BY;
449  }
450 
451  double mcParticleSecondaryPhysicsProcess(const Particle* p)
452  {
453  const MCParticle* mcp = p->getMCParticle();
454  if (!mcp) return Const::doubleNaN;
455  return mcp->getSecondaryPhysicsProcess();
456  }
457 
458  double mcParticleStatus(const Particle* p)
459  {
460  const MCParticle* mcp = p->getMCParticle();
461  if (!mcp) return Const::doubleNaN;
462  return mcp->getStatus();
463  }
464 
465  double particleMCPrimaryParticle(const Particle* p)
466  {
467  const MCParticle* mcp = p->getMCParticle();
468  if (!mcp) return Const::doubleNaN;
469 
470  unsigned int bitmask = MCParticle::c_PrimaryParticle;
471  return mcp->hasStatus(bitmask);
472  }
473 
474  double particleMCVirtualParticle(const Particle* p)
475  {
476  const MCParticle* mcp = p->getMCParticle();
477  if (!mcp) return Const::doubleNaN;
478 
479  unsigned int bitmask = MCParticle::c_IsVirtual;
480  return mcp->hasStatus(bitmask);
481  }
482 
483  double particleMCInitialParticle(const Particle* p)
484  {
485  const MCParticle* mcp = p->getMCParticle();
486  if (!mcp) return Const::doubleNaN;
487 
488  unsigned int bitmask = MCParticle::c_Initial;
489  return mcp->hasStatus(bitmask);
490  }
491 
492  double particleMCISRParticle(const Particle* p)
493  {
494  const MCParticle* mcp = p->getMCParticle();
495  if (!mcp) return Const::doubleNaN;
496 
497  unsigned int bitmask = MCParticle::c_IsISRPhoton;
498  return mcp->hasStatus(bitmask);
499  }
500 
501  double particleMCFSRParticle(const Particle* p)
502  {
503  const MCParticle* mcp = p->getMCParticle();
504  if (!mcp) return Const::doubleNaN;
505 
506  unsigned int bitmask = MCParticle::c_IsFSRPhoton;
507  return mcp->hasStatus(bitmask);
508  }
509 
510  double particleMCPhotosParticle(const Particle* p)
511  {
512  const MCParticle* mcp = p->getMCParticle();
513  if (!mcp) return Const::doubleNaN;
514 
515  unsigned int bitmask = MCParticle::c_IsPHOTOSPhoton;
516  return mcp->hasStatus(bitmask);
517  }
518 
519  double generatorEventWeight(const Particle*)
520  {
521  StoreObjPtr<EventMetaData> evtMetaData;
522  if (!evtMetaData) return Const::doubleNaN;
523  return evtMetaData->getGeneratedWeight();
524  }
525 
526  int tauPlusMcMode(const Particle*)
527  {
528  StoreObjPtr<TauPairDecay> tauDecay;
529  if (!tauDecay) {
530  B2WARNING("Cannot find tau decay ID, did you forget to run TauDecayMarkerModule?");
531  return 0;
532  }
533  return tauDecay->getTauPlusIdMode();
534  }
535 
536  int tauMinusMcMode(const Particle*)
537  {
538  StoreObjPtr<TauPairDecay> tauDecay;
539  if (!tauDecay) {
540  B2WARNING("Cannot find tau decay ID, did you forget to run TauDecayMarkerModule?");
541  return 0;
542  }
543  return tauDecay->getTauMinusIdMode();
544  }
545 
546  int tauPlusMcProng(const Particle*)
547  {
548  StoreObjPtr<TauPairDecay> tauDecay;
549  if (!tauDecay) {
550  B2WARNING("Cannot find tau prong, did you forget to run TauDecayMarkerModule?");
551  return 0;
552  }
553  return tauDecay->getTauPlusMcProng();
554  }
555 
556  int tauMinusMcProng(const Particle*)
557  {
558  StoreObjPtr<TauPairDecay> tauDecay;
559  if (!tauDecay) {
560  B2WARNING("Cannot find tau prong, did you forget to run TauDecayMarkerModule?");
561  return 0;
562  }
563  return tauDecay->getTauMinusMcProng();
564  }
565 
566  double isReconstructible(const Particle* p)
567  {
568  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
569  return Const::doubleNaN;
570  const MCParticle* mcp = p->getMCParticle();
571  if (!mcp) return Const::doubleNaN;
572 
573  // If charged: make sure it was seen in the SVD.
574  // If neutral: make sure it was seen in the ECL.
575  return (abs(mcp->getCharge()) > 0) ? seenInSVD(p) : seenInECL(p);
576  }
577 
578  double isTrackFound(const Particle* p)
579  {
580  if (p->getParticleSource() != Particle::EParticleSourceObject::c_MCParticle)
581  return Const::doubleNaN;
582  const MCParticle* tmp_mcP = p->getMCParticle();
583  if (!Const::chargedStableSet.contains(Const::ParticleType(abs(tmp_mcP->getPDG()))))
584  return Const::doubleNaN;
585  Track* tmp_track = tmp_mcP->getRelated<Track>();
586  if (tmp_track) {
587  const TrackFitResult* tmp_tfr = tmp_track->getTrackFitResultWithClosestMass(Const::ChargedStable(abs(tmp_mcP->getPDG())));
588  if (tmp_tfr->getChargeSign()*tmp_mcP->getCharge() > 0)
589  return 1;
590  else
591  return -1;
592  }
593  return 0;
594  }
595 
596  double seenInPXD(const Particle* p)
597  {
598  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
599  return Const::doubleNaN;
600  const MCParticle* mcp = p->getMCParticle();
601  if (!mcp) return Const::doubleNaN;
602  return mcp->hasSeenInDetector(Const::PXD);
603  }
604 
605  double seenInSVD(const Particle* p)
606  {
607  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
608  return Const::doubleNaN;
609  const MCParticle* mcp = p->getMCParticle();
610  if (!mcp) return Const::doubleNaN;
611  return mcp->hasSeenInDetector(Const::SVD);
612  }
613 
614  double seenInCDC(const Particle* p)
615  {
616  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
617  return Const::doubleNaN;
618  const MCParticle* mcp = p->getMCParticle();
619  if (!mcp) return Const::doubleNaN;
620  return mcp->hasSeenInDetector(Const::CDC);
621  }
622 
623  double seenInTOP(const Particle* p)
624  {
625  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
626  return Const::doubleNaN;
627  const MCParticle* mcp = p->getMCParticle();
628  if (!mcp) return Const::doubleNaN;
629  return mcp->hasSeenInDetector(Const::TOP);
630  }
631 
632  double seenInECL(const Particle* p)
633  {
634  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
635  return Const::doubleNaN;
636  const MCParticle* mcp = p->getMCParticle();
637  if (!mcp) return Const::doubleNaN;
638  return mcp->hasSeenInDetector(Const::ECL);
639  }
640 
641  double seenInARICH(const Particle* p)
642  {
643  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
644  return Const::doubleNaN;
645  const MCParticle* mcp = p->getMCParticle();
646  if (!mcp) return Const::doubleNaN;
647  return mcp->hasSeenInDetector(Const::ARICH);
648  }
649 
650  double seenInKLM(const Particle* p)
651  {
652  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
653  return Const::doubleNaN;
654  const MCParticle* mcp = p->getMCParticle();
655  if (!mcp) return Const::doubleNaN;
656  return mcp->hasSeenInDetector(Const::KLM);
657  }
658 
659  int genNStepsToDaughter(const Particle* p, const std::vector<double>& arguments)
660  {
661  if (arguments.size() != 1)
662  B2FATAL("Wrong number of arguments for genNStepsToDaughter");
663 
664  const MCParticle* mcp = p->getMCParticle();
665  if (!mcp) {
666  B2WARNING("No MCParticle is associated to the particle");
667  return 0;
668  }
669 
670  int nChildren = p->getNDaughters();
671  if (arguments[0] >= nChildren) {
672  return 0;
673  }
674 
675  const Particle* daugP = p->getDaughter(arguments[0]);
676  const MCParticle* daugMCP = daugP->getMCParticle();
677  if (!daugMCP) {
678  // This is a strange case.
679  // The particle, p, has the related MC particle, but i-th daughter does not have the related MC Particle.
680  B2WARNING("No MCParticle is associated to the i-th daughter");
681  return 0;
682  }
683 
684  if (nChildren == 1) return 1;
685 
686  std::vector<int> genMothers;
687  MCMatching::fillGenMothers(daugMCP, genMothers);
688  auto match = std::find(genMothers.begin(), genMothers.end(), mcp->getIndex());
689  return match - genMothers.begin();
690  }
691 
692  int genNMissingDaughter(const Particle* p, const std::vector<double>& arguments)
693  {
694  if (arguments.size() < 1)
695  B2FATAL("Wrong number of arguments for genNMissingDaughter");
696 
697  const std::vector<int> PDGcodes(arguments.begin(), arguments.end());
698 
699  const MCParticle* mcp = p->getMCParticle();
700  if (!mcp) {
701  B2WARNING("No MCParticle is associated to the particle");
702  return 0;
703  }
704 
705  return MCMatching::countMissingParticle(p, mcp, PDGcodes);
706  }
707 
708  double getHEREnergy(const Particle*)
709  {
710  static DBObjPtr<BeamParameters> beamParamsDB;
711  return (beamParamsDB->getHER()).E();
712  }
713 
714  double getLEREnergy(const Particle*)
715  {
716  static DBObjPtr<BeamParameters> beamParamsDB;
717  return (beamParamsDB->getLER()).E();
718  }
719 
720  double getCrossingAngleX(const Particle*)
721  {
722  // get the beam momenta from the DB
723  static DBObjPtr<BeamParameters> beamParamsDB;
724  B2Vector3D herVec = beamParamsDB->getHER().Vect();
725  B2Vector3D lerVec = beamParamsDB->getLER().Vect();
726 
727  // only looking at the horizontal (XZ plane) -> set y-coordinates to zero
728  herVec.SetY(0);
729  lerVec.SetY(0);
730 
731  //calculate the crossing angle
732  return herVec.Angle(-lerVec);
733  }
734 
735  double getCrossingAngleY(const Particle*)
736  {
737  // get the beam momenta from the DB
738  static DBObjPtr<BeamParameters> beamParamsDB;
739  B2Vector3D herVec = beamParamsDB->getHER().Vect();
740  B2Vector3D lerVec = beamParamsDB->getLER().Vect();
741 
742  // only looking at the vertical (YZ plane) -> set x-coordinates to zero
743  herVec.SetX(0);
744  lerVec.SetX(0);
745 
746  //calculate the crossing angle
747  return herVec.Angle(-lerVec);
748  }
749 
750 
751  double particleClusterMatchWeight(const Particle* particle)
752  {
753  /* Get the weight of the *cluster* mc match for the mcparticle matched to
754  * this particle.
755  *
756  * Note that for track-based particles this is different from the mc match
757  * of the particle (which it inherits from the mc match of the track)
758  */
759  const MCParticle* matchedToParticle = particle->getMCParticle();
760  if (!matchedToParticle) return Const::doubleNaN;
761  int matchedToIndex = matchedToParticle->getArrayIndex();
762 
763  const ECLCluster* cluster = particle->getECLCluster();
764  if (!cluster) return Const::doubleNaN;
765 
766  const auto mcps = cluster->getRelationsTo<MCParticle>();
767  for (unsigned int i = 0; i < mcps.size(); ++i)
768  if (mcps[i]->getArrayIndex() == matchedToIndex)
769  return mcps.weight(i);
770 
771  return Const::doubleNaN;
772  }
773 
774  double particleClusterBestMCMatchWeight(const Particle* particle)
775  {
776  /* Get the weight of the best mc match of the cluster associated to
777  * this particle.
778  *
779  * Note for electrons (or any track-based particle) this may not be
780  * the same thing as the mc match of the particle (which is taken
781  * from the track).
782  *
783  * For photons (or any ECL-based particle) this will be the same as the
784  * mcMatchWeight
785  */
786  const ECLCluster* cluster = particle->getECLCluster();
787  if (!cluster) return Const::doubleNaN;
788 
789  /* loop over all mcparticles related to this cluster, find the largest
790  * weight by std::sort-ing the doubles
791  */
792  auto mcps = cluster->getRelationsTo<MCParticle>();
793  if (mcps.size() == 0) return Const::doubleNaN;
794 
795  std::vector<double> weights;
796  for (unsigned int i = 0; i < mcps.size(); ++i)
797  weights.emplace_back(mcps.weight(i));
798 
799  // sort descending by weight
800  std::sort(weights.begin(), weights.end());
801  std::reverse(weights.begin(), weights.end());
802  return weights[0];
803  }
804 
805  double particleClusterBestMCPDGCode(const Particle* particle)
806  {
807  /* Get the PDG code of the best mc match of the cluster associated to this
808  * particle.
809  *
810  * Note for electrons (or any track-based particle) this may not be the
811  * same thing as the mc match of the particle (which is taken from the track).
812  *
813  * For photons (or any ECL-based particle) this will be the same as the mcPDG
814  */
815  const ECLCluster* cluster = particle->getECLCluster();
816  if (!cluster) return Const::doubleNaN;
817 
818  auto mcps = cluster->getRelationsTo<MCParticle>();
819  if (mcps.size() == 0) return Const::doubleNaN;
820 
821  std::vector<std::pair<double, int>> weightsAndIndices;
822  for (unsigned int i = 0; i < mcps.size(); ++i)
823  weightsAndIndices.emplace_back(mcps.weight(i), i);
824 
825  // sort descending by weight
826  std::sort(weightsAndIndices.begin(), weightsAndIndices.end(),
827  ValueIndexPairSorting::higherPair<decltype(weightsAndIndices)::value_type>);
828  // cppcheck-suppress containerOutOfBounds
829  return mcps.object(weightsAndIndices[0].second)->getPDG();
830  }
831 
832  double particleClusterTotalMCMatchWeight(const Particle* particle)
833  {
834  const ECLCluster* cluster = particle->getECLCluster();
835  if (!cluster) return Const::doubleNaN;
836 
837  auto mcps = cluster->getRelationsTo<MCParticle>();
838 
839  // if there are no relations to any MCParticles, we return 0!
840  double weightsum = 0;
841  for (unsigned int i = 0; i < mcps.size(); ++i)
842  weightsum += mcps.weight(i);
843 
844  return weightsum;
845  }
846 
847  // Helper function for particleClusterTotalMCMatchWeightForKlong
848  void getKlongWeightMap(const Particle* particle, std::map<int, double>& mapMCParticleIndxAndWeight)
849  {
850  const ECLCluster* cluster = particle->getECLCluster();
851  auto mcps = cluster->getRelationsTo<MCParticle>();
852 
853  for (unsigned int i = 0; i < mcps.size(); ++i) {
854  double weight = mcps.weight(i);
855  const MCParticle* mcp = mcps[i];
856 
857  while (mcp) {
858  if (mcp->getPDG() == 130) {
859  int index = mcp->getArrayIndex();
860  if (mapMCParticleIndxAndWeight.find(index) != mapMCParticleIndxAndWeight.end()) {
861  mapMCParticleIndxAndWeight.at(index) = mapMCParticleIndxAndWeight.at(index) + weight;
862  } else {
863  mapMCParticleIndxAndWeight.insert({index, weight});
864  }
865  break;
866  } else {
867  mcp = mcp->getMother();
868  }
869  }
870  }
871  }
872 
873  double particleClusterTotalMCMatchWeightForKlong(const Particle* particle)
874  {
875  const ECLCluster* cluster = particle->getECLCluster();
876  if (!cluster) return Const::doubleNaN;
877 
878  auto mcps = cluster->getRelationsTo<MCParticle>();
879  if (mcps.size() == 0) return Const::doubleNaN;
880 
881  std::map<int, double> mapMCParticleIndxAndWeight;
882  getKlongWeightMap(particle, mapMCParticleIndxAndWeight);
883 
884  double totalWeight = 0;
885  for (const auto& map : mapMCParticleIndxAndWeight) {
886  totalWeight += map.second;
887  }
888 
889  return totalWeight;
890  }
891 
892  double particleClusterTotalMCMatchWeightForBestKlong(const Particle* particle)
893  {
894  const ECLCluster* cluster = particle->getECLCluster();
895  if (!cluster) return Const::doubleNaN;
896 
897  auto mcps = cluster->getRelationsTo<MCParticle>();
898  if (mcps.size() == 0) return Const::doubleNaN;
899 
900  std::map<int, double> mapMCParticleIndxAndWeight;
901  getKlongWeightMap(particle, mapMCParticleIndxAndWeight);
902 
903  if (mapMCParticleIndxAndWeight.size() == 0)
904  return 0.0;
905 
906  auto maxMap = std::max_element(mapMCParticleIndxAndWeight.begin(), mapMCParticleIndxAndWeight.end(),
907  [](const auto & x, const auto & y) { return x.second < y.second; }
908  );
909 
910  return maxMap->second;
911  }
912 
913  double isBBCrossfeed(const Particle* particle)
914  {
915  if (particle == nullptr)
916  return Const::doubleNaN;
917 
918  int pdg = particle->getPDGCode();
919  if (abs(pdg) != 511 && abs(pdg) != 521 && abs(pdg) != 531)
920  return Const::doubleNaN;
921 
922  std::vector<const Particle*> daughters = particle->getFinalStateDaughters();
923  int nDaughters = daughters.size();
924  if (nDaughters <= 1)
925  return 0;
926  std::vector<int> mother_ids;
927 
928  for (int j = 0; j < nDaughters; ++j) {
929  const MCParticle* curMCParticle = daughters[j]->getMCParticle();
930  while (curMCParticle != nullptr) {
931  pdg = curMCParticle->getPDG();
932  if (abs(pdg) == 511 || abs(pdg) == 521 || abs(pdg) == 531) {
933  mother_ids.emplace_back(curMCParticle->getArrayIndex());
934  break;
935  }
936  const MCParticle* curMCMother = curMCParticle->getMother();
937  curMCParticle = curMCMother;
938  }
939  if (curMCParticle == nullptr) {
940  return Const::doubleNaN;
941  }
942  }
943 
944  std::set<int> distinctIDs = std::set(mother_ids.begin(), mother_ids.end());
945  if (distinctIDs.size() == 1)
946  return 0;
947  else
948  return 1;
949  }
950 
951  int ancestorBIndex(const Particle* particle)
952  {
953  const MCParticle* mcpart = particle->getMCParticle();
954 
955  while (mcpart) {
956  int pdg = std::abs(mcpart->getPDG());
957 
958  if ((pdg == 521) || (pdg == 511))
959  return mcpart->getArrayIndex();
960 
961  mcpart = mcpart->getMother();
962  }
963 
964  return -1;
965  }
966 
967  VARIABLE_GROUP("MC matching and MC truth");
968  REGISTER_VARIABLE("isSignal", isSignal,
969  "1.0 if Particle is correctly reconstructed (SIGNAL), 0.0 if not, and NaN if no related MCParticle could be found. \n"
970  "It behaves according to DecayStringGrammar.");
971  REGISTER_VARIABLE("isSignalAcceptWrongFSPs", isSignalAcceptWrongFSPs,
972  "1.0 if Particle is almost correctly reconstructed (SIGNAL), 0.0 if not, and NaN if no related MCParticle could be found.\n"
973  "Misidentification of charged FSP is allowed.");
974  REGISTER_VARIABLE("isPrimarySignal", isPrimarySignal,
975  "1.0 if Particle is correctly reconstructed (SIGNAL) and primary, 0.0 if not, and NaN if no related MCParticle could be found");
976  REGISTER_VARIABLE("isSignalAcceptBremsPhotons", isSignalAcceptBremsPhotons,
977  "1.0 if Particle is correctly reconstructed (SIGNAL), 0.0 if not, and NaN if no related MCParticle could be found.\n"
978  "Particles with gamma daughters attached through the bremsstrahlung recovery modules are allowed.");
979  REGISTER_VARIABLE("genMotherPDG", genMotherPDG,
980  "Check the PDG code of a particles MC mother particle");
981  REGISTER_VARIABLE("genMotherPDG(i)", genNthMotherPDG,
982  "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:");
983 
984  REGISTER_VARIABLE("genQ2PmPd(i,j,...)", genQ2PmPd, R"DOC(
985  Returns the generated four momentum transfer squared :math:`q^2` calculated as :math:`q^2 = (p_m - p_{d_i} - p_{d_j} - ...)^2`.
986 
987  Here :math:`p_m` is the four momentum of the given (mother) particle,
988  and :math:`p_{d_{i,j,...}}` are the daughter particles with indices given as arguments .
989  The ordering of daughters is as defined in the DECAY.DEC file used in the generation, with the numbering starting at :math:`N=0`.
990 
991  Returns NaN if no related MCParticle could be found.
992  Returns NaN if any of the given indices is larger than the number of daughters of the given particle.
993 
994  )DOC", ":math:`[\\text{GeV}/\\text{c}]^2`");
995 
996  REGISTER_VARIABLE("genMotherID", genMotherIndex,
997  "Check the array index of a particles generated mother");
998  REGISTER_VARIABLE("genMotherID(i)", genNthMotherIndex,
999  "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:");
1000  // genMotherPDG and genMotherID are overloaded (each are two C++ functions
1001  // sharing one variable name) so one of the two needs to be made the indexed
1002  // variable in sphinx
1003  REGISTER_VARIABLE("isBBCrossfeed", isBBCrossfeed,
1004  "Returns 1 for crossfeed in reconstruction of given B meson, 0 for no crossfeed and NaN for no true B meson or failed truthmatching.");
1005  REGISTER_VARIABLE("ancestorBIndex", ancestorBIndex,
1006  "Returns array index of B ancestor, or -1 if no B or no MC-matching is found.");
1007  REGISTER_VARIABLE("genMotherP", genMotherP,
1008  "Generated momentum of a particles MC mother particle\n\n", "GeV/c");
1009  REGISTER_VARIABLE("genParticleID", genParticleIndex,
1010  "Check the array index of a particle's related MCParticle");
1011  REGISTER_VARIABLE("isSignalAcceptMissingNeutrino",
1012  isSignalAcceptMissingNeutrino,
1013  "Same as isSignal, but also accept missing neutrino");
1014  REGISTER_VARIABLE("isSignalAcceptMissingMassive",
1015  isSignalAcceptMissingMassive,
1016  "Same as isSignal, but also accept missing massive particle");
1017  REGISTER_VARIABLE("isSignalAcceptMissingGamma",
1018  isSignalAcceptMissingGamma,
1019  "Same as isSignal, but also accept missing gamma, such as B -> K* gamma, pi0 -> gamma gamma");
1020  REGISTER_VARIABLE("isSignalAcceptMissing",
1021  isSignalAcceptMissing,
1022  "Same as isSignal, but also accept missing particle");
1023  REGISTER_VARIABLE("isMisidentified", isMisidentified,
1024  "Return 1 if the particle is misidentified: at least one of the final state particles has the wrong PDG code assignment (including wrong charge), 0 if PDG code is fine, and NaN if no related MCParticle could be found.");
1025  REGISTER_VARIABLE("isWrongCharge", isWrongCharge,
1026  "Return 1 if the charge of the particle is wrongly assigned, 0 if it's the correct charge, and NaN if no related MCParticle could be found.");
1027  REGISTER_VARIABLE("isCloneTrack", isCloneTrack,
1028  "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)");
1029  REGISTER_VARIABLE("isOrHasCloneTrack", isOrHasCloneTrack,
1030  "Return 1 if the particle is a clone track or has a clone track as a daughter, 0 otherwise.");
1031  REGISTER_VARIABLE("mcPDG", particleMCMatchPDGCode,
1032  "The PDG code of matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
1033  REGISTER_VARIABLE("mcErrors", particleMCErrors,
1034  "The bit pattern indicating the quality of MC match (see MCMatching::MCErrorFlags)");
1035  REGISTER_VARIABLE("mcMatchWeight", particleMCMatchWeight,
1036  "The weight of the Particle -> MCParticle relation (only for the first Relation = largest weight).");
1037  REGISTER_VARIABLE("nMCMatches", particleNumberOfMCMatch,
1038  "The number of relations of this Particle to MCParticle.");
1039  REGISTER_VARIABLE("mcDecayTime", particleMCMatchDecayTime,
1040  "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).\n\n",
1041  "ns");
1042  REGISTER_VARIABLE("mcLifeTime", particleMCMatchLifeTime,
1043  "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).\n\n",
1044  "ns");
1045  REGISTER_VARIABLE("mcPX", particleMCMatchPX,
1046  "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).\n\n",
1047  "GeV/c");
1048  REGISTER_VARIABLE("mcPY", particleMCMatchPY,
1049  "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).\n\n",
1050  "GeV/c");
1051  REGISTER_VARIABLE("mcPZ", particleMCMatchPZ,
1052  "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).\n\n",
1053  "GeV/c");
1054  REGISTER_VARIABLE("mcPT", particleMCMatchPT,
1055  "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).\n\n",
1056  "GeV/c");
1057  REGISTER_VARIABLE("mcE", particleMCMatchE,
1058  "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).\n\n",
1059  "GeV");
1060  REGISTER_VARIABLE("mcP", particleMCMatchP,
1061  "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).\n\n",
1062  "GeV/c");
1063  REGISTER_VARIABLE("mcPhi", particleMCMatchPhi,
1064  "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).\n\n",
1065  "rad");
1066  REGISTER_VARIABLE("mcTheta", particleMCMatchTheta,
1067  "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).\n\n",
1068  "rad");
1069  REGISTER_VARIABLE("nMCDaughters", mcParticleNDaughters,
1070  "The number of daughters of the matched MCParticle, NaN if no match. Requires running matchMCTruth() on the reconstructed particles, or a particle list filled with generator particles (MCParticle objects).");
1071  REGISTER_VARIABLE("mcRecoilMass", particleMCRecoilMass,
1072  "The mass recoiling against the particles attached as particle's daughters calculated using MC truth values.\n\n",
1073  "GeV/:math:`\\text{c}^2`");
1074  REGISTER_VARIABLE("mcCosThetaBetweenParticleAndNominalB",
1075  particleMCCosThetaBetweenParticleAndNominalB,
1076  "Cosine of the angle in CMS between momentum the particle and a nominal B particle. In this calculation, the momenta of all descendant neutrinos are subtracted from the B momentum.");
1077 
1078 
1079  REGISTER_VARIABLE("mcSecPhysProc", mcParticleSecondaryPhysicsProcess,
1080  R"DOC(
1081 Returns the secondary physics process flag, which is set by Geant4 on secondary particles. It indicates the type of process that produced the particle.
1082 
1083 Returns NaN if the particle is not matched to a MCParticle.
1084 
1085 Returns -1 in case of unknown process.
1086 
1087 Returns 0 if the particle is primary, i.e. produced by the event generator and not Geant4. Particles produced by Geant4 (i.e. secondary particles) include those produced in interaction with detector material, Bremsstrahlung, and the decay products of long-lived particles (e.g. muons, pions, K_S0, K_L0, Lambdas, ...).
1088 
1089 List of possible values (taken from the Geant4 source of
1090 `G4DecayProcessType <https://github.com/Geant4/geant4/blob/v10.6.3/source/processes/decay/include/G4DecayProcessType.hh>`_,
1091 `G4HadronicProcessType <https://github.com/Geant4/geant4/blob/v10.6.3/source/processes/hadronic/management/include/G4HadronicProcessType.hh>`_,
1092 `G4TransportationProcessType <https://github.com/Geant4/geant4/blob/v10.6.3/source/processes/transportation/include/G4TransportationProcessType.hh>`_ and
1093 `G4EmProcessSubType <https://github.com/Geant4/geant4/blob/v10.6.3/source/processes/electromagnetic/utils/include/G4EmProcessSubType.hh>`_)
1094 
1095 * 1 Coulomb scattering
1096 * 2 Ionisation
1097 * 3 Bremsstrahlung
1098 * 4 Pair production by charged
1099 * 5 Annihilation
1100 * 6 Annihilation to mu mu
1101 * 7 Annihilation to hadrons
1102 * 8 Nuclear stopping
1103 * 9 Electron general process
1104 * 10 Multiple scattering
1105 * 11 Rayleigh
1106 * 12 Photo-electric effect
1107 * 13 Compton scattering
1108 * 14 Gamma conversion
1109 * 15 Gamma conversion to mu mu
1110 * 16 Gamma general process
1111 * 21 Cerenkov
1112 * 22 Scintillation
1113 * 23 Synchrotron radiation
1114 * 24 Transition radiation
1115 * 91 Transportation
1116 * 92 Coupled transportation
1117 * 111 Hadron elastic
1118 * 121 Hadron inelastic
1119 * 131 Capture
1120 * 132 Mu atomic capture
1121 * 141 Fission
1122 * 151 Hadron at rest
1123 * 152 Lepton at rest
1124 * 161 Charge exchange
1125 * 201 Decay
1126 * 202 Decay with spin
1127 * 203 Decay (pion make spin)
1128 * 210 Radioactive decay
1129 * 211 Unknown decay
1130 * 221 Mu atom decay
1131 * 231 External decay
1132 
1133 .. note:: This is what `modularAnalysis.printMCParticles` shows as ``creation process`` when ``showStatus`` is set to ``True``.
1134 )DOC");
1135  REGISTER_VARIABLE("mcParticleStatus", mcParticleStatus,
1136  "Returns status bits of related MCParticle or NaN if MCParticle relation is not set.");
1137  REGISTER_VARIABLE("mcPrimary", particleMCPrimaryParticle,
1138  "Returns 1 if Particle is related to primary MCParticle, 0 if Particle is related to non - primary MCParticle, "
1139  "NaN if Particle is not related to MCParticle.");
1140  REGISTER_VARIABLE("mcVirtual", particleMCVirtualParticle,
1141  "Returns 1 if Particle is related to virtual MCParticle, 0 if Particle is related to non - virtual MCParticle, "
1142  "NaN if Particle is not related to MCParticle.")
1143  REGISTER_VARIABLE("mcInitial", particleMCInitialParticle,
1144  "Returns 1 if Particle is related to initial MCParticle, 0 if Particle is related to non - initial MCParticle, "
1145  "NaN if Particle is not related to MCParticle.")
1146  REGISTER_VARIABLE("mcISR", particleMCISRParticle,
1147  "Returns 1 if Particle is related to ISR MCParticle, 0 if Particle is related to non - ISR MCParticle, "
1148  "NaN if Particle is not related to MCParticle.")
1149  REGISTER_VARIABLE("mcFSR", particleMCFSRParticle,
1150  "Returns 1 if Particle is related to FSR MCParticle, 0 if Particle is related to non - FSR MCParticle ,"
1151  "NaN if Particle is not related to MCParticle.")
1152  REGISTER_VARIABLE("mcPhotos", particleMCPhotosParticle,
1153  "Returns 1 if Particle is related to Photos MCParticle, 0 if Particle is related to non - Photos MCParticle, "
1154  "NaN if Particle is not related to MCParticle.")
1155  REGISTER_VARIABLE("generatorEventWeight", generatorEventWeight,
1156  "[Eventbased] Returns the event weight produced by the event generator")
1157 
1158  REGISTER_VARIABLE("genNStepsToDaughter(i)", genNStepsToDaughter,
1159  "Returns number of steps to i-th daughter from the particle at generator level. "
1160  "NaN if no MCParticle is associated to the particle or i-th daughter. "
1161  "NaN if i-th daughter does not exist.");
1162  REGISTER_VARIABLE("genNMissingDaughter(PDG)", genNMissingDaughter,
1163  "Returns the number of missing daughters having assigned PDG codes. "
1164  "NaN if no MCParticle is associated to the particle.");
1165  REGISTER_VARIABLE("Eher", getHEREnergy, R"DOC(
1166 [Eventbased] The nominal HER energy used by the generator.
1167 
1168 .. warning:: This variable does not make sense for data.
1169 
1170 )DOC","GeV");
1171  REGISTER_VARIABLE("Eler", getLEREnergy, R"DOC(
1172 [Eventbased] The nominal LER energy used by the generator.
1173 
1174 .. warning:: This variable does not make sense for data.
1175 
1176 )DOC","GeV");
1177  REGISTER_VARIABLE("XAngle", getCrossingAngleX, R"DOC(
1178 [Eventbased] The nominal beam crossing angle in the x-z plane from generator level beam kinematics.
1179 
1180 .. warning:: This variable does not make sense for data.
1181 
1182 )DOC","rad");
1183  REGISTER_VARIABLE("YAngle", getCrossingAngleY, R"DOC(
1184 [Eventbased] The nominal beam crossing angle in the y-z plane from generator level beam kinematics.
1185 
1186 .. warning:: This variable does not make sense for data.
1187 
1188 )DOC","rad");
1189 
1190  VARIABLE_GROUP("Generated tau decay information");
1191  REGISTER_VARIABLE("tauPlusMCMode", tauPlusMcMode,
1192  "[Eventbased] Decay ID for the positive tau lepton in a tau pair generated event.");
1193  REGISTER_VARIABLE("tauMinusMCMode", tauMinusMcMode,
1194  "[Eventbased] Decay ID for the negative tau lepton in a tau pair generated event.");
1195  REGISTER_VARIABLE("tauPlusMCProng", tauPlusMcProng,
1196  "[Eventbased] Prong for the positive tau lepton in a tau pair generated event.");
1197  REGISTER_VARIABLE("tauMinusMCProng", tauMinusMcProng,
1198  "[Eventbased] Prong for the negative tau lepton in a tau pair generated event.");
1199 
1200  VARIABLE_GROUP("MC particle seen in subdetectors");
1201  REGISTER_VARIABLE("isReconstructible", isReconstructible,
1202  "Checks charged particles were seen in the SVD and neutrals in the ECL, returns 1.0 if so, 0.0 if not, NaN for composite particles or if no related MCParticle could be found. Useful for generator studies, not for reconstructed particles.");
1203  REGISTER_VARIABLE("seenInPXD", seenInPXD,
1204  "Returns 1.0 if the MC particle was seen in the PXD, 0.0 if not, NaN for composite particles or if no related MCParticle could be found. Useful for generator studies, not for reconstructed particles.");
1205  REGISTER_VARIABLE("isTrackFound", isTrackFound,
1206  "works on charged stable particle list created from MCParticles, returns NaN if not ; returns 1.0 if there is a reconstructed track related to the charged stable MCParticle with the correct charge, return -1.0 if the reconstructed track has the wrong charge, return 0.0 when no reconstructed track is found.");
1207  REGISTER_VARIABLE("seenInSVD", seenInSVD,
1208  "Returns 1.0 if the MC particle was seen in the SVD, 0.0 if not, NaN for composite particles or if no related MCParticle could be found. Useful for generator studies, not for reconstructed particles.");
1209  REGISTER_VARIABLE("seenInCDC", seenInCDC,
1210  "Returns 1.0 if the MC particle was seen in the CDC, 0.0 if not, NaN for composite particles or if no related MCParticle could be found. Useful for generator studies, not for reconstructed particles.");
1211  REGISTER_VARIABLE("seenInTOP", seenInTOP,
1212  "Returns 1.0 if the MC particle was seen in the TOP, 0.0 if not, NaN for composite particles or if no related MCParticle could be found. Useful for generator studies, not for reconstructed particles.");
1213  REGISTER_VARIABLE("seenInECL", seenInECL,
1214  "Returns 1.0 if the MC particle was seen in the ECL, 0.0 if not, NaN for composite particles or if no related MCParticle could be found. Useful for generator studies, not for reconstructed particles.");
1215  REGISTER_VARIABLE("seenInARICH", seenInARICH,
1216  "Returns 1.0 if the MC particle was seen in the ARICH, 0.0 if not, NaN for composite particles or if no related MCParticle could be found. Useful for generator studies, not for reconstructed particles.");
1217  REGISTER_VARIABLE("seenInKLM", seenInKLM,
1218  "Returns 1.0 if the MC particle was seen in the KLM, 0.0 if not, NaN for composite particles or if no related MCParticle could be found. Useful for generator studies, not for reconstructed particles.");
1219 
1220  VARIABLE_GROUP("MC Matching for ECLClusters");
1221  REGISTER_VARIABLE("clusterMCMatchWeight", particleClusterMatchWeight,
1222  "Returns the weight of the ECLCluster -> MCParticle relation for the MCParticle matched to the particle. "
1223  "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. "
1224  "Returns -1 if the cluster *was* matched to particles, but not the match of the particle provided.");
1225  REGISTER_VARIABLE("clusterBestMCMatchWeight", particleClusterBestMCMatchWeight,
1226  "Returns the weight of the ECLCluster -> MCParticle relation for the relation with the largest weight.");
1227  REGISTER_VARIABLE("clusterBestMCPDG", particleClusterBestMCPDGCode,
1228  "Returns the PDG code of the MCParticle for the ECLCluster -> MCParticle relation with the largest weight.");
1229  REGISTER_VARIABLE("clusterTotalMCMatchWeight", particleClusterTotalMCMatchWeight,
1230  "Returns the sum of all weights of the ECLCluster -> MCParticles relations.");
1231 
1232  REGISTER_VARIABLE("clusterTotalMCMatchWeightForKlong", particleClusterTotalMCMatchWeightForKlong,
1233  "Returns the sum of all weights of the ECLCluster -> MCParticles relations when MCParticle is a Klong or daughter of a Klong");
1234  REGISTER_VARIABLE("clusterTotalMCMatchWeightForBestKlong", particleClusterTotalMCMatchWeightForBestKlong,
1235  "Returns the sum of all weights of the ECLCluster -> MCParticles relations when MCParticle is the same Klong or daughter of the Klong. If multiple MC Klongs are related to the ECLCluster, returns the sum of weights for the best matched Klong.");
1236 
1237 
1238  }
1240 }
void SetX(DataType x)
set X/1st-coordinate
Definition: B2Vector3.h:457
void SetY(DataType y)
set Y/2nd-coordinate
Definition: B2Vector3.h:459
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:609
static const double doubleNaN
quiet_NaN
Definition: Const.h:694
@ c_IsFSRPhoton
bit 7: Particle is from finial state radiation
Definition: MCParticle.h:61
@ c_Initial
bit 5: Particle is initial such as e+ or e- and not going to Geant4
Definition: MCParticle.h:57
@ c_IsPHOTOSPhoton
bit 8: Particle is an radiative photon from PHOTOS
Definition: MCParticle.h:63
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Definition: MCParticle.h:47
@ c_IsVirtual
bit 4: Particle is virtual and not going to Geant4.
Definition: MCParticle.h:55
@ c_IsISRPhoton
bit 6: Particle is from initial state radiation
Definition: MCParticle.h:59
const MCParticle * getMCParticle() const
Returns the pointer to the MCParticle object that was used to create this Particle (ParticleType == c...
Definition: Particle.cc:942
static const ReferenceFrame & GetCurrent()
Get current rest frame.
int getArrayIndex() const
Returns this object's array index (in StoreArray), or -1 if not found.
B2Vector3< double > B2Vector3D
typedef for common usage with double
Definition: B2Vector3.h:516
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:24
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
@ c_Correct
This Particle and all its daughters are perfectly reconstructed.
Definition: MCMatching.h:34
@ c_MisID
One of the charged final state particles is mis-identified, i.e.
Definition: MCMatching.h:42
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
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:61