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