ATLAS Offline Software
ElasticDecayUtil.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 #include "xAODTruth/TruthVertex.h"
5 #include <sstream>
6 #include "TruthUtils/HepMCHelpers.h"
7 
8 template <bool IsDebug>
9 const xAOD::TruthParticle *ElasticDecayUtil<IsDebug>::getMother(const xAOD::TruthParticle &truth_particle, float max_energy_loss) const {
10  // from ElasticTruthTrajectoryBuilder.cxx
11  // Restrict to quasi-elastic processes (e.g. brems, delta-rays, pi->pi+Delta).
12  //
13  // Require not more than 2 outgoing particles. Note that
14  // delta-rays for primary==electron is a special case, because we have two
15  // outgoing particles with the same PDG id. The "correct" one
16  // is that with the higher energy (NOT pt).
17  //
18  // allow 1 outgoing to cover possible vertexes from interaction in detector material
19  // disallow hadronic pi->N*pi etc.
20 
21  const xAOD::TruthParticle *last_parent = &truth_particle;
22 
23  typename std::conditional<IsDebug, unsigned int,Empty>::type stat_n_parents {};
24 
25  // follow decay chain upwards until PdgId changes, a particle has more than one
26  // parent, or a particle has more than one sibling.
27  for (;; ) {
28  const xAOD::TruthVertex* prod_vtx = last_parent->production_vertex();
29  if (!prod_vtx) break;
30  if (prod_vtx->nIncomingParticles() != 1) break;
31  if (prod_vtx->nOutgoingParticles() > 2) break;
32  const xAOD::TruthParticle *grand_parent = prod_vtx->incomingParticle(0u);
33  if (!grand_parent || !MC::isPhysical(grand_parent)) break;
34  if (grand_parent->pdgId() != last_parent->pdgId()) break;
35  if constexpr(IsDebug) {
36  unsigned int particle_type_i = kNoSibling;
37  std::lock_guard<std::mutex> lock(m_mutex);
38  if (prod_vtx->nOutgoingParticles()>1) {
39  int sibling_particle_type =0;
40  for (unsigned int part_out_i=0u; part_out_i<prod_vtx->nOutgoingParticles(); ++part_out_i) {
41  const xAOD::TruthParticle *a_sibling = prod_vtx->outgoingParticle(part_out_i);
42 
43  if (a_sibling != last_parent && a_sibling) {
44  if (particle_type_i == kNoSibling) {
45  sibling_particle_type = a_sibling->absPdgId();
46  if (sibling_particle_type==11) {
47  particle_type_i = kElectron;
48  }
49  else if (sibling_particle_type==22) {
50  particle_type_i = kPhoton;
51  }
52  else {
53  particle_type_i = kOther;
54  }
55  }
56  else if (sibling_particle_type != a_sibling->absPdgId() ) {
57  particle_type_i = kOther;
58  }
59  m_outgoingPdgIds.insert( a_sibling->pdgId() );
60  }
61  }
62  }
63 
64  m_energyLossStat.at(particle_type_i).add( grand_parent->e() - last_parent->e() );
65  }
66 
67  if (prod_vtx->nOutgoingParticles()>1) {
68  unsigned int part_out_i=0u;
69  for (; part_out_i<prod_vtx->nOutgoingParticles(); ++part_out_i) {
70  const xAOD::TruthParticle *a_sibling = prod_vtx->outgoingParticle(part_out_i);
71  if (a_sibling != last_parent) {
72  if (last_parent->pdgId() == a_sibling->pdgId() && (last_parent->pdgId() != 11 || last_parent->e() < a_sibling->e())) {
73  break;
74  }
75  }
76  }
77  if (part_out_i < prod_vtx->nOutgoingParticles()) break;
78  }
79  if (last_parent->e() - grand_parent->e() > max_energy_loss) break;
80 
81  if constexpr(IsDebug) {
82  m_outgoingMotherPdgIds.insert( grand_parent->pdgId() );
83  ++stat_n_parents;
84  }
85 
86  last_parent = grand_parent;
87  }
88  if constexpr(IsDebug) {
89  std::lock_guard<std::mutex> lock(m_mutex);
90  m_nParentsStat.add(stat_n_parents);
91  }
92  return last_parent;
93 }
94 
95 template <bool IsDebug>
96 inline void ElasticDecayUtil<IsDebug>::setEnergyLossBinning(const typename std::conditional<IsDebug,
97  std::vector<float>,
98  EmptyProperty>::type &binning) {
99  if constexpr(IsDebug) {
100  if (binning.size()>=3) {
101  for (ActsUtils::StatHist &stat : m_energyLossStat ) {
102  stat.setBinning( static_cast<unsigned int>(binning[0]), binning[1],binning[2]);
103  }
104  }
105  }
106 }
107 
108 template <bool IsDebug>
109 template <class T_OutStream>
110 inline void ElasticDecayUtil<IsDebug>::dumpStatistics(T_OutStream &out) const {
111  if constexpr(IsDebug) {
112  std::stringstream tmp_out;
113  tmp_out << m_nParentsStat << " number of parents" << std::endl
114  << m_nParentsStat.histogramToString() << std::endl;
115  std::array<std::string,kNParticleTypes> energyLossLabel{"no-sibling",
116  "electron as sibling",
117  "photon as sibling",
118  "other sibling"};
119 
120  unsigned int type_i=0;
121  for (const auto &stat : m_energyLossStat) {
122  if (stat.n()>0) {
123  tmp_out << stat << " energy loss, decay with " << energyLossLabel.at(type_i) << std::endl
124  << stat.histogramToString() << std::endl;
125  }
126  ++type_i;
127  }
128  tmp_out << "Sibling PDG IDs : ";
129  for(const auto &elm : m_outgoingPdgIds) {
130  tmp_out << " " << elm;
131  }
132  tmp_out << std::endl;
133  tmp_out << "PDG IDs of followed particles : ";
134  for(const auto &elm : m_outgoingMotherPdgIds) {
135  tmp_out << " " << elm;
136  }
137  tmp_out << std::endl;
138  out << tmp_out.str();
139  }
140 }