Belle II Software  release-08-00-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 isReconstructible(const Particle* p)
549  {
550  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
551  return Const::doubleNaN;
552  const MCParticle* mcp = p->getMCParticle();
553  if (!mcp) return Const::doubleNaN;
554 
555  // If charged: make sure it was seen in the SVD.
556  // If neutral: make sure it was seen in the ECL.
557  return (abs(mcp->getCharge()) > 0) ? seenInSVD(p) : seenInECL(p);
558  }
559 
560  double isTrackFound(const Particle* p)
561  {
562  if (p->getParticleSource() != Particle::EParticleSourceObject::c_MCParticle)
563  return Const::doubleNaN;
564  const MCParticle* tmp_mcP = p->getMCParticle();
565  if (!Const::chargedStableSet.contains(Const::ParticleType(abs(tmp_mcP->getPDG()))))
566  return Const::doubleNaN;
567  Track* tmp_track = tmp_mcP->getRelated<Track>();
568  if (tmp_track) {
569  const TrackFitResult* tmp_tfr = tmp_track->getTrackFitResultWithClosestMass(Const::ChargedStable(abs(tmp_mcP->getPDG())));
570  if (tmp_tfr->getChargeSign()*tmp_mcP->getCharge() > 0)
571  return 1;
572  else
573  return -1;
574  }
575  return 0;
576  }
577 
578  double seenInPXD(const Particle* p)
579  {
580  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
581  return Const::doubleNaN;
582  const MCParticle* mcp = p->getMCParticle();
583  if (!mcp) return Const::doubleNaN;
584  return mcp->hasSeenInDetector(Const::PXD);
585  }
586 
587  double seenInSVD(const Particle* p)
588  {
589  if (p->getParticleSource() == Particle::EParticleSourceObject::c_Composite)
590  return Const::doubleNaN;
591  const MCParticle* mcp = p->getMCParticle();
592  if (!mcp) return Const::doubleNaN;
593  return mcp->hasSeenInDetector(Const::SVD);
594  }
595 
596  double seenInCDC(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::CDC);
603  }
604 
605  double seenInTOP(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::TOP);
612  }
613 
614  double seenInECL(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::ECL);
621  }
622 
623  double seenInARICH(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::ARICH);
630  }
631 
632  double seenInKLM(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::KLM);
639  }
640 
641  int genNStepsToDaughter(const Particle* p, const std::vector<double>& arguments)
642  {
643  if (arguments.size() != 1)
644  B2FATAL("Wrong number of arguments for genNStepsToDaughter");
645 
646  const MCParticle* mcp = p->getMCParticle();
647  if (!mcp) {
648  B2WARNING("No MCParticle is associated to the particle");
649  return 0;
650  }
651 
652  int nChildren = p->getNDaughters();
653  if (arguments[0] >= nChildren) {
654  return 0;
655  }
656 
657  const Particle* daugP = p->getDaughter(arguments[0]);
658  const MCParticle* daugMCP = daugP->getMCParticle();
659  if (!daugMCP) {
660  // This is a strange case.
661  // The particle, p, has the related MC particle, but i-th daughter does not have the related MC Particle.
662  B2WARNING("No MCParticle is associated to the i-th daughter");
663  return 0;
664  }
665 
666  if (nChildren == 1) return 1;
667 
668  std::vector<int> genMothers;
669  MCMatching::fillGenMothers(daugMCP, genMothers);
670  auto match = std::find(genMothers.begin(), genMothers.end(), mcp->getIndex());
671  return match - genMothers.begin();
672  }
673 
674  int genNMissingDaughter(const Particle* p, const std::vector<double>& arguments)
675  {
676  if (arguments.size() < 1)
677  B2FATAL("Wrong number of arguments for genNMissingDaughter");
678 
679  const std::vector<int> PDGcodes(arguments.begin(), arguments.end());
680 
681  const MCParticle* mcp = p->getMCParticle();
682  if (!mcp) {
683  B2WARNING("No MCParticle is associated to the particle");
684  return 0;
685  }
686 
687  return MCMatching::countMissingParticle(p, mcp, PDGcodes);
688  }
689 
690  double getHEREnergy(const Particle*)
691  {
692  static DBObjPtr<BeamParameters> beamParamsDB;
693  return (beamParamsDB->getHER()).E();
694  }
695 
696  double getLEREnergy(const Particle*)
697  {
698  static DBObjPtr<BeamParameters> beamParamsDB;
699  return (beamParamsDB->getLER()).E();
700  }
701 
702  double getCrossingAngleX(const Particle*)
703  {
704  // get the beam momenta from the DB
705  static DBObjPtr<BeamParameters> beamParamsDB;
706  B2Vector3D herVec = beamParamsDB->getHER().Vect();
707  B2Vector3D lerVec = beamParamsDB->getLER().Vect();
708 
709  // only looking at the horizontal (XZ plane) -> set y-coordinates to zero
710  herVec.SetY(0);
711  lerVec.SetY(0);
712 
713  //calculate the crossing angle
714  return herVec.Angle(-lerVec);
715  }
716 
717  double getCrossingAngleY(const Particle*)
718  {
719  // get the beam momenta from the DB
720  static DBObjPtr<BeamParameters> beamParamsDB;
721  B2Vector3D herVec = beamParamsDB->getHER().Vect();
722  B2Vector3D lerVec = beamParamsDB->getLER().Vect();
723 
724  // only looking at the vertical (YZ plane) -> set x-coordinates to zero
725  herVec.SetX(0);
726  lerVec.SetX(0);
727 
728  //calculate the crossing angle
729  return herVec.Angle(-lerVec);
730  }
731 
732 
733  double particleClusterMatchWeight(const Particle* particle)
734  {
735  /* Get the weight of the *cluster* mc match for the mcparticle matched to
736  * this particle.
737  *
738  * Note that for track-based particles this is different from the mc match
739  * of the particle (which it inherits from the mc match of the track)
740  */
741  const MCParticle* matchedToParticle = particle->getMCParticle();
742  if (!matchedToParticle) return Const::doubleNaN;
743  int matchedToIndex = matchedToParticle->getArrayIndex();
744 
745  const ECLCluster* cluster = particle->getECLCluster();
746  if (!cluster) return Const::doubleNaN;
747 
748  const auto mcps = cluster->getRelationsTo<MCParticle>();
749  for (unsigned int i = 0; i < mcps.size(); ++i)
750  if (mcps[i]->getArrayIndex() == matchedToIndex)
751  return mcps.weight(i);
752 
753  return Const::doubleNaN;
754  }
755 
756  double particleClusterBestMCMatchWeight(const Particle* particle)
757  {
758  /* Get the weight of the best mc match of the cluster associated to
759  * this particle.
760  *
761  * Note for electrons (or any track-based particle) this may not be
762  * the same thing as the mc match of the particle (which is taken
763  * from the track).
764  *
765  * For photons (or any ECL-based particle) this will be the same as the
766  * mcMatchWeight
767  */
768  const ECLCluster* cluster = particle->getECLCluster();
769  if (!cluster) return Const::doubleNaN;
770 
771  /* loop over all mcparticles related to this cluster, find the largest
772  * weight by std::sort-ing the doubles
773  */
774  auto mcps = cluster->getRelationsTo<MCParticle>();
775  if (mcps.size() == 0) return Const::doubleNaN;
776 
777  std::vector<double> weights;
778  for (unsigned int i = 0; i < mcps.size(); ++i)
779  weights.emplace_back(mcps.weight(i));
780 
781  // sort descending by weight
782  std::sort(weights.begin(), weights.end());
783  std::reverse(weights.begin(), weights.end());
784  return weights[0];
785  }
786 
787  double particleClusterBestMCPDGCode(const Particle* particle)
788  {
789  /* Get the PDG code of the best mc match of the cluster associated to this
790  * particle.
791  *
792  * Note for electrons (or any track-based particle) this may not be the
793  * same thing as the mc match of the particle (which is taken from the track).
794  *
795  * For photons (or any ECL-based particle) this will be the same as the mcPDG
796  */
797  const ECLCluster* cluster = particle->getECLCluster();
798  if (!cluster) return Const::doubleNaN;
799 
800  auto mcps = cluster->getRelationsTo<MCParticle>();
801  if (mcps.size() == 0) return Const::doubleNaN;
802 
803  std::vector<std::pair<double, int>> weightsAndIndices;
804  for (unsigned int i = 0; i < mcps.size(); ++i)
805  weightsAndIndices.emplace_back(mcps.weight(i), i);
806 
807  // sort descending by weight
808  std::sort(weightsAndIndices.begin(), weightsAndIndices.end(),
809  ValueIndexPairSorting::higherPair<decltype(weightsAndIndices)::value_type>);
810  // cppcheck-suppress containerOutOfBounds
811  return mcps.object(weightsAndIndices[0].second)->getPDG();
812  }
813 
814  double particleClusterTotalMCMatchWeight(const Particle* particle)
815  {
816  const ECLCluster* cluster = particle->getECLCluster();
817  if (!cluster) return Const::doubleNaN;
818 
819  auto mcps = cluster->getRelationsTo<MCParticle>();
820 
821  // if there are no relations to any MCParticles, we return 0!
822  double weightsum = 0;
823  for (unsigned int i = 0; i < mcps.size(); ++i)
824  weightsum += mcps.weight(i);
825 
826  return weightsum;
827  }
828 
829  double isBBCrossfeed(const Particle* particle)
830  {
831  if (particle == nullptr)
832  return Const::doubleNaN;
833 
834  int pdg = particle->getPDGCode();
835  if (abs(pdg) != 511 && abs(pdg) != 521 && abs(pdg) != 531)
836  return Const::doubleNaN;
837 
838  std::vector<const Particle*> daughters = particle->getFinalStateDaughters();
839  int nDaughters = daughters.size();
840  if (nDaughters <= 1)
841  return 0;
842  std::vector<int> mother_ids;
843 
844  for (int j = 0; j < nDaughters; ++j) {
845  const MCParticle* curMCParticle = daughters[j]->getMCParticle();
846  while (curMCParticle != nullptr) {
847  pdg = curMCParticle->getPDG();
848  if (abs(pdg) == 511 || abs(pdg) == 521 || abs(pdg) == 531) {
849  mother_ids.emplace_back(curMCParticle->getArrayIndex());
850  break;
851  }
852  const MCParticle* curMCMother = curMCParticle->getMother();
853  curMCParticle = curMCMother;
854  }
855  if (curMCParticle == nullptr) {
856  return Const::doubleNaN;
857  }
858  }
859 
860  std::set<int> distinctIDs = std::set(mother_ids.begin(), mother_ids.end());
861  if (distinctIDs.size() == 1)
862  return 0;
863  else
864  return 1;
865  }
866 
867  VARIABLE_GROUP("MC matching and MC truth");
868  REGISTER_VARIABLE("isSignal", isSignal,
869  "1.0 if Particle is correctly reconstructed (SIGNAL), 0.0 if not, and NaN if no related MCParticle could be found. \n"
870  "It behaves according to DecayStringGrammar.");
871  REGISTER_VARIABLE("isSignalAcceptWrongFSPs", isSignalAcceptWrongFSPs,
872  "1.0 if Particle is almost correctly reconstructed (SIGNAL), 0.0 if not, and NaN if no related MCParticle could be found.\n"
873  "Misidentification of charged FSP is allowed.");
874  REGISTER_VARIABLE("isPrimarySignal", isPrimarySignal,
875  "1.0 if Particle is correctly reconstructed (SIGNAL) and primary, 0.0 if not, and NaN if no related MCParticle could be found");
876  REGISTER_VARIABLE("isSignalAcceptBremsPhotons", isSignalAcceptBremsPhotons,
877  "1.0 if Particle is correctly reconstructed (SIGNAL), 0.0 if not, and NaN if no related MCParticle could be found.\n"
878  "Particles with gamma daughters attached through the bremsstrahlung recovery modules are allowed.");
879  REGISTER_VARIABLE("genMotherPDG", genMotherPDG,
880  "Check the PDG code of a particles MC mother particle");
881  REGISTER_VARIABLE("genMotherPDG(i)", genNthMotherPDG,
882  "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:");
883 
884  REGISTER_VARIABLE("genMotherID", genMotherIndex,
885  "Check the array index of a particles generated mother");
886  REGISTER_VARIABLE("genMotherID(i)", genNthMotherIndex,
887  "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:");
888  // genMotherPDG and genMotherID are overloaded (each are two C++ functions
889  // sharing one variable name) so one of the two needs to be made the indexed
890  // variable in sphinx
891  REGISTER_VARIABLE("isBBCrossfeed", isBBCrossfeed,
892  "Returns 1 for crossfeed in reconstruction of given B meson, 0 for no crossfeed and NaN for no true B meson or failed truthmatching.");
893  REGISTER_VARIABLE("genMotherP", genMotherP,
894  "Generated momentum of a particles MC mother particle\n\n", "GeV/c");
895  REGISTER_VARIABLE("genParticleID", genParticleIndex,
896  "Check the array index of a particle's related MCParticle");
897  REGISTER_VARIABLE("isSignalAcceptMissingNeutrino",
898  isSignalAcceptMissingNeutrino,
899  "Same as isSignal, but also accept missing neutrino");
900  REGISTER_VARIABLE("isSignalAcceptMissingMassive",
901  isSignalAcceptMissingMassive,
902  "Same as isSignal, but also accept missing massive particle");
903  REGISTER_VARIABLE("isSignalAcceptMissingGamma",
904  isSignalAcceptMissingGamma,
905  "Same as isSignal, but also accept missing gamma, such as B -> K* gamma, pi0 -> gamma gamma");
906  REGISTER_VARIABLE("isSignalAcceptMissing",
907  isSignalAcceptMissing,
908  "Same as isSignal, but also accept missing particle");
909  REGISTER_VARIABLE("isMisidentified", isMisidentified,
910  "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.");
911  REGISTER_VARIABLE("isWrongCharge", isWrongCharge,
912  "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.");
913  REGISTER_VARIABLE("isCloneTrack", isCloneTrack,
914  "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)");
915  REGISTER_VARIABLE("isOrHasCloneTrack", isOrHasCloneTrack,
916  "Return 1 if the particle is a clone track or has a clone track as a daughter, 0 otherwise.");
917  REGISTER_VARIABLE("mcPDG", particleMCMatchPDGCode,
918  "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).");
919  REGISTER_VARIABLE("mcErrors", particleMCErrors,
920  "The bit pattern indicating the quality of MC match (see MCMatching::MCErrorFlags)");
921  REGISTER_VARIABLE("mcMatchWeight", particleMCMatchWeight,
922  "The weight of the Particle -> MCParticle relation (only for the first Relation = largest weight).");
923  REGISTER_VARIABLE("nMCMatches", particleNumberOfMCMatch,
924  "The number of relations of this Particle to MCParticle.");
925  REGISTER_VARIABLE("mcDecayTime", particleMCMatchDecayTime,
926  "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",
927  "ns");
928  REGISTER_VARIABLE("mcLifeTime", particleMCMatchLifeTime,
929  "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",
930  "ns");
931  REGISTER_VARIABLE("mcPX", particleMCMatchPX,
932  "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",
933  "GeV/c");
934  REGISTER_VARIABLE("mcPY", particleMCMatchPY,
935  "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",
936  "GeV/c");
937  REGISTER_VARIABLE("mcPZ", particleMCMatchPZ,
938  "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",
939  "GeV/c");
940  REGISTER_VARIABLE("mcPT", particleMCMatchPT,
941  "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",
942  "GeV/c");
943  REGISTER_VARIABLE("mcE", particleMCMatchE,
944  "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",
945  "GeV");
946  REGISTER_VARIABLE("mcP", particleMCMatchP,
947  "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",
948  "GeV/c");
949  REGISTER_VARIABLE("mcPhi", particleMCMatchPhi,
950  "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",
951  "rad");
952  REGISTER_VARIABLE("mcTheta", particleMCMatchTheta,
953  "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",
954  "rad");
955  REGISTER_VARIABLE("nMCDaughters", mcParticleNDaughters,
956  "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).");
957  REGISTER_VARIABLE("mcRecoilMass", particleMCRecoilMass,
958  "The mass recoiling against the particles attached as particle's daughters calculated using MC truth values.\n\n",
959  "GeV/:math:`\\text{c}^2`");
960  REGISTER_VARIABLE("mcCosThetaBetweenParticleAndNominalB",
961  particleMCCosThetaBetweenParticleAndNominalB,
962  "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.");
963 
964 
965  REGISTER_VARIABLE("mcSecPhysProc", mcParticleSecondaryPhysicsProcess,
966  R"DOC(
967 Returns the secondary physics process flag, which is set by Geant4 on secondary particles. It indicates the type of process that produced the particle.
968 
969 Returns NaN if the particle is not matched to a MCParticle.
970 
971 Returns -1 in case of unknown process.
972 
973 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, ...).
974 
975 List of possible values (taken from the Geant4 source of
976 `G4DecayProcessType <https://github.com/Geant4/geant4/blob/v10.6.3/source/processes/decay/include/G4DecayProcessType.hh>`_,
977 `G4HadronicProcessType <https://github.com/Geant4/geant4/blob/v10.6.3/source/processes/hadronic/management/include/G4HadronicProcessType.hh>`_,
978 `G4TransportationProcessType <https://github.com/Geant4/geant4/blob/v10.6.3/source/processes/transportation/include/G4TransportationProcessType.hh>`_ and
979 `G4EmProcessSubType <https://github.com/Geant4/geant4/blob/v10.6.3/source/processes/electromagnetic/utils/include/G4EmProcessSubType.hh>`_)
980 
981 * 1 Coulomb scattering
982 * 2 Ionisation
983 * 3 Bremsstrahlung
984 * 4 Pair production by charged
985 * 5 Annihilation
986 * 6 Annihilation to mu mu
987 * 7 Annihilation to hadrons
988 * 8 Nuclear stopping
989 * 9 Electron general process
990 * 10 Multiple scattering
991 * 11 Rayleigh
992 * 12 Photo-electric effect
993 * 13 Compton scattering
994 * 14 Gamma conversion
995 * 15 Gamma conversion to mu mu
996 * 16 Gamma general process
997 * 21 Cerenkov
998 * 22 Scintillation
999 * 23 Synchrotron radiation
1000 * 24 Transition radiation
1001 * 91 Transportation
1002 * 92 Coupled transportation
1003 * 111 Hadron elastic
1004 * 121 Hadron inelastic
1005 * 131 Capture
1006 * 132 Mu atomic capture
1007 * 141 Fission
1008 * 151 Hadron at rest
1009 * 152 Lepton at rest
1010 * 161 Charge exchange
1011 * 201 Decay
1012 * 202 Decay with spin
1013 * 203 Decay (pion make spin)
1014 * 210 Radioactive decay
1015 * 211 Unknown decay
1016 * 221 Mu atom decay
1017 * 231 External decay
1018 
1019 .. note:: This is what `modularAnalysis.printMCParticles` shows as ``creation process`` when ``showStatus`` is set to ``True``.
1020 )DOC");
1021  REGISTER_VARIABLE("mcParticleStatus", mcParticleStatus,
1022  "Returns status bits of related MCParticle or NaN if MCParticle relation is not set.");
1023  REGISTER_VARIABLE("mcPrimary", particleMCPrimaryParticle,
1024  "Returns 1 if Particle is related to primary MCParticle, 0 if Particle is related to non - primary MCParticle, "
1025  "NaN if Particle is not related to MCParticle.");
1026  REGISTER_VARIABLE("mcVirtual", particleMCVirtualParticle,
1027  "Returns 1 if Particle is related to virtual MCParticle, 0 if Particle is related to non - virtual MCParticle, "
1028  "NaN if Particle is not related to MCParticle.")
1029  REGISTER_VARIABLE("mcInitial", particleMCInitialParticle,
1030  "Returns 1 if Particle is related to initial MCParticle, 0 if Particle is related to non - initial MCParticle, "
1031  "NaN if Particle is not related to MCParticle.")
1032  REGISTER_VARIABLE("mcISR", particleMCISRParticle,
1033  "Returns 1 if Particle is related to ISR MCParticle, 0 if Particle is related to non - ISR MCParticle, "
1034  "NaN if Particle is not related to MCParticle.")
1035  REGISTER_VARIABLE("mcFSR", particleMCFSRParticle,
1036  "Returns 1 if Particle is related to FSR MCParticle, 0 if Particle is related to non - FSR MCParticle ,"
1037  "NaN if Particle is not related to MCParticle.")
1038  REGISTER_VARIABLE("mcPhotos", particleMCPhotosParticle,
1039  "Returns 1 if Particle is related to Photos MCParticle, 0 if Particle is related to non - Photos MCParticle, "
1040  "NaN if Particle is not related to MCParticle.")
1041  REGISTER_VARIABLE("generatorEventWeight", generatorEventWeight,
1042  "[Eventbased] Returns the event weight produced by the event generator")
1043 
1044  REGISTER_VARIABLE("genNStepsToDaughter(i)", genNStepsToDaughter,
1045  "Returns number of steps to i-th daughter from the particle at generator level. "
1046  "NaN if no MCParticle is associated to the particle or i-th daughter. "
1047  "NaN if i-th daughter does not exist.");
1048  REGISTER_VARIABLE("genNMissingDaughter(PDG)", genNMissingDaughter,
1049  "Returns the number of missing daughters having assigned PDG codes. "
1050  "NaN if no MCParticle is associated to the particle.");
1051  REGISTER_VARIABLE("Eher", getHEREnergy, R"DOC(
1052 [Eventbased] The nominal HER energy used by the generator.
1053 
1054 .. warning:: This variable does not make sense for data.
1055 
1056 )DOC","GeV");
1057  REGISTER_VARIABLE("Eler", getLEREnergy, R"DOC(
1058 [Eventbased] The nominal LER energy used by the generator.
1059 
1060 .. warning:: This variable does not make sense for data.
1061 
1062 )DOC","GeV");
1063  REGISTER_VARIABLE("XAngle", getCrossingAngleX, R"DOC(
1064 [Eventbased] The nominal beam crossing angle in the x-z plane from generator level beam kinematics.
1065 
1066 .. warning:: This variable does not make sense for data.
1067 
1068 )DOC","rad");
1069  REGISTER_VARIABLE("YAngle", getCrossingAngleY, R"DOC(
1070 [Eventbased] The nominal beam crossing angle in the y-z plane from generator level beam kinematics.
1071 
1072 .. warning:: This variable does not make sense for data.
1073 
1074 )DOC","rad");
1075 
1076  VARIABLE_GROUP("Generated tau decay information");
1077  REGISTER_VARIABLE("tauPlusMCMode", tauPlusMcMode,
1078  "[Eventbased] Decay ID for the positive tau lepton in a tau pair generated event.");
1079  REGISTER_VARIABLE("tauMinusMCMode", tauMinusMcMode,
1080  "[Eventbased] Decay ID for the negative tau lepton in a tau pair generated event.");
1081  REGISTER_VARIABLE("tauPlusMCProng", tauPlusMcProng,
1082  "[Eventbased] Prong for the positive tau lepton in a tau pair generated event.");
1083  REGISTER_VARIABLE("tauMinusMCProng", tauMinusMcProng,
1084  "[Eventbased] Prong for the negative tau lepton in a tau pair generated event.");
1085 
1086  VARIABLE_GROUP("MC particle seen in subdetectors");
1087  REGISTER_VARIABLE("isReconstructible", isReconstructible,
1088  "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.");
1089  REGISTER_VARIABLE("seenInPXD", seenInPXD,
1090  "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.");
1091  REGISTER_VARIABLE("isTrackFound", isTrackFound,
1092  "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.");
1093  REGISTER_VARIABLE("seenInSVD", seenInSVD,
1094  "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.");
1095  REGISTER_VARIABLE("seenInCDC", seenInCDC,
1096  "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.");
1097  REGISTER_VARIABLE("seenInTOP", seenInTOP,
1098  "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.");
1099  REGISTER_VARIABLE("seenInECL", seenInECL,
1100  "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.");
1101  REGISTER_VARIABLE("seenInARICH", seenInARICH,
1102  "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.");
1103  REGISTER_VARIABLE("seenInKLM", seenInKLM,
1104  "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.");
1105 
1106  VARIABLE_GROUP("MC Matching for ECLClusters");
1107  REGISTER_VARIABLE("clusterMCMatchWeight", particleClusterMatchWeight,
1108  "Returns the weight of the ECLCluster -> MCParticle relation for the MCParticle matched to the particle. "
1109  "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. "
1110  "Returns -1 if the cluster *was* matched to particles, but not the match of the particle provided.");
1111  REGISTER_VARIABLE("clusterBestMCMatchWeight", particleClusterBestMCMatchWeight,
1112  "Returns the weight of the ECLCluster -> MCParticle relation for the relation with the largest weight.");
1113  REGISTER_VARIABLE("clusterBestMCPDG", particleClusterBestMCPDGCode,
1114  "Returns the PDG code of the MCParticle for the ECLCluster -> MCParticle relation with the largest weight.");
1115  REGISTER_VARIABLE("clusterTotalMCMatchWeight", particleClusterTotalMCMatchWeight,
1116  "Returns the sum of all weights of the ECLCluster -> MCParticles relations.");
1117 
1118  }
1120 }
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