ATLAS Offline Software
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 
15 namespace
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 {
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
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
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
205  && origin == MCTruthPartClassifier::PhotonConv && firstMotherOrigin == MCTruthPartClassifier::PhotonConv
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
246  && origin == MCTruthPartClassifier::TauLep)
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  {
356  if ((type == MCTruthPartClassifier::Unknown || type == MCTruthPartClassifier::UnknownPhoton) && firstMotherType == MCTruthPartClassifier::Unknown)
357  {
358  classification = Truth::Type::KnownUnknown;
359  return StatusCode::SUCCESS;
360  }
361  } else {
362  if ((type == MCTruthPartClassifier::Unknown && firstMotherType == MCTruthPartClassifier::Unknown)
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:");
395  std::string out = "\t";
396  while (parent != nullptr)
397  {
398  out.append(std::to_string(parent->pdgId()));
399  parent = parent->parent();
400  if (parent) out.append(" -> ");
401  }
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
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) {
540  if (type == MCTruthPartClassifier::Unknown && origin == MCTruthPartClassifier::NonDefined)
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)
556  if (type == MCTruthPartClassifier::IsoElectron || type == MCTruthPartClassifier::BkgElectron || type == MCTruthPartClassifier::NonIsoElectron)
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
570  if (type == MCTruthPartClassifier::Unknown && origin == MCTruthPartClassifier::NonDefined){
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
619  if (type == MCTruthPartClassifier::IsoElectron)
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 
753  static const std::set<int> light_source({
761  });
762  return isInSet(origin, light_source);
763 }
TruthClassificationTool::classifyElectron
StatusCode classifyElectron(const xAOD::IParticle &electron, Truth::Type &classification) const
electron classification helper
Definition: TruthClassificationTool.cxx:65
xAOD::TruthParticle_v1::parent
const TruthParticle_v1 * parent(size_t i=0) const
Retrieve the i-th mother (TruthParticle) of this TruthParticle.
Definition: TruthParticle_v1.cxx:131
xAOD::muon
@ muon
Definition: TrackingPrimitives.h:195
IsoPhoton
@ IsoPhoton
Definition: TruthClasses.h:23
Truth::Type::IsoElectron
@ IsoElectron
xAOD::Electron_v1::charge
float charge() const
Obtain the charge of the object.
Trk::ParticleSwitcher::particle
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses
Definition: ParticleHypothesis.h:76
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
TauLep
@ TauLep
Definition: TruthClasses.h:63
StrangeMeson
@ StrangeMeson
Definition: TruthClasses.h:80
Mu
@ Mu
Definition: TruthClasses.h:62
TruthClassificationTool::isChargeFlipElectron
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
Definition: TruthClassificationTool.cxx:652
BBbarMeson
@ BBbarMeson
Definition: TruthClasses.h:85
BottomMeson
@ BottomMeson
Definition: TruthClasses.h:82
Truth::Type::LightFlavorDecay
@ LightFlavorDecay
TruthClassificationTool::m_firstMotherTruthOrigin
const SG::AuxElement::ConstAccessor< int > m_firstMotherTruthOrigin
Definition: TruthClassificationTool.h:56
TruthClassificationTool::hasCHadronOrigin
bool hasCHadronOrigin(int origin) const
a helper to check if the origin is a c-hadron
Definition: TruthClassificationTool.cxx:742
NonIsoPhoton
@ NonIsoPhoton
Definition: TruthClasses.h:24
PionDecay
@ PionDecay
Definition: TruthClasses.h:90
xAODP4Helpers.h
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
TruthClassificationTool::isPromptElectron
bool isPromptElectron(const xAOD::IParticle &electron, bool isTruthParticle, const xAOD::TruthParticle *truthParticle) const
a helper to check if an electron is prompt
Definition: TruthClassificationTool.cxx:604
ElMagProc
@ ElMagProc
Definition: TruthClasses.h:61
asg
Definition: DataHandleTestTool.h:28
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:71
Truth::Type::TauDecayLike
@ TauDecayLike
BkgPhoton
@ BkgPhoton
Definition: TruthClasses.h:25
ANA_MSG_ERROR
#define ANA_MSG_ERROR(xmsg)
Macro printing error messages.
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:294
PhotonConv
@ PhotonConv
Definition: TruthClasses.h:59
ANA_CHECK
#define ANA_CHECK(EXP)
check whether the given expression was successful
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:324
PromptPhot
@ PromptPhot
Definition: TruthClasses.h:93
SG::ConstAccessor< int >
UnknownMuon
@ UnknownMuon
Definition: TruthClasses.h:14
ZBoson
@ ZBoson
Definition: TruthClasses.h:67
TruthClassificationTool::m_useTruthParticleDecorations
bool m_useTruthParticleDecorations
use truth particle decorations
Definition: TruthClassificationTool.h:47
Hadron
@ Hadron
Definition: TruthClasses.h:26
TruthClassificationTool::m_lastMotherTruthType
const SG::AuxElement::ConstAccessor< int > m_lastMotherTruthType
Definition: TruthClassificationTool.h:58
xAOD::IParticle
Class providing the definition of the 4-vector interface.
Definition: Event/xAOD/xAODBase/xAODBase/IParticle.h:40
TruthClassificationTool::m_separateChargeFlipElectrons
bool m_separateChargeFlipElectrons
separately store charge-flip electrons/muons
Definition: TruthClassificationTool.h:43
xAODTruthHelpers.h
Truth::Type::CHadronDecay
@ CHadronDecay
TruthClassificationTool::TruthClassificationTool
TruthClassificationTool(const std::string &type)
Definition: TruthClassificationTool.cxx:24
PowhegPy8EG_H2a.pdgId
dictionary pdgId
Definition: PowhegPy8EG_H2a.py:128
BkgMuon
@ BkgMuon
Definition: TruthClasses.h:17
xAOD::Muon_v1
Class describing a Muon.
Definition: Muon_v1.h:38
Truth::Type::BHadronDecayLike
@ BHadronDecayLike
WBoson
@ WBoson
Definition: TruthClasses.h:66
FSRPhot
@ FSRPhot
Definition: TruthClasses.h:96
xAOD::Muon_v1::charge
float charge() const
CCbarMeson
@ CCbarMeson
Definition: TruthClasses.h:83
NonDefined
@ NonDefined
Definition: TruthClasses.h:52
HiggsMSSM
@ HiggsMSSM
Definition: TruthClasses.h:69
MCTruthClassifierDefs.h
xAOD::TruthParticle_v1::nParents
size_t nParents() const
Number of parents of this particle.
Definition: TruthParticle_v1.cxx:122
TruthClassificationTool::m_truthOrigin
const SG::AuxElement::ConstAccessor< int > m_truthOrigin
Definition: TruthClassificationTool.h:51
CharmedBaryon
@ CharmedBaryon
Definition: TruthClasses.h:88
TruthClassificationTool::m_classifierParticleType
const SG::AuxElement::ConstAccessor< unsigned int > m_classifierParticleType
Definition: TruthClassificationTool.h:53
Truth::Type::TauDecay
@ TauDecay
TruthClassificationTool::hasLightHadronOrigin
bool hasLightHadronOrigin(int origin) const
a helper to check if the origin is a light hadron
Definition: TruthClassificationTool.cxx:752
Truth::Type::Unknown
@ Unknown
Truth::Type::ChargeFlipIsoElectron
@ ChargeFlipIsoElectron
UnknownElectron
@ UnknownElectron
Definition: TruthClasses.h:10
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
PiZero
@ PiZero
Definition: TruthClasses.h:98
xAOD::EgammaHelpers::isElectron
bool isElectron(const xAOD::Egamma *eg)
is the object an electron (not Fwd)
Definition: EgammaxAODHelpers.cxx:12
xAOD::TruthParticle_v1
Class describing a truth particle in the MC record.
Definition: TruthParticle_v1.h:41
StrangeBaryon
@ StrangeBaryon
Definition: TruthClasses.h:87
LightMeson
@ LightMeson
Definition: TruthClasses.h:79
ANA_MSG_WARNING
#define ANA_MSG_WARNING(xmsg)
Macro printing warning messages.
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:292
test_pyathena.parent
parent
Definition: test_pyathena.py:15
DiBoson
@ DiBoson
Definition: TruthClasses.h:99
MCTruthPartClassifier::stable
@ stable
Definition: TruthClassifiers.h:148
TruthClassificationTool::classifyMuon
StatusCode classifyMuon(const xAOD::IParticle &muon, Truth::Type &classification) const
muon classification helper
Definition: TruthClassificationTool.cxx:410
CharmedMeson
@ CharmedMeson
Definition: TruthClasses.h:81
TruthClassificationTool::m_firstMotherTruthType
const SG::AuxElement::ConstAccessor< int > m_firstMotherTruthType
Definition: TruthClassificationTool.h:55
IsoMuon
@ IsoMuon
Definition: TruthClasses.h:15
NonIsoMuon
@ NonIsoMuon
Definition: TruthClasses.h:16
Truth::Type::PromptPhotonConversion
@ PromptPhotonConversion
TruthClassificationTool::m_fallbackTruthType
const SG::AuxElement::ConstAccessor< int > m_fallbackTruthType
Definition: TruthClassificationTool.h:61
Truth::Type::BHadronDecay
@ BHadronDecay
Truth::Type::NonMuonlike
@ NonMuonlike
Truth::Type::KnownUnknown
@ KnownUnknown
Truth::Type::ElectronFromMuon
@ ElectronFromMuon
TruthClassificationTool::hasBHadronOrigin
bool hasBHadronOrigin(int origin) const
a helper to check if the origin is a b-hadron
Definition: TruthClassificationTool.cxx:731
TruthClassificationTool::m_firstMotherPdgId
const SG::AuxElement::ConstAccessor< int > m_firstMotherPdgId
Definition: TruthClassificationTool.h:57
TruthClassificationTool::m_lastMotherTruthOrigin
const SG::AuxElement::ConstAccessor< int > m_lastMotherTruthOrigin
Definition: TruthClassificationTool.h:59
ActsTrk::to_string
std::string to_string(const DetectorType &type)
Definition: GeometryDefs.h:34
xAOD::TruthHelpers::getTruthParticle
const xAOD::TruthParticle * getTruthParticle(const xAOD::IParticle &p)
Return the truthParticle associated to the given IParticle (if any)
Definition: xAODTruthHelpers.cxx:25
SUSY
@ SUSY
Definition: TruthClasses.h:77
HeavyBoson
@ HeavyBoson
Definition: TruthClasses.h:70
TruthClassificationTool::m_classifierParticleOrigin
const SG::AuxElement::ConstAccessor< unsigned int > m_classifierParticleOrigin
Definition: TruthClassificationTool.h:54
TruthClassificationTool.h
UndrPhot
@ UndrPhot
Definition: TruthClasses.h:94
xAOD::Electron_v1
Definition: Electron_v1.h:34
BottomBaryon
@ BottomBaryon
Definition: TruthClasses.h:89
LightBaryon
@ LightBaryon
Definition: TruthClasses.h:86
TruthClassificationTool::m_fallbackDR
const SG::AuxElement::ConstAccessor< float > m_fallbackDR
Definition: TruthClassificationTool.h:63
MC::isStable
bool isStable(const T &p)
Definition: HepMCHelpers.h:30
Truth::Type::CHadronDecayLike
@ CHadronDecayLike
TruthClassificationTool::isChargeFlipMuon
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
Definition: TruthClassificationTool.cxx:711
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
Higgs
@ Higgs
Definition: TruthClasses.h:68
xAOD::EgammaParameters::electron
@ electron
Definition: EgammaEnums.h:18
TruthClassificationTool::m_separateChargeFlipMuons
bool m_separateChargeFlipMuons
Definition: TruthClassificationTool.h:44
TruthClassificationTool::m_truthPdgId
const SG::AuxElement::ConstAccessor< int > m_truthPdgId
Definition: TruthClassificationTool.h:52
SingleMuon
@ SingleMuon
Definition: TruthClasses.h:55
TruthClassificationTool::m_lastMotherPdgId
const SG::AuxElement::ConstAccessor< int > m_lastMotherPdgId
Definition: TruthClassificationTool.h:60
SG::ConstAccessor::isAvailable
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
TruthClassificationTool::classify
virtual StatusCode classify(const xAOD::IParticle &particle, unsigned int &classification) const override
classify and return unsigned int
Definition: TruthClassificationTool.cxx:33
DalitzDec
@ DalitzDec
Definition: TruthClasses.h:60
top
@ top
Definition: TruthClasses.h:64
TruthClassificationTool::m_truthType
const SG::AuxElement::ConstAccessor< int > m_truthType
Definition: TruthClassificationTool.h:50
xAOD::P4Helpers::isInDeltaR
bool isInDeltaR(const xAOD::IParticle &p1, const xAOD::IParticle &p2, double dR, bool useRapidity=true)
Check if 2 xAOD::IParticle are in a cone.
Definition: xAODP4Helpers.h:174
TruthParticle.h
KaonDecay
@ KaonDecay
Definition: TruthClasses.h:91
xAOD::TruthParticle_v1::pdgId
int pdgId() const
PDG ID code.
Truth::Type::ChargeFlipMuon
@ ChargeFlipMuon
NonIsoElectron
@ NonIsoElectron
Definition: TruthClasses.h:12
BkgElectron
@ BkgElectron
Definition: TruthClasses.h:13
xAOD::TruthParticle_v1::charge
double charge() const
Physical charge.
Truth::Type::PromptMuon
@ PromptMuon
HepMCHelpers.h
UnknownPhoton
@ UnknownPhoton
Definition: TruthClasses.h:22
Truth::Type
Type
truth classification type enum
Definition: ITruthClassificationTool.h:19
GenParticle
@ GenParticle
Definition: TruthClasses.h:30
isMuon
bool isMuon(const T &p)
Definition: AtlasPID.h:145
ANA_MSG_DEBUG
#define ANA_MSG_DEBUG(xmsg)
Macro printing debug messages.
Definition: Control/AthToolSupport/AsgMessaging/AsgMessaging/MessageCheck.h:288