ATLAS Offline Software
Loading...
Searching...
No Matches
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
8template <bool IsDebug>
9const 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
95template <bool IsDebug>
96inline 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
108template <bool IsDebug>
109template <class T_OutStream>
110inline 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}