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