ATLAS Offline Software
Loading...
Searching...
No Matches
TruthClassificationTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include <set>
6
11
14
15namespace
16{
17 bool isInSet(int origin, const std::set<int> &s)
18 {
19 return s.find(origin) != s.end();
20 }
21}
22
23
25 : asg::AsgTool(type)
26{
27 declareProperty ("separateChargeFlipElectrons", m_separateChargeFlipElectrons, "separate prompt charge-flipped electrons");
28 declareProperty ("separateChargeFlipMuons", m_separateChargeFlipMuons, "separate prompt charge-flipped muons");
29 declareProperty ("useTruthParticleDecorations", m_useTruthParticleDecorations, "use truth particle decorations");
30}
31
32
34 unsigned int &classification) const
35{
36 Truth::Type type = Truth::Type::Unknown;
37 ANA_CHECK(classify(particle, type));
38 classification = static_cast<int>(type);
39 return StatusCode::SUCCESS;
40}
41
42
44 Truth::Type &classification) const
45{
46 const xAOD::TruthParticle *truthParticle = dynamic_cast<const xAOD::TruthParticle *> (&particle);
47 if (dynamic_cast<const xAOD::Electron *> (&particle) || (truthParticle != nullptr && MC::isElectron(truthParticle)))
48 {
49 ANA_CHECK(classifyElectron(particle, classification));
50 }
51 else if (dynamic_cast<const xAOD::Muon *> (&particle) || (truthParticle != nullptr && MC::isMuon(truthParticle)))
52 {
53 ANA_CHECK(classifyMuon(particle, classification));
54 }
55 else
56 {
57 ANA_MSG_ERROR("Only electrons and muons are supported.");
58 return StatusCode::FAILURE;
59 }
60
61 return StatusCode::SUCCESS;
62}
63
64
66 Truth::Type &classification) const
67{
68
69
70 // Check if xAOD::TruthParticle or if not if it has the TruthParticleLink
71 const xAOD::TruthParticle *truthParticle = dynamic_cast<const xAOD::TruthParticle *> (&electron);
72 bool isTruthParticle{};
73 if (truthParticle == nullptr)
74 {
75 // need to find the truth particle
76 truthParticle = xAOD::TruthHelpers::getTruthParticle(electron);
77 }
78 else
79 {
80 isTruthParticle = true;
81 }
82
83 if (!m_truthPdgId.isAvailable(electron) && !isTruthParticle)
84 {
85 ANA_MSG_ERROR("Electron does not have the 'truthPdgId' decoration.");
86 return StatusCode::FAILURE;
87 }
88
89 if (!m_firstMotherTruthType.isAvailable(electron)
90 || !m_firstMotherTruthOrigin.isAvailable(electron)
91 || !m_firstMotherPdgId.isAvailable(electron))
92 {
93 ANA_MSG_ERROR("Electron does not have one or more 'firstEgMother' decorations.");
94 return StatusCode::FAILURE;
95 }
96
97 int type = isTruthParticle ? m_classifierParticleType(electron) : m_truthType(electron);
98 int origin = isTruthParticle ? m_classifierParticleOrigin(electron) : m_truthOrigin(electron);
99 int pdgId = isTruthParticle ? truthParticle->pdgId() : m_truthPdgId(electron);
100 if (m_useTruthParticleDecorations && !isTruthParticle)
101 {
102 type = m_classifierParticleType(*truthParticle);
103 origin = m_classifierParticleOrigin(*truthParticle);
104 }
105
106 int firstMotherType = m_firstMotherTruthType(electron);
107 int firstMotherOrigin = m_firstMotherTruthOrigin(electron);
108 int firstMotherPdgId = m_firstMotherPdgId(electron);
109 // not in the smart slimming list, thus only in few derivations
110 int lastMotherType = m_lastMotherTruthType.isAvailable(electron) ? m_lastMotherTruthType(electron) : -1;
111 int lastMotherOrigin = m_lastMotherTruthOrigin.isAvailable(electron) ? m_lastMotherTruthOrigin(electron) : -1;
112 int lastMotherPdgId = m_lastMotherPdgId.isAvailable(electron) ? m_lastMotherPdgId(electron) : -1;
113 // fallback recorations
114 int fallbackType{-1};
115 if (m_fallbackTruthType.isAvailable(electron) && m_fallbackDR.isAvailable(electron))
116 {
117 fallbackType = m_fallbackDR(electron) < 0.05 ? m_fallbackTruthType(electron) : -1;
118 }
119
120 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
121 // Prompt Photon Conversions
122 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
123
124 // gamma -> e+ e-
127 && firstMotherType == MCTruthPartClassifier::IsoPhoton && firstMotherOrigin == MCTruthPartClassifier::PromptPhot)
128 {
129 classification = Truth::Type::PromptPhotonConversion;
130 return StatusCode::SUCCESS;
131 }
132
133 // H -> gamma gamma, gamma -> e+ e-
135 && firstMotherType == MCTruthPartClassifier::IsoPhoton && firstMotherOrigin == MCTruthPartClassifier::Higgs)
136 {
137 classification = Truth::Type::PromptPhotonConversion;
138 return StatusCode::SUCCESS;
139 }
140
141 // bkg electrons from bkg photons
143 && firstMotherType == MCTruthPartClassifier::UnknownPhoton && firstMotherOrigin == MCTruthPartClassifier::NonDefined)
144 {
145 classification = Truth::Type::PromptPhotonConversion;
146 return StatusCode::SUCCESS;
147 }
148
149 // bkg photon from UndrPhot; (Here there is a generator level photon (not gen electron ) that later converts)
152 && firstMotherType == MCTruthPartClassifier::BkgPhoton && firstMotherOrigin == MCTruthPartClassifier::UndrPhot)
153 {
154 classification = Truth::Type::PromptPhotonConversion;
155 return StatusCode::SUCCESS;
156 }
157
158 // type = 16 and origin = 38 (again, this is a photon)
160 {
161 classification = Truth::Type::PromptPhotonConversion;
162 return StatusCode::SUCCESS;
163 }
164
165 // Is an isolated photon
166 if (type == MCTruthPartClassifier::IsoPhoton && pdgId == 22)
167 {
168 classification = Truth::Type::PromptPhotonConversion;
169 return StatusCode::SUCCESS;
170 }
171
172 // electrons from ElMagProc
173 // when FSR, a better classification can be made with the fall back vars
175 && firstMotherType == MCTruthPartClassifier::UnknownPhoton && firstMotherOrigin == MCTruthPartClassifier::NonDefined)
176 {
177 classification = Truth::Type::PromptPhotonConversion;
178 return StatusCode::SUCCESS;
179 }
181 && firstMotherType == MCTruthPartClassifier::NonIsoPhoton && firstMotherOrigin == MCTruthPartClassifier::FSRPhot)
182 {
183 classification = Truth::Type::PromptPhotonConversion;
184 return StatusCode::SUCCESS;
185 }
186
187 // TODO: Message from Otilia: """
188 // but it's not clear if these electrons are really
189 // "fakes" or they should go in the real category (we don't know from where
190 // this photon is coming...). I would say more truth studies should be done.
191 // """
192 // Hence the warning message...
194 && firstMotherType == MCTruthPartClassifier::Unknown && firstMotherOrigin == MCTruthPartClassifier::ZBoson)
195 {
196 ANA_MSG_WARNING("Electron identified as from a PromptPhotonConversion, "
197 "but this type of electron needs further study!");
198 classification = Truth::Type::PromptPhotonConversion;
199 return StatusCode::SUCCESS;
200 }
201
202 // when always a photon (last mum is a photon, even if the truth PDG is 11 and first mum PDG is 11 ):
203 // very likely these are internal conversions; last_mum_pdgId == 22 important as the cases with last_mum_pdgId == 11 were found to be quite often close to a true electron
206 && std::abs(firstMotherPdgId) == 11 && std::abs(pdgId) == 11)
207 { // electron
208 if(lastMotherType == -1 || (lastMotherType == MCTruthPartClassifier::GenParticle && (lastMotherPdgId == 22 || std::abs(lastMotherPdgId) == 11)))
209 {
210 // lastMotherType == -1 ==> when the last mother info is not stored in the derivations
211 classification = Truth::Type::PromptPhotonConversion;
212 return StatusCode::SUCCESS;
213 }
214 }
215
216
217 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
218 // Is muon reco as electron or ele radiated by muons
219 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
220
222 && (origin == MCTruthPartClassifier::Mu || firstMotherOrigin == MCTruthPartClassifier::Mu))
223 {
224 classification = Truth::Type::ElectronFromMuon;
225 return StatusCode::SUCCESS;
226 }
227
229 {
230 classification = Truth::Type::ElectronFromMuon;
231 return StatusCode::SUCCESS;
232 }
233
235 classification = Truth::Type::ElectronFromMuon;
236 return StatusCode::SUCCESS;
237 }
238
239
240 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
241 // Tau decays
242 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
243
244 // Non-isolated electron/photon from tau decay
247 {
248 classification = Truth::Type::TauDecay;
249 return StatusCode::SUCCESS;
250 }
251
252 // tau -> tau gamma, gamma -> e+ e-, etc
253 if ((firstMotherType == MCTruthPartClassifier::NonIsoElectron || firstMotherType == MCTruthPartClassifier::NonIsoPhoton)
254 && firstMotherOrigin == MCTruthPartClassifier::TauLep)
255 {
256 classification = Truth::Type::TauDecay;
257 return StatusCode::SUCCESS;
258 }
259
260
261 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
262 // Light hadron sources
263 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
264
266 {
267 classification = Truth::Type::LightFlavorDecay;
268 return StatusCode::SUCCESS;
269 }
270
271 if (firstMotherType == MCTruthPartClassifier::BkgElectron)
272 {
274 && (hasLightHadronOrigin(origin) || hasLightHadronOrigin(firstMotherOrigin)))
275 {
276 classification = Truth::Type::LightFlavorDecay;
277 return StatusCode::SUCCESS;
278 }
279 }
280
282 {
283 if (origin == MCTruthPartClassifier::DalitzDec || firstMotherOrigin == MCTruthPartClassifier::DalitzDec) {
284 classification = Truth::Type::LightFlavorDecay;
285 return StatusCode::SUCCESS;
286 }
287 if (hasLightHadronOrigin(origin) || hasLightHadronOrigin(firstMotherOrigin)) {
288 classification = Truth::Type::LightFlavorDecay;
289 return StatusCode::SUCCESS;
290 }
291 }
292
294 && (hasLightHadronOrigin(origin) || hasLightHadronOrigin(firstMotherOrigin)))
295 {
296 classification = Truth::Type::LightFlavorDecay;
297 return StatusCode::SUCCESS;
298 }
299
300
301 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
302 // From B hadron
303 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
304
305 if (hasBHadronOrigin(origin) || hasBHadronOrigin(firstMotherOrigin))
306 {
307 classification = Truth::Type::BHadronDecay;
308 return StatusCode::SUCCESS;
309 }
310
311 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
312 // From C hadron
313 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
314
315 if (type != MCTruthPartClassifier::IsoElectron && (hasCHadronOrigin(origin) || hasCHadronOrigin(firstMotherOrigin)))
316 {
317 classification = Truth::Type::CHadronDecay;
318 return StatusCode::SUCCESS;
319 }
320
321
322 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
323 // Prompt / Isolated electrons
324 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
325
326 if (isPromptElectron(electron, isTruthParticle, truthParticle))
327 {
328 if (m_separateChargeFlipElectrons && isChargeFlipElectron(electron, isTruthParticle, truthParticle))
329 {
330 classification = Truth::Type::ChargeFlipIsoElectron;
331 return StatusCode::SUCCESS;
332 }
333
334 classification = Truth::Type::IsoElectron;
335 return StatusCode::SUCCESS;
336 }
337
338
339 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
340 // Unknown & known Unknown
341 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
342
343 // TODO: See if we want this or not. Now we check if this is something we are
344 // able to classify or not. Note that this might be a bit dangerous because
345 // the reasons for not having origin and status codes might be complex. The
346 // main idea is to weed out things we don't have a hope of classifying due to
347 // missing or unknown information.
348 static const SG::ConstAccessor<int> statusAcc("status");
349 bool stable = (truthParticle != nullptr && statusAcc.isAvailable(*truthParticle)) ? MC::isStable(truthParticle) : false;
350
351
352 if (origin == MCTruthPartClassifier::NonDefined && firstMotherOrigin == MCTruthPartClassifier::NonDefined)
353 {
354 if (!stable)
355 {
357 {
358 classification = Truth::Type::KnownUnknown;
359 return StatusCode::SUCCESS;
360 }
361 } else {
364 {
365 classification = Truth::Type::KnownUnknown;
366 return StatusCode::SUCCESS;
367 }
368
370 {
371 classification = Truth::Type::KnownUnknown;
372 return StatusCode::SUCCESS;
373 }
374 }
375 }
376
377 // non-iso photons with no info available to classify
379 && firstMotherType == 0 && firstMotherOrigin == 0 && firstMotherPdgId == 0)
380 {
381 if (lastMotherType == -1 || (lastMotherType == 0 && lastMotherOrigin == 0 && lastMotherPdgId == 0))
382 { // last_firstMotherType == -1 ==> when the last_mum info is not stored in the derivations
383 classification = Truth::Type::KnownUnknown;
384 return StatusCode::SUCCESS;
385 }
386 }
387
388 ANA_MSG_WARNING("Electron type unknown: type = " << type << ", origin = " << origin);
389
390 // debug printout
391 if (truthParticle != nullptr)
392 {
393 const xAOD::TruthParticle *parent = truthParticle;
394 ATH_MSG_DEBUG("Unknown particle decay chain (approximate):");
395 std::string out = "\t";
396 while (parent != nullptr)
397 {
398 out.append(std::to_string(parent->pdgId()));
399 parent = parent->parent(0); //AV: Note the ambiguity: only the first particle is considered.
400 if (parent) out.append(" -> ");
401 }
402 ATH_MSG_DEBUG(out);
403 }
404
405 classification = Truth::Type::Unknown;
406 return StatusCode::SUCCESS;
407}
408
409
411 Truth::Type &classification) const
412{
413
414
415 // Check if xAOD::TruthParticle or if not if it has the TruthParticleLink
416 const xAOD::TruthParticle *truthParticle
417 = dynamic_cast<const xAOD::TruthParticle *> (&muon);
418 bool isTruthParticle{};
419 if (truthParticle == nullptr)
420 {
421 // need to find the truth particle
422 truthParticle = xAOD::TruthHelpers::getTruthParticle(muon);
423 }
424 else
425 {
426 isTruthParticle = true;
427 }
428
429 int type = isTruthParticle ? m_classifierParticleType(muon) : m_truthType(muon);
430 int origin = isTruthParticle ? m_classifierParticleOrigin(muon) : m_truthOrigin(muon);
431 if (m_useTruthParticleDecorations && !isTruthParticle && truthParticle != nullptr)
432 {
433 type = m_classifierParticleType(*truthParticle);
434 origin = m_classifierParticleOrigin(*truthParticle);
435 }
436
437 // fallback recorations
438 int fallbackType{-1};
439 if (m_fallbackTruthType.isAvailable(muon) && m_fallbackDR.isAvailable(muon))
440 {
441 fallbackType = m_fallbackDR(muon) < 0.05 ? m_fallbackTruthType(muon) : -1;
442 }
443
444 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
445 // muons from taus
446 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
447
449 {
450 classification = Truth::Type::TauDecay;
451 return StatusCode::SUCCESS;
452 }
453
454
455 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
456 // Light hadron sources
457 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
458
460 {
461 classification = Truth::Type::LightFlavorDecay;
462 return StatusCode::SUCCESS;
463 }
464
466 {
467 classification = Truth::Type::LightFlavorDecay;
468 return StatusCode::SUCCESS;
469 }
470
471
472 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
473 // From B hadron
474 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
475
476 if (hasBHadronOrigin(origin))
477 {
478 classification = Truth::Type::BHadronDecay;
479 return StatusCode::SUCCESS;
480 }
481
482 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
483 // From C hadron
484 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
485
487 {
488 classification = Truth::Type::CHadronDecay;
489 return StatusCode::SUCCESS;
490 }
491 // TODO:: There is a comment in the example code about J/psi but there is a
492 // separate origin code for that: `MCTruthPartClassifier::JPsi == 28.` --> this might not be in all samples/generators?
493
494
495 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
496 // prompt muons
497 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
498 // Check if the type of muon is IsoMuon(6) and whether the origin
499 // of the muon is from a prompt source
500 static const std::set<int> promptOrigin({
501 MCTruthPartClassifier::SingleMuon, // Single muon (origin = 2) from muon twiki
509 MCTruthPartClassifier::CCbarMeson, // PromptQuarkoniumDecay
512 });
513 if (type == MCTruthPartClassifier::IsoMuon && isInSet(origin, promptOrigin))
514 {
515 //separate charge-flip muons
516 if (m_separateChargeFlipMuons && isChargeFlipMuon(muon, isTruthParticle, truthParticle))
517 {
518 classification = Truth::Type::ChargeFlipMuon;
519 return StatusCode::SUCCESS;
520 }
521 classification = Truth::Type::PromptMuon;
522 return StatusCode::SUCCESS;
523 }
524
525
526 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
527 // Known Unknown
528 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
529
531 {
532 classification = Truth::Type::KnownUnknown;
533 return StatusCode::SUCCESS;
534 }
535
536 static const SG::ConstAccessor<int> statusAcc("status");
537 bool stable = (truthParticle != nullptr && statusAcc.isAvailable(*truthParticle)) ? MC::isStable(truthParticle) : false;
538
539 if (!stable) {
541 { // Data
542 classification = Truth::Type::KnownUnknown;
543 return StatusCode::SUCCESS;
544 }
545 if (type == -99999 && origin == -99999)
546 { // MC - no status = 1 truth particle associated with the primary track
547 classification = Truth::Type::KnownUnknown;
548 return StatusCode::SUCCESS;
549 }
550 }
551
552 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
553 // NonMuonlike
554 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
555 // Check if the type of muon is related to electrons, ie IsoElectron (2) or NonIsoElectron (3) or BkgElectron (4)
557 {
558 classification = Truth::Type::NonMuonlike;
559 return StatusCode::SUCCESS;
560 }
561
562 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
563 // TauLike, BHadLike, CHadLike
564 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
565 // Check if the matched parent of truth muon fall into these 3 xxxLike
566 // Only truth muon with one matched parent is considered
567 // If parent is tau, the muons is TauLike
568 // If parent is bhadron/b quark, the muons is BHadLike
569 // If parent is chadron/c quark, the muons is CHadLike
571 if( truthParticle != nullptr && truthParticle->nParents() == 1 && truthParticle->parent(0) != nullptr){
572 const xAOD::TruthParticle *parent = truthParticle->parent(0);
573 int parent_pdgid = parent->pdgId();
574 if(parent->isTau()){
575 classification = Truth::Type::TauDecayLike;
576 ATH_MSG_WARNING("Muon type taudecaylike: type = " << type << ", origin = " << origin << ", parent = " << parent_pdgid) ;
577 return StatusCode::SUCCESS;
578 }
579 if(parent->isBottomHadron() || parent->hasBottom()){
580 classification = Truth::Type::BHadronDecayLike;
581 ATH_MSG_WARNING("Muon type bhadrondecaylike: type = " << type << ", origin = " << origin << ", parent = " << parent_pdgid) ;
582 return StatusCode::SUCCESS;
583 }
584 if(parent->isCharmHadron() || parent->hasCharm()){
585 if( (parent_pdgid / 1000) % 10 != 0 || (parent_pdgid / 100) % 10 != 4 || (parent_pdgid / 10) % 10 != 4){ // to exclude ccbarmeson
586 classification = Truth::Type::CHadronDecayLike;
587 ATH_MSG_WARNING("Muon type chadrondecaylike: type = " << type << ", origin = " << origin << ", parent = " << parent_pdgid) ;
588 return StatusCode::SUCCESS;
589 }
590 }
591 }
592 }
593
594 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
595 // Unknown
596 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
597 classification = Truth::Type::Unknown;
598 ATH_MSG_WARNING("Muon type unknown: type = " << type << ", origin = " << origin) ;
599
600 return StatusCode::SUCCESS;
602}
603
605 bool isTruthParticle,
606 const xAOD::TruthParticle *truthParticle) const
607{
608
609
610 int type = isTruthParticle ? m_classifierParticleType(electron) : m_truthType(electron);
611 int origin = isTruthParticle ? m_classifierParticleOrigin(electron) : m_truthOrigin(electron);
612 if (m_useTruthParticleDecorations && !isTruthParticle && truthParticle != nullptr)
613 {
614 type = m_classifierParticleType(*truthParticle);
615 origin = m_classifierParticleOrigin(*truthParticle);
616 }
617
618 // Electron is IsoElectron - return true
620 {
621 return true;
622 }
623
624 int pdgId = isTruthParticle ? truthParticle->pdgId() : m_truthPdgId(electron);
625 int firstMotherType = m_firstMotherTruthType(electron);
626 int firstMotherOrigin = m_firstMotherTruthOrigin(electron);
627
628 // Adding these cases from ElectronEfficiencyHelpers
629 if (firstMotherType == MCTruthPartClassifier::IsoElectron && std::abs(m_firstMotherPdgId(electron)) == 11)
630 {
631 return true;
632 }
633
634 // FSR photons from electrons
635 if (origin == MCTruthPartClassifier::FSRPhot && type == MCTruthPartClassifier::NonIsoPhoton && std::abs(pdgId) == 11)
636 {
637 return true;
638 }
639
641 && firstMotherType == MCTruthPartClassifier::NonIsoPhoton && firstMotherOrigin == MCTruthPartClassifier::FSRPhot
642 && std::abs(pdgId) == 11)
643 {
644 return true;
645 }
646
647 // If we reach here then it is not a prompt electron
648 return false;
649}
650
651
653 bool isTruthParticle,
654 const xAOD::TruthParticle *truthParticle) const
655{
656
657
658 int type = isTruthParticle ? m_classifierParticleType(electron) : m_truthType(electron);
659 int origin = isTruthParticle ? m_classifierParticleOrigin(electron) : m_truthOrigin(electron);
660 int pdgId = isTruthParticle && truthParticle ? truthParticle->pdgId() : m_truthPdgId(electron);
661 if (m_useTruthParticleDecorations && !isTruthParticle && truthParticle != nullptr)
662 {
663 type = m_classifierParticleType(*truthParticle);
664 origin = m_classifierParticleOrigin(*truthParticle);
665 }
666
667 int firstMotherType = m_firstMotherTruthType(electron);
668 int firstMotherOrigin = m_firstMotherTruthOrigin(electron);
669 int firstMotherPdgId = m_firstMotherPdgId(electron);
670
671 // not consider FSR photons from electrons (the photon has no charge)
672 if (origin == MCTruthPartClassifier::FSRPhot && type == MCTruthPartClassifier::NonIsoPhoton && std::abs(pdgId) == 11)
673 {
674 return false;
675 }
677 && firstMotherType == MCTruthPartClassifier::NonIsoPhoton && firstMotherOrigin == MCTruthPartClassifier::FSRPhot
678 && std::abs(pdgId) == 11)
679 {
680 return false;
681 }
682
683 // bkg electrons with no additional info to help us classify them FSR -- not in the charge flip category
685 && firstMotherType == MCTruthPartClassifier::BkgElectron && firstMotherOrigin == MCTruthPartClassifier::PhotonConv
686 && std::abs(pdgId) == 11)
687 {
688 return false;
689 }
690
691 if (isTruthParticle)
692 {
693 if (truthParticle->charge() != 0)
694 {
695 return (firstMotherPdgId * truthParticle->charge()) > 0;
696 }
697 }
698 else
699 {
700 const xAOD::Electron &xAODElectron = *dynamic_cast<const xAOD::Electron *> (&electron);
701 if (xAODElectron.charge() != 0)
702 {
703 return (firstMotherPdgId * xAODElectron.charge()) > 0;
704 }
705 }
706
707 return (firstMotherPdgId * (-pdgId)) > 0;
708}
709
710
712 bool isTruthParticle,
713 const xAOD::TruthParticle *truthParticle) const
714{
715 if (isTruthParticle)
716 {
717 return false;
718 }
719
720 if (truthParticle != nullptr && xAOD::P4Helpers::isInDeltaR(*truthParticle, muon, 0.025))
721 {
722 const xAOD::Muon &xAODMuon = *dynamic_cast<const xAOD::Muon *> (&muon);
723 return (truthParticle->charge() * xAODMuon.charge()) < 0;
724 }
725
726 ANA_MSG_DEBUG("Cannot find associated truth-particle... assuming muon has correct charge");
727 return false;
728}
729
730
732{
733 static const std::set<int> b_hadrons({
737 });
738 return isInSet(origin, b_hadrons);
739}
740
741
743 static const std::set<int> c_hadrons({
747 });
748 return isInSet(origin, c_hadrons);
749}
750
751
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define ANA_MSG_ERROR(xmsg)
Macro printing error messages.
#define ANA_MSG_WARNING(xmsg)
Macro printing warning messages.
#define ANA_MSG_DEBUG(xmsg)
Macro printing debug messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
ATLAS-specific HepMC functions.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
Helper class to provide constant type-safe access to aux data.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
bool m_separateChargeFlipElectrons
separately store charge-flip electrons/muons
const SG::AuxElement::ConstAccessor< int > m_lastMotherTruthOrigin
StatusCode classifyElectron(const xAOD::IParticle &electron, Truth::Type &classification) const
electron classification helper
const SG::AuxElement::ConstAccessor< int > m_lastMotherTruthType
const SG::AuxElement::ConstAccessor< int > m_truthPdgId
bool hasCHadronOrigin(int origin) const
a helper to check if the origin is a c-hadron
const SG::AuxElement::ConstAccessor< int > m_truthOrigin
StatusCode classifyMuon(const xAOD::IParticle &muon, Truth::Type &classification) const
muon classification helper
virtual StatusCode classify(const xAOD::IParticle &particle, unsigned int &classification) const override
classify and return unsigned int
const SG::AuxElement::ConstAccessor< float > m_fallbackDR
bool isChargeFlipElectron(const xAOD::IParticle &electron, bool isTruthParticle, const xAOD::TruthParticle *truthParticle) const
a helper to check if an electron has an incorrectly reconstructed charge
bool hasBHadronOrigin(int origin) const
a helper to check if the origin is a b-hadron
TruthClassificationTool(const std::string &type)
bool isPromptElectron(const xAOD::IParticle &electron, bool isTruthParticle, const xAOD::TruthParticle *truthParticle) const
a helper to check if an electron is prompt
const SG::AuxElement::ConstAccessor< int > m_firstMotherPdgId
bool isChargeFlipMuon(const xAOD::IParticle &muon, bool isTruthParticle, const xAOD::TruthParticle *truthParticle) const
a helper to check if a muon has an incorrectly reconstructed charge
const SG::AuxElement::ConstAccessor< int > m_firstMotherTruthOrigin
const SG::AuxElement::ConstAccessor< unsigned int > m_classifierParticleOrigin
const SG::AuxElement::ConstAccessor< int > m_firstMotherTruthType
bool hasLightHadronOrigin(int origin) const
a helper to check if the origin is a light hadron
bool m_useTruthParticleDecorations
use truth particle decorations
const SG::AuxElement::ConstAccessor< int > m_truthType
const SG::AuxElement::ConstAccessor< int > m_fallbackTruthType
const SG::AuxElement::ConstAccessor< int > m_lastMotherPdgId
const SG::AuxElement::ConstAccessor< unsigned int > m_classifierParticleType
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
float charge() const
Obtain the charge of the object.
Class providing the definition of the 4-vector interface.
float charge() const
int pdgId() const
PDG ID code.
const TruthParticle_v1 * parent(size_t i) const
Retrieve the i-th mother (TruthParticle) of this TruthParticle.
double charge() const
Physical charge.
size_t nParents() const
Number of parents of this particle.
bool isElectron(const T &p)
bool isStable(const T &p)
Identify if the particle is stable, i.e. has not decayed.
bool isMuon(const T &p)
Type
truth classification type enum
bool isInDeltaR(const xAOD::IParticle &p1, const xAOD::IParticle &p2, double dR, bool useRapidity=true)
Check if 2 xAOD::IParticle are in a cone.
const xAOD::TruthParticle * getTruthParticle(const xAOD::IParticle &p)
Return the truthParticle associated to the given IParticle (if any)
TruthParticle_v1 TruthParticle
Typedef to implementation.
Muon_v1 Muon
Reference the current persistent version:
Electron_v1 Electron
Definition of the current "egamma version".