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();