2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
4 #include "xAODTruth/TruthVertex.h"
6 #include "TruthUtils/HepMCHelpers.h"
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).
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).
18 // allow 1 outgoing to cover possible vertexes from interaction in detector material
19 // disallow hadronic pi->N*pi etc.
21 const xAOD::TruthParticle *last_parent = &truth_particle;
23 typename std::conditional<IsDebug, unsigned int,Empty>::type stat_n_parents {};
25 // follow decay chain upwards until PdgId changes, a particle has more than one
26 // parent, or a particle has more than one sibling.
28 const xAOD::TruthVertex* prod_vtx = last_parent->production_vertex();
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);
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;
49 else if (sibling_particle_type==22) {
50 particle_type_i = kPhoton;
53 particle_type_i = kOther;
56 else if (sibling_particle_type != a_sibling->absPdgId() ) {
57 particle_type_i = kOther;
59 m_outgoingPdgIds.insert( a_sibling->pdgId() );
64 m_energyLossStat.at(particle_type_i).add( grand_parent->e() - last_parent->e() );
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())) {
77 if (part_out_i < prod_vtx->nOutgoingParticles()) break;
79 if (last_parent->e() - grand_parent->e() > max_energy_loss) break;
81 if constexpr(IsDebug) {
82 m_outgoingMotherPdgIds.insert( grand_parent->pdgId() );
86 last_parent = grand_parent;
88 if constexpr(IsDebug) {
89 std::lock_guard<std::mutex> lock(m_mutex);
90 m_nParentsStat.add(stat_n_parents);
95 template <bool IsDebug>
96 inline void ElasticDecayUtil<IsDebug>::setEnergyLossBinning(const typename std::conditional<IsDebug,
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]);
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",
120 unsigned int type_i=0;
121 for (const auto &stat : m_energyLossStat) {
123 tmp_out << stat << " energy loss, decay with " << energyLossLabel.at(type_i) << std::endl
124 << stat.histogramToString() << std::endl;
128 tmp_out << "Sibling PDG IDs : ";
129 for(const auto &elm : m_outgoingPdgIds) {
130 tmp_out << " " << elm;
132 tmp_out << std::endl;
133 tmp_out << "PDG IDs of followed particles : ";
134 for(const auto &elm : m_outgoingMotherPdgIds) {
135 tmp_out << " " << elm;
137 tmp_out << std::endl;
138 out << tmp_out.str();