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