ATLAS Offline Software
Loading...
Searching...
No Matches
MC Namespace Reference

Namespaces

namespace  Pythia8

Classes

class  DecodedPID
 Implementation of classification functions according to PDG2022. More...
class  Loops

Functions

auto particles_in (const HepMC::GenVertex *p)
template<class VTX>
auto particles_in (const VTX *p)
template<class VTX>
auto particles_in (const std::shared_ptr< VTX > &p)
template<class T>
bool isQuark (const T &p)
 PDG rule 2: Quarks and leptons are numbered consecutively starting from 1 and 11 respectively; to do this they are first ordered by family and within families by weak isospin.
template<>
bool isQuark (const int &p)
template<>
bool isQuark (const DecodedPID &p)
template<class T>
bool isSMQuark (const T &p)
template<>
bool isSMQuark (const int &p)
template<>
bool isSMQuark (const DecodedPID &p)
template<class T>
bool isStrange (const T &p)
template<>
bool isStrange (const int &p)
template<class T>
bool isCharm (const T &p)
template<>
bool isCharm (const int &p)
template<class T>
bool isBottom (const T &p)
template<>
bool isBottom (const int &p)
template<class T>
bool isTop (const T &p)
template<>
bool isTop (const int &p)
template<class T>
bool isLepton (const T &p)
 APID: the fourth generation leptons are leptons.
template<>
bool isLepton (const int &p)
template<>
bool isLepton (const DecodedPID &p)
template<class T>
bool isSMLepton (const T &p)
 APID: the fourth generation leptons are not standard model leptons.
template<>
bool isSMLepton (const int &p)
template<>
bool isSMLepton (const DecodedPID &p)
template<class T>
bool isChLepton (const T &p)
 APID: the fourth generation leptons are leptons.
template<>
bool isChLepton (const int &p)
template<class T>
bool isElectron (const T &p)
template<>
bool isElectron (const int &p)
template<class T>
bool isMuon (const T &p)
template<>
bool isMuon (const int &p)
template<class T>
bool isTau (const T &p)
template<>
bool isTau (const int &p)
template<class T>
bool isNeutrino (const T &p)
 APID: the fourth generation neutrinos are neutrinos.
template<>
bool isNeutrino (const int &p)
template<class T>
bool isSMNeutrino (const T &p)
template<>
bool isSMNeutrino (const int &p)
template<class T>
bool isFourthGeneration (const T &p)
 Is this a 4th generation fermion?
template<>
bool isFourthGeneration (const int &p)
template<class T>
bool isDiquark (const T &p)
 PDG rule 4 Diquarks have 4-digit numbers with nq1 >= nq2 and nq3 = 0 APID: states with top quarks are diquarks APID: states with fourth generation quarks are not diquarks.
template<>
bool isDiquark (const DecodedPID &p)
template<>
bool isDiquark (const int &p)
template<class T>
bool isMeson (const T &p)
 Table 43.1 PDG rule 5a: The numbers specifying the meson’s quark content conform to the convention nq1= 0 and nq2 >= nq3.
template<>
bool isMeson (const DecodedPID &p)
template<>
bool isMeson (const int &p)
template<class T>
bool isQuarkonium (const T &p)
 Is this a heavy-flavour quarkonium meson?
template<>
bool isQuarkonium (const DecodedPID &p)
template<>
bool isQuarkonium (const int &p)
template<class T>
bool isBaryon (const T &p)
 Table 43.2 APID: states with fourth generation quarks are not baryons.
template<>
bool isBaryon (const DecodedPID &p)
template<>
bool isBaryon (const int &p)
template<class T>
bool isTetraquark (const T &p)
 PDG rule 14 The 9-digit tetra-quark codes are ±1nrnLnq1nq20nq3nq4nJ.
template<>
bool isTetraquark (const DecodedPID &p)
template<>
bool isTetraquark (const int &p)
template<class T>
bool isPentaquark (const T &p)
 PDG rule 15 The 9-digit penta-quark codes are ±1nrnLnq1nq2nq3nq4nq5nJ, sorted such that nq1≥nq2≥nq3≥nq4.
template<>
bool isPentaquark (const DecodedPID &p)
template<>
bool isPentaquark (const int &p)
template<class T>
bool isHadron (const T &p)
template<>
bool isHadron (const DecodedPID &p)
template<>
bool isHadron (const int &p)
template<class T>
bool isTrajectory (const T &p)
 PDG rule 8: The pomeron and odderon trajectories and a generic reggeon trajectory of states in QCD areassigned codes 990, 9990, and 110 respectively.
template<>
bool isTrajectory (const int &p)
template<class T>
bool isBoson (const T &p)
 PDG rule 9: Two-digit numbers in the range 21–30 are provided for the Standard Model gauge and Higgs bosons.
template<>
bool isBoson (const int &p)
template<>
bool isBoson (const DecodedPID &p)
template<class T>
bool isGluon (const T &p)
template<>
bool isGluon (const int &p)
template<class T>
bool isPhoton (const T &p)
template<>
bool isPhoton (const int &p)
template<class T>
bool isZ (const T &p)
template<>
bool isZ (const int &p)
template<class T>
bool isW (const T &p)
template<>
bool isW (const int &p)
template<class T>
bool isHeavyBoson (const T &p)
 APID: Additional "Heavy"/"prime" versions of W and Z bosons (Used in MCTruthClassifier)
template<>
bool isHeavyBoson (const int &p)
template<class T>
bool isHiggs (const T &p)
 APID: HIGGS boson is only one particle.
template<>
bool isHiggs (const int &p)
template<class T>
bool isMSSMHiggs (const T &p)
 APID: Additional Higgs bosons for MSSM (Used in MCTruthClassifier)
template<>
bool isMSSMHiggs (const int &p)
template<class T>
bool isGraviton (const T &p)
template<>
bool isGraviton (const int &p)
template<class T>
bool isResonance (const T &p)
template<class T>
bool isLeptoQuark (const T &p)
 PDG rule 11c: “One-of-a-kind” exotic particles are assigned numbers in the range 41–80.
template<>
bool isLeptoQuark (const int &p)
template<class T>
bool isPythia8Specific (const T &p)
template<>
bool isPythia8Specific (const DecodedPID &p)
template<>
bool isPythia8Specific (const int &p)
template<class T>
bool isNeutrinoRH (const T &p)
 PDG Rule 12: APID: Helper function for right-handed neutrino states These are generator defined PDG ID values for right handed neutrinos.
template<>
bool isNeutrinoRH (const int &p)
template<class T>
bool isGenSpecific (const T &p)
 Main Table for MC internal use 81–100,901–930,998-999,1901–1930,2901–2930, and 3901–3930.
template<>
bool isGenSpecific (const int &p)
template<class T>
bool isGeantino (const T &p)
template<>
bool isGeantino (const int &p)
template<class T>
bool isGlueball (const T &p)
 APID: Definition of Glueballs: SM glueballs 99X (X=1,5), 999Y (Y=3,7)
template<>
bool isGlueball (const DecodedPID &p)
template<>
bool isGlueball (const int &p)
template<class T>
bool isSquark (const T &p)
 PDG rule 11d Fundamental supersymmetric particles are identified by adding a nonzero n to the particle number.
template<>
bool isSquark (const DecodedPID &p)
template<>
bool isSquark (const int &p)
template<class T>
bool isSquarkLH (const T &p)
template<>
bool isSquarkLH (const DecodedPID &p)
template<>
bool isSquarkLH (const int &p)
template<class T>
bool isSquarkRH (const T &p)
template<>
bool isSquarkRH (const DecodedPID &p)
template<>
bool isSquarkRH (const int &p)
template<class T>
bool isSlepton (const T &p)
template<>
bool isSlepton (const DecodedPID &p)
template<>
bool isSlepton (const int &p)
template<class T>
bool isSleptonLH (const T &p)
template<>
bool isSleptonLH (const DecodedPID &p)
template<>
bool isSleptonLH (const int &p)
template<class T>
bool isSleptonRH (const T &p)
template<>
bool isSleptonRH (const DecodedPID &p)
template<>
bool isSleptonRH (const int &p)
template<class T>
bool isGaugino (const T &p)
template<>
bool isGaugino (const DecodedPID &p)
template<>
bool isGaugino (const int &p)
template<class T>
bool isSuperpartner (const T &p)
template<>
bool isSuperpartner (const DecodedPID &p)
template<>
bool isSuperpartner (const int &p)
template<class T>
bool isTechnicolor (const T &p)
 PDG rule 11e Technicolor states have n = 3, with technifermions treated like ordinary fermions.
template<>
bool isTechnicolor (const DecodedPID &p)
template<>
bool isTechnicolor (const int &p)
template<class T>
bool isExcited (const T &p)
 PDG rule 11f Excited (composite) quarks and leptons are identified by setting n= 4 and nr= 0.
template<>
bool isExcited (const DecodedPID &p)
template<>
bool isExcited (const int &p)
template<class T>
bool isRGlueball (const T &p)
 PDG rule 11g: Within several scenarios of new physics, it is possible to have colored particles sufficiently long-lived for color-singlet hadronic states to form around them.
template<>
bool isRGlueball (const DecodedPID &p)
template<>
bool isRGlueball (const int &p)
template<class T>
bool isRMeson (const T &p)
template<>
bool isRMeson (const DecodedPID &p)
template<>
bool isRMeson (const int &p)
template<class T>
bool isRBaryon (const T &p)
template<>
bool isRBaryon (const DecodedPID &p)
template<>
bool isRBaryon (const int &p)
template<class T>
bool isRHadron (const T &p)
template<>
bool isRHadron (const DecodedPID &p)
template<>
bool isRHadron (const int &p)
template<class T>
bool hasSquark (const T &p, const int &q)
template<>
bool hasSquark (const DecodedPID &p, const int &q)
template<>
bool hasSquark (const int &p, const int &q)
template<class T>
bool isSUSY (const T &p)
template<>
bool isSUSY (const DecodedPID &p)
template<>
bool isSUSY (const int &p)
template<class T>
bool isKK (const T &p)
 PDG rule 11h A black hole in models with extra dimensions has code 5000040.
template<>
bool isKK (const DecodedPID &p)
template<>
bool isKK (const int &p)
template<class T>
bool isMonopole (const T &p)
 PDG rule 11i Magnetic monopoles and dyons are assumed to have one unit of Dirac monopole charge and a variable integer number nq1nq2 nq3 units of electric charge.
template<>
bool isMonopole (const DecodedPID &p)
template<>
bool isMonopole (const int &p)
template<class T>
bool isDM (const T &p)
 PDG rule 11j: The nature of Dark Matter (DM) is not known, and therefore a definitive classificationis too early.
template<>
bool isDM (const int &p)
template<class T>
bool isHiddenValley (const T &p)
 PDG rule 11k Hidden Valley particles have n = 4 and n_r = 9, and trailing numbers in agreement with their nearest-analog standard particles, as far as possible.
template<>
bool isHiddenValley (const DecodedPID &p)
template<>
bool isHiddenValley (const int &p)
template<class T>
bool isGenericMultichargedParticle (const T &p)
 In addition, there is a need to identify ”Q-ball” and similar very exotic (multi-charged) particles which may have large, non-integer charge.
template<>
bool isGenericMultichargedParticle (const DecodedPID &p)
template<>
bool isGenericMultichargedParticle (const int &p)
template<class T>
bool isNucleus (const T &p)
 PDG rule 16 Nuclear codes are given as 10-digit numbers ±10LZZZAAAI.
template<>
bool isNucleus (const DecodedPID &p)
template<>
bool isNucleus (const int &p)
template<class T>
bool hasQuark (const T &p, const int &q)
template<>
bool hasQuark (const DecodedPID &p, const int &q)
template<>
bool hasQuark (const int &p, const int &q)
template<class T>
bool hasStrange (const T &p)
template<class T>
bool hasCharm (const T &p)
template<class T>
bool hasBottom (const T &p)
template<class T>
bool hasTop (const T &p)
template<class T>
int baryonNumber3 (const T &p)
template<>
int baryonNumber3 (const DecodedPID &p)
template<>
int baryonNumber3 (const int &p)
template<class T>
double baryonNumber (const T &p)
template<>
double baryonNumber (const DecodedPID &p)
template<>
double baryonNumber (const int &p)
template<class T>
int strangeness (const T &p)
template<>
int strangeness (const DecodedPID &p)
template<>
int strangeness (const int &p)
template<class T>
int numberOfLambdas (const T &p)
template<>
int numberOfLambdas (const DecodedPID &p)
template<>
int numberOfLambdas (const int &p)
template<class T>
int numberOfProtons (const T &p)
template<>
int numberOfProtons (const DecodedPID &p)
template<>
int numberOfProtons (const int &p)
template<class T>
bool isBSM (const T &p)
 APID: graviton and all Higgs extensions are BSM.
template<>
bool isBSM (const DecodedPID &p)
template<>
bool isBSM (const int &p)
template<class T>
bool isTransportable (const T &p)
template<>
bool isTransportable (const DecodedPID &p)
template<>
bool isTransportable (const int &p)
template<class T>
bool isValid (const T &p)
 Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
template<>
bool isValid (const DecodedPID &p)
template<>
bool isValid (const int &p)
template<class T>
int leadingQuark (const T &p)
template<>
int leadingQuark (const DecodedPID &p)
template<>
int leadingQuark (const int &p)
template<class T>
bool isLightHadron (const T &p)
template<class T>
bool isHeavyHadron (const T &p)
template<class T>
bool isStrangeHadron (const T &p)
template<class T>
bool isCharmHadron (const T &p)
template<class T>
bool isBottomHadron (const T &p)
template<class T>
bool isTopHadron (const T &p)
template<class T>
bool isLightMeson (const T &p)
template<class T>
bool isHeavyMeson (const T &p)
template<class T>
bool isStrangeMeson (const T &p)
template<class T>
bool isCharmMeson (const T &p)
template<class T>
bool isBottomMeson (const T &p)
template<class T>
bool isTopMeson (const T &p)
template<class T>
bool isCCbarMeson (const T &p)
template<>
bool isCCbarMeson (const DecodedPID &p)
template<>
bool isCCbarMeson (const int &p)
template<class T>
bool isBBbarMeson (const T &p)
template<>
bool isBBbarMeson (const DecodedPID &p)
template<>
bool isBBbarMeson (const int &p)
template<class T>
bool isLightBaryon (const T &p)
template<class T>
bool isHeavyBaryon (const T &p)
template<class T>
bool isStrangeBaryon (const T &p)
template<class T>
bool isCharmBaryon (const T &p)
template<class T>
bool isBottomBaryon (const T &p)
template<class T>
bool isTopBaryon (const T &p)
template<class T>
bool isWeaklyDecayingBHadron (const T &p)
template<>
bool isWeaklyDecayingBHadron (const int &p)
template<>
bool isWeaklyDecayingBHadron (const DecodedPID &p)
template<class T>
bool isWeaklyDecayingCHadron (const T &p)
template<>
bool isWeaklyDecayingCHadron (const int &p)
template<>
bool isWeaklyDecayingCHadron (const DecodedPID &p)
template<class T>
int charge3 (const T &p)
template<class T>
double fractionalCharge (const T &p)
template<class T>
double charge (const T &p)
template<class T>
double threeCharge (const T &p)
template<class T>
bool isCharged (const T &p)
template<>
int charge3 (const DecodedPID &p)
template<>
int charge3 (const int &p)
template<class T>
bool isNeutral (const T &p)
template<>
bool isNeutral (const DecodedPID &p)
template<>
bool isNeutral (const int &p)
template<>
double fractionalCharge (const DecodedPID &p)
template<>
double fractionalCharge (const int &p)
template<class T>
bool isEMInteracting (const T &p)
template<>
bool isEMInteracting (const int &p)
template<class T>
bool isParton (const T &p)
template<class T>
int spin2 (const T &p)
template<>
int spin2 (const DecodedPID &p)
template<>
int spin2 (const int &p)
template<class T>
double spin (const T &p)
template<>
double spin (const DecodedPID &p)
template<>
double spin (const int &p)
template<class T>
std::vector< int > containedQuarks (const T &p)
template<>
std::vector< int > containedQuarks (const int &p)
template<>
std::vector< int > containedQuarks (const DecodedPID &p)
template<class T>
bool isStrongInteracting (const T &p)
template<>
bool isStrongInteracting (const int &p)
template<class T>
bool isInteracting (const T &p)
 Identify if the particle with given PDG ID would not interact with the detector, i.e. not a neutrino or WIMP.
template<class T>
bool isChargedNonShowering (const T &p)
 Identify if the particle with given PDG ID would produce ID tracks but not shower in the detector if stable.
template<class T>
bool isBeam (const T &p)
 Identify if the particle is beam particle.
template<class T>
bool isDecayed (const T &p)
 Identify if the particle decayed.
template<class T>
bool isStable (const T &p)
 Identify if the particle is stable, i.e. has not decayed.
template<class T>
bool isFinalState (const T &p)
 Identify if the particle is final state particle.
template<class T>
bool isPhysical (const T &p)
 Identify if the particle is physical, i.e. is stable or decayed.
template<class T>
bool isGenStable (const T &p)
 Determine if the particle is stable at the generator (not det-sim) level,.
template<class T>
bool isSimStable (const T &p)
 Identify if the particle is considered stable at the post-detector-sim stage.
template<class T>
bool isSimInteracting (const T &p)
 Identify if the particle could interact with the detector during the simulation, e.g. not a neutrino or WIMP.
template<class T>
bool isStableOrSimDecayed (const T &p)
 Identify if particle is satble or decayed in simulation.
template<class T>
bool isZeroEnergyPhoton (const T &p)
 Identify a photon with zero energy. Probably a workaround for a generator bug.
template<class T>
bool isSpecialNonInteracting (const T &p)
 Identify a special non-interacting particles.
template<class T>
findMother (T thePart)
 Function to get a mother of particle. MCTruthClassifier legacy.
template<class C, class T>
findMatching (C TruthContainer, T p)
 Function to find a particle in container.
template<class T>
void findParticleAncestors (T thePart, std::set< T > &allancestors)
 Function to find all ancestors of the particle.
template<class T>
void findParticleStableDescendants (T thePart, std::set< T > &allstabledescendants)
 Function to get the particle stable MC daughters.
template<class T>
bool isHardScatteringVertex (T pVert)
 Function to classify the vertex as hard scattering vertex.
template<class T, class U>
bool isFromHadron (T p, U hadron, bool &fromTau, bool &fromBSM)
 Function to classify the particle.
template<class T>
auto findSimulatedEndVertex (T thePart) -> decltype(thePart->end_vertex())
 Function to find the end vertex of a particle.
template<class V>
auto findFinalStateParticles (V theVert) -> decltype(theVert->particles_out())
 Function to find the stable particle descendants of the given vertex..

Variables

static const int TABLESIZE = 100
static const std::array< int, TABLESIZEtriple_charge
static const std::array< int, TABLESIZEdouble_spin
static const int DQUARK = 1
static const int UQUARK = 2
static const int SQUARK = 3
static const int CQUARK = 4
static const int BQUARK = 5
static const int TQUARK = 6
static const int BPRIME = 7
static const int TPRIME = 8
static const int QUARK_LIMIT = BPRIME
static const int ELECTRON = 11
static const int POSITRON = -ELECTRON
static const int NU_E = 12
static const int MUON = 13
static const int NU_MU = 14
static const int TAU = 15
static const int NU_TAU = 16
static const int LPRIME = 17
static const int NUPRIME = 18
static const int GLUON = 21
static const int COMPOSITEGLUON = 9
static const int PHOTON = 22
static const int Z0BOSON = 23
static const int WPLUSBOSON = 24
static const int HIGGSBOSON = 25
static const int ZPRIME = 32
static const int ZDBLPRIME = 33
static const int WPLUSPRIME = 34
static const int HIGGS2 = 35
static const int HIGGS3 = 36
static const int HIGGSPLUS = 37
static const int HIGGSPLUSPLUS = 38
static const int GRAVITON = 39
static const int HIGGS4 = 40
static const int LEPTOQUARK = 42
static const int DARKPHOTON = 60000
 PDG Ids for Mavtop madgraph UFO model found under DarkX.
static const int MAVTOP = 60001
static const int PIPLUS = 211
static const int PIMINUS = -PIPLUS
static const int PI0 = 111
static const int K0L = 130
static const int K0S = 310
static const int K0 = 311
static const int KPLUS = 321
static const int DPLUS = 411
static const int DSTAR = 413
static const int D0 = 421
static const int DSPLUS = 431
static const int JPSI = 443
static const int B0 = 511
static const int BCPLUS = 541
static const int PROTON = 2212
static const int NEUTRON = 2112
static const int LAMBDA0 = 3122
static const int LAMBDACPLUS = 4122
static const int LAMBDAB0 = 5122
static const int PSI2S = 20443
static const int RH_NU_E = 9900012
 PDG Rule 12: Generator defined PDG ID values for right handed neutrinos and corresponding W+ boson from a Left-Right symmetric Standard Model extension.
static const int RH_NU_MU = 9900014
static const int RH_NU_TAU = 9900016
static const int WBOSON_LRSM = 9900024
static const int LEAD = 1000822080
static const int OXYGEN = 1000080160
static const int NEON = 1000100200
static const int HELIUM = 1000020040
static const int POMERON = 990
 PDG rule 8: The pomeron and odderon trajectories and a generic reggeon trajectory of states in QCD areassigned codes 990, 9990, and 110 respectively.
static const int ODDERON = 9990
static const int REGGEON = 110
static const int GEANTINOPLUS = 998
 PDG rule 10: Codes 81–100 are reserved for generator-specific pseudoparticles and concepts.
static const int GEANTINO0 = 999
static const std::array< int, 10 > is_strange

Function Documentation

◆ baryonNumber() [1/3]

template<>
double MC::baryonNumber ( const DecodedPID & p)
inline

Definition at line 775 of file HepMCHelpers.h.

◆ baryonNumber() [2/3]

template<>
double MC::baryonNumber ( const int & p)
inline

Definition at line 776 of file HepMCHelpers.h.

797{
798inline
799auto particles_in (const HepMC::GenVertex* p) {
800 return std::ranges::subrange (p->particles_in_const_begin(),
801 p->particles_in_const_end());
802}
803}
804#endif
805
806namespace MC
807{
808 template <class VTX>
809 auto particles_in (const VTX* p) { return p->particles_in(); }
810 template <class VTX>
811 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
812
813 namespace Pythia8
814 {
816 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
817
818 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
819
820 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
821 }
822
823#include "AtlasPID.h"
824
826 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
827
829 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
830
832 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
833
835 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
836
838 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
839
841 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
842
844 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
845
847 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
848
850 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
851
853 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
854
858 template <class T> inline bool isStableOrSimDecayed(const T& p) {
859 const auto vertex = p->end_vertex();
860 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
861 }
862
864 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
865
867 template <class T> inline bool isSpecialNonInteracting(const T& p) {
868 const int apid = std::abs(p->pdg_id());
869 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
870 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
871 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
872 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
873 return false;
874 }
875
877
878 template <class T> T findMother(T thePart) {
879 auto partOriVert = thePart->production_vertex();
880 if (!partOriVert) return nullptr;
881
882 long partPDG = thePart->pdg_id();
883 long MotherPDG(0);
884
885 auto MothOriVert = partOriVert;
886 MothOriVert = nullptr;
887 T theMoth(nullptr);
888
889 size_t itr = 0;
890 do {
891 if (itr != 0) partOriVert = MothOriVert;
892 for ( const auto& p : particles_in(partOriVert) ) {
893 theMoth = p;
894 if (!theMoth) continue;
895 MotherPDG = theMoth->pdg_id();
896 MothOriVert = theMoth->production_vertex();
897 if (MotherPDG == partPDG) break;
898 }
899 itr++;
900 if (itr > 100) {
901 break;
902 }
903 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
904 MothOriVert != partOriVert);
905 return theMoth;
906 }
907
909
910 template <class C, class T> T findMatching(C TruthContainer, T p) {
911 T ptrPart = nullptr;
912 if (!p) return ptrPart;
913 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
914 for (T truthParticle : *TruthContainer) {
915 if (HepMC::is_sim_descendant(p,truthParticle)) {
916 ptrPart = truthParticle;
917 break;
918 }
919 }
920 }
921 else {
922 for (T truthParticle : TruthContainer) {
923 if (HepMC::is_sim_descendant(p,truthParticle)) {
924 ptrPart = truthParticle;
925 break;
926 }
927 }
928 }
929 return ptrPart;
930 }
932
933 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
934 auto prodVtx = thePart->production_vertex();
935 if (!prodVtx) return;
936 for (const auto& theMother: prodVtx->particles_in()) {
937 if (!theMother) continue;
938 allancestors.insert(theMother);
939 findParticleAncestors(theMother, allancestors);
940 }
941 }
942
944
945 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
946 auto endVtx = thePart->end_vertex();
947 if (!endVtx) return;
948 for (const auto& theDaughter: endVtx->particles_out()) {
949 if (!theDaughter) continue;
950 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
951 allstabledescendants.insert(theDaughter);
952 }
953 findParticleStableDescendants(theDaughter, allstabledescendants);
954 }
955 }
956
960
961 template <class T> bool isHardScatteringVertex(T pVert) {
962 if (pVert == nullptr) return false;
963 T pV = pVert;
964 int numOfPartIn(0);
965 int pdg(0);
966
967 do {
968 pVert = pV;
969 auto incoming = pVert->particles_in();
970 numOfPartIn = incoming.size();
971 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
972 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
973
974 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
975
976 if (numOfPartIn == 2) {
977 auto incoming = pVert->particles_in();
978 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
979 }
980 return false;
981}
982
986
987 template <class T, class U>
988 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
989 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
990 auto vtx = p->production_vertex();
991 if (!vtx) return false;
992 bool fromHad = false;
993 for ( const auto& parent : particles_in(vtx) ) {
994 if (!parent) continue;
995 // should this really go into parton-level territory?
996 // probably depends where BSM particles are being decayed
997 fromBSM |= isBSM(parent);
998 if (!isPhysical(parent)) return false;
999 fromTau |= isTau(parent);
1000 if (isHadron(parent)&&!isBeam(parent)) {
1001 if (!hadron) hadron = parent; // assumes linear hadron parentage
1002 return true;
1003 }
1004 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1005 }
1006 return fromHad;
1007 }
1008
1011
1012 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1013 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1014 decltype(thePart->end_vertex()) pVert(nullptr);
1015 if (EndVert != nullptr) {
1016 do {
1017 bool samePart = false;
1018 pVert = nullptr;
1019 auto outgoing = EndVert->particles_out();
1020 auto incoming = EndVert->particles_in();
1021 for (const auto& itrDaug: outgoing) {
1022 if (!itrDaug) continue;
1023 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1024 // brem on generator level for tau
1025 (outgoing.size() == 1 && incoming.size() == 1 &&
1027 itrDaug->pdg_id() == thePart->pdg_id()) {
1028 samePart = true;
1029 pVert = itrDaug->end_vertex();
1030 }
1031 }
1032 if (samePart) EndVert = pVert;
1033 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1034 }
1035 return EndVert;
1036 }
1037
1039
1040 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1041 if (!theVert) return {};
1042 decltype(theVert->particles_out()) finalStatePart;
1043 auto outgoing = theVert->particles_out();
1044 for (const auto& thePart: outgoing) {
1045 if (!thePart) continue;
1046 finalStatePart.push_back(thePart);
1047 if (isStable(thePart)) continue;
1048 V pVert = findSimulatedEndVertex(thePart);
1049 if (pVert == theVert) break; // to prevent Sherpa loop
1050 if (pVert != nullptr) {
1051 auto vecPart = findFinalStateParticles<V>(pVert);
1052 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1053 }
1054 }
1055 return finalStatePart;
1056 }
1057
1058}
1059#endif
struct color C
bool is_same_generator_particle(const T1 &p1, const T2 &p2)
Method to establish if two particles in the GenEvent actually represent the same generated particle.
bool is_simulation_vertex(const T &v)
Method to establish if the vertex was created during simulation (TODO migrate to be based on status).
constexpr int SIM_STATUS_THRESHOLD
Constant definiting the status threshold for simulated particles, eg. can be used to separate generat...
int status(const T &p)
bool is_simulation_particle(const T &p)
Method to establish if a particle (or barcode) was created during the simulation (TODO update to be s...
constexpr bool is_smart_ptr_v
bool is_sim_descendant(const T1 &p1, const T2 &p2)
Method to check if the first particle is a descendant of the second in the simulation,...
bool isConditionB(const T &p)
bool isConditionA(const T &p)
To be understood.
bool isConditionC(const T &p)
T findMatching(C TruthContainer, T p)
Function to find a particle in container.
static const int GRAVITON
bool isZeroEnergyPhoton(const T &p)
Identify a photon with zero energy. Probably a workaround for a generator bug.
bool isHardScatteringVertex(T pVert)
Function to classify the vertex as hard scattering vertex.
bool isStableOrSimDecayed(const T &p)
Identify if particle is satble or decayed in simulation.
bool isPhoton(const T &p)
bool isSpecialNonInteracting(const T &p)
Identify a special non-interacting particles.
bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM)
Function to classify the particle.
bool isStable(const T &p)
Identify if the particle is stable, i.e. has not decayed.
bool isGeantino(const T &p)
bool isSimInteracting(const T &p)
Identify if the particle could interact with the detector during the simulation, e....
bool isEMInteracting(const T &p)
void findParticleAncestors(T thePart, std::set< T > &allancestors)
Function to find all ancestors of the particle.
bool isStrongInteracting(const T &p)
bool isInteracting(const T &p)
Identify if the particle with given PDG ID would not interact with the detector, i....
bool isMuon(const T &p)
bool isSUSY(const T &p)
auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out())
Function to find the stable particle descendants of the given vertex..
static const int NU_MU
bool isChargedNonShowering(const T &p)
Identify if the particle with given PDG ID would produce ID tracks but not shower in the detector if ...
bool isDecayed(const T &p)
Identify if the particle decayed.
T findMother(T thePart)
Function to get a mother of particle. MCTruthClassifier legacy.
auto particles_in(const HepMC::GenVertex *p)
void findParticleStableDescendants(T thePart, std::set< T > &allstabledescendants)
Function to get the particle stable MC daughters.
static const int NU_E
bool isBeam(const T &p)
Identify if the particle is beam particle.
static const int NU_TAU
bool isFinalState(const T &p)
Identify if the particle is final state particle.
bool isGenStable(const T &p)
Determine if the particle is stable at the generator (not det-sim) level,.
bool isHadron(const T &p)
bool isSimStable(const T &p)
Identify if the particle is considered stable at the post-detector-sim stage.
auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex())
Function to find the end vertex of a particle.
bool isTau(const T &p)
bool isPhysical(const T &p)
Identify if the particle is physical, i.e. is stable or decayed.
bool isBSM(const T &p)
APID: graviton and all Higgs extensions are BSM.
unsigned long long T

◆ baryonNumber() [3/3]

template<class T>
double MC::baryonNumber ( const T & p)
inline

Definition at line 774 of file HepMCHelpers.h.

795{
796inline
797auto particles_in (const HepMC::GenVertex* p) {
798 return std::ranges::subrange (p->particles_in_const_begin(),
799 p->particles_in_const_end());
800}
801}
802#endif
803
804namespace MC
805{
806 template <class VTX>
807 auto particles_in (const VTX* p) { return p->particles_in(); }
808 template <class VTX>
809 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
810
811 namespace Pythia8
812 {
814 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
815
816 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
817
818 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
819 }
820
821#include "AtlasPID.h"
822
824 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
825
827 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
828
830 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
831
833 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
834
836 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
837
839 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
840
842 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
843
845 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
846
848 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
849
851 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
852
856 template <class T> inline bool isStableOrSimDecayed(const T& p) {
857 const auto vertex = p->end_vertex();
858 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
859 }
860
862 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
863
865 template <class T> inline bool isSpecialNonInteracting(const T& p) {
866 const int apid = std::abs(p->pdg_id());
867 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
868 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
869 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
870 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
871 return false;
872 }
873
875
876 template <class T> T findMother(T thePart) {
877 auto partOriVert = thePart->production_vertex();
878 if (!partOriVert) return nullptr;
879
880 long partPDG = thePart->pdg_id();
881 long MotherPDG(0);
882
883 auto MothOriVert = partOriVert;
884 MothOriVert = nullptr;
885 T theMoth(nullptr);
886
887 size_t itr = 0;
888 do {
889 if (itr != 0) partOriVert = MothOriVert;
890 for ( const auto& p : particles_in(partOriVert) ) {
891 theMoth = p;
892 if (!theMoth) continue;
893 MotherPDG = theMoth->pdg_id();
894 MothOriVert = theMoth->production_vertex();
895 if (MotherPDG == partPDG) break;
896 }
897 itr++;
898 if (itr > 100) {
899 break;
900 }
901 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
902 MothOriVert != partOriVert);
903 return theMoth;
904 }
905
907
908 template <class C, class T> T findMatching(C TruthContainer, T p) {
909 T ptrPart = nullptr;
910 if (!p) return ptrPart;
911 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
912 for (T truthParticle : *TruthContainer) {
913 if (HepMC::is_sim_descendant(p,truthParticle)) {
914 ptrPart = truthParticle;
915 break;
916 }
917 }
918 }
919 else {
920 for (T truthParticle : TruthContainer) {
921 if (HepMC::is_sim_descendant(p,truthParticle)) {
922 ptrPart = truthParticle;
923 break;
924 }
925 }
926 }
927 return ptrPart;
928 }
930
931 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
932 auto prodVtx = thePart->production_vertex();
933 if (!prodVtx) return;
934 for (const auto& theMother: prodVtx->particles_in()) {
935 if (!theMother) continue;
936 allancestors.insert(theMother);
937 findParticleAncestors(theMother, allancestors);
938 }
939 }
940
942
943 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
944 auto endVtx = thePart->end_vertex();
945 if (!endVtx) return;
946 for (const auto& theDaughter: endVtx->particles_out()) {
947 if (!theDaughter) continue;
948 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
949 allstabledescendants.insert(theDaughter);
950 }
951 findParticleStableDescendants(theDaughter, allstabledescendants);
952 }
953 }
954
958
959 template <class T> bool isHardScatteringVertex(T pVert) {
960 if (pVert == nullptr) return false;
961 T pV = pVert;
962 int numOfPartIn(0);
963 int pdg(0);
964
965 do {
966 pVert = pV;
967 auto incoming = pVert->particles_in();
968 numOfPartIn = incoming.size();
969 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
970 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
971
972 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
973
974 if (numOfPartIn == 2) {
975 auto incoming = pVert->particles_in();
976 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
977 }
978 return false;
979}
980
984
985 template <class T, class U>
986 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
987 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
988 auto vtx = p->production_vertex();
989 if (!vtx) return false;
990 bool fromHad = false;
991 for ( const auto& parent : particles_in(vtx) ) {
992 if (!parent) continue;
993 // should this really go into parton-level territory?
994 // probably depends where BSM particles are being decayed
995 fromBSM |= isBSM(parent);
996 if (!isPhysical(parent)) return false;
997 fromTau |= isTau(parent);
998 if (isHadron(parent)&&!isBeam(parent)) {
999 if (!hadron) hadron = parent; // assumes linear hadron parentage
1000 return true;
1001 }
1002 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1003 }
1004 return fromHad;
1005 }
1006
1009
1010 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1011 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1012 decltype(thePart->end_vertex()) pVert(nullptr);
1013 if (EndVert != nullptr) {
1014 do {
1015 bool samePart = false;
1016 pVert = nullptr;
1017 auto outgoing = EndVert->particles_out();
1018 auto incoming = EndVert->particles_in();
1019 for (const auto& itrDaug: outgoing) {
1020 if (!itrDaug) continue;
1021 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1022 // brem on generator level for tau
1023 (outgoing.size() == 1 && incoming.size() == 1 &&
1025 itrDaug->pdg_id() == thePart->pdg_id()) {
1026 samePart = true;
1027 pVert = itrDaug->end_vertex();
1028 }
1029 }
1030 if (samePart) EndVert = pVert;
1031 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1032 }
1033 return EndVert;
1034 }
1035
1037
1038 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1039 if (!theVert) return {};
1040 decltype(theVert->particles_out()) finalStatePart;
1041 auto outgoing = theVert->particles_out();
1042 for (const auto& thePart: outgoing) {
1043 if (!thePart) continue;
1044 finalStatePart.push_back(thePart);
1045 if (isStable(thePart)) continue;
1046 V pVert = findSimulatedEndVertex(thePart);
1047 if (pVert == theVert) break; // to prevent Sherpa loop
1048 if (pVert != nullptr) {
1049 auto vecPart = findFinalStateParticles<V>(pVert);
1050 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1051 }
1052 }
1053 return finalStatePart;
1054 }
1055
1056}
1057#endif

◆ baryonNumber3() [1/3]

template<>
int MC::baryonNumber3 ( const DecodedPID & p)
inline

Definition at line 750 of file HepMCHelpers.h.

771 {
772inline
773auto particles_in (const HepMC::GenVertex* p) {
774 return std::ranges::subrange (p->particles_in_const_begin(),
775 p->particles_in_const_end());
776}
777}
778#endif
779
780namespace MC
781{
782 template <class VTX>
783 auto particles_in (const VTX* p) { return p->particles_in(); }
784 template <class VTX>
785 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
786
787 namespace Pythia8
788 {
790 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
791
792 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
793
794 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
795 }
796
797#include "AtlasPID.h"
798
800 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
801
803 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
804
806 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
807
809 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
810
812 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
813
815 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
816
818 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
819
821 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
822
824 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
825
827 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
828
832 template <class T> inline bool isStableOrSimDecayed(const T& p) {
833 const auto vertex = p->end_vertex();
834 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
835 }
836
838 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
839
841 template <class T> inline bool isSpecialNonInteracting(const T& p) {
842 const int apid = std::abs(p->pdg_id());
843 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
844 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
845 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
846 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
847 return false;
848 }
849
851
852 template <class T> T findMother(T thePart) {
853 auto partOriVert = thePart->production_vertex();
854 if (!partOriVert) return nullptr;
855
856 long partPDG = thePart->pdg_id();
857 long MotherPDG(0);
858
859 auto MothOriVert = partOriVert;
860 MothOriVert = nullptr;
861 T theMoth(nullptr);
862
863 size_t itr = 0;
864 do {
865 if (itr != 0) partOriVert = MothOriVert;
866 for ( const auto& p : particles_in(partOriVert) ) {
867 theMoth = p;
868 if (!theMoth) continue;
869 MotherPDG = theMoth->pdg_id();
870 MothOriVert = theMoth->production_vertex();
871 if (MotherPDG == partPDG) break;
872 }
873 itr++;
874 if (itr > 100) {
875 break;
876 }
877 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
878 MothOriVert != partOriVert);
879 return theMoth;
880 }
881
883
884 template <class C, class T> T findMatching(C TruthContainer, T p) {
885 T ptrPart = nullptr;
886 if (!p) return ptrPart;
887 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
888 for (T truthParticle : *TruthContainer) {
889 if (HepMC::is_sim_descendant(p,truthParticle)) {
890 ptrPart = truthParticle;
891 break;
892 }
893 }
894 }
895 else {
896 for (T truthParticle : TruthContainer) {
897 if (HepMC::is_sim_descendant(p,truthParticle)) {
898 ptrPart = truthParticle;
899 break;
900 }
901 }
902 }
903 return ptrPart;
904 }
906
907 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
908 auto prodVtx = thePart->production_vertex();
909 if (!prodVtx) return;
910 for (const auto& theMother: prodVtx->particles_in()) {
911 if (!theMother) continue;
912 allancestors.insert(theMother);
913 findParticleAncestors(theMother, allancestors);
914 }
915 }
916
918
919 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
920 auto endVtx = thePart->end_vertex();
921 if (!endVtx) return;
922 for (const auto& theDaughter: endVtx->particles_out()) {
923 if (!theDaughter) continue;
924 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
925 allstabledescendants.insert(theDaughter);
926 }
927 findParticleStableDescendants(theDaughter, allstabledescendants);
928 }
929 }
930
934
935 template <class T> bool isHardScatteringVertex(T pVert) {
936 if (pVert == nullptr) return false;
937 T pV = pVert;
938 int numOfPartIn(0);
939 int pdg(0);
940
941 do {
942 pVert = pV;
943 auto incoming = pVert->particles_in();
944 numOfPartIn = incoming.size();
945 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
946 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
947
948 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
949
950 if (numOfPartIn == 2) {
951 auto incoming = pVert->particles_in();
952 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
953 }
954 return false;
955}
956
960
961 template <class T, class U>
962 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
963 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
964 auto vtx = p->production_vertex();
965 if (!vtx) return false;
966 bool fromHad = false;
967 for ( const auto& parent : particles_in(vtx) ) {
968 if (!parent) continue;
969 // should this really go into parton-level territory?
970 // probably depends where BSM particles are being decayed
971 fromBSM |= isBSM(parent);
972 if (!isPhysical(parent)) return false;
973 fromTau |= isTau(parent);
974 if (isHadron(parent)&&!isBeam(parent)) {
975 if (!hadron) hadron = parent; // assumes linear hadron parentage
976 return true;
977 }
978 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
979 }
980 return fromHad;
981 }
982
985
986 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
987 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
988 decltype(thePart->end_vertex()) pVert(nullptr);
989 if (EndVert != nullptr) {
990 do {
991 bool samePart = false;
992 pVert = nullptr;
993 auto outgoing = EndVert->particles_out();
994 auto incoming = EndVert->particles_in();
995 for (const auto& itrDaug: outgoing) {
996 if (!itrDaug) continue;
997 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
998 // brem on generator level for tau
999 (outgoing.size() == 1 && incoming.size() == 1 &&
1001 itrDaug->pdg_id() == thePart->pdg_id()) {
1002 samePart = true;
1003 pVert = itrDaug->end_vertex();
1004 }
1005 }
1006 if (samePart) EndVert = pVert;
1007 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1008 }
1009 return EndVert;
1010 }
1011
1013
1014 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1015 if (!theVert) return {};
1016 decltype(theVert->particles_out()) finalStatePart;
1017 auto outgoing = theVert->particles_out();
1018 for (const auto& thePart: outgoing) {
1019 if (!thePart) continue;
1020 finalStatePart.push_back(thePart);
1021 if (isStable(thePart)) continue;
1022 V pVert = findSimulatedEndVertex(thePart);
1023 if (pVert == theVert) break; // to prevent Sherpa loop
1024 if (pVert != nullptr) {
1025 auto vecPart = findFinalStateParticles<V>(pVert);
1026 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1027 }
1028 }
1029 return finalStatePart;
1030 }
1031
1032}
1033#endif

◆ baryonNumber3() [2/3]

template<>
int MC::baryonNumber3 ( const int & p)
inline

Definition at line 772 of file HepMCHelpers.h.

793{
794inline
795auto particles_in (const HepMC::GenVertex* p) {
796 return std::ranges::subrange (p->particles_in_const_begin(),
797 p->particles_in_const_end());
798}
799}
800#endif
801
802namespace MC
803{
804 template <class VTX>
805 auto particles_in (const VTX* p) { return p->particles_in(); }
806 template <class VTX>
807 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
808
809 namespace Pythia8
810 {
812 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
813
814 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
815
816 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
817 }
818
819#include "AtlasPID.h"
820
822 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
823
825 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
826
828 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
829
831 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
832
834 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
835
837 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
838
840 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
841
843 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
844
846 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
847
849 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
850
854 template <class T> inline bool isStableOrSimDecayed(const T& p) {
855 const auto vertex = p->end_vertex();
856 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
857 }
858
860 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
861
863 template <class T> inline bool isSpecialNonInteracting(const T& p) {
864 const int apid = std::abs(p->pdg_id());
865 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
866 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
867 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
868 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
869 return false;
870 }
871
873
874 template <class T> T findMother(T thePart) {
875 auto partOriVert = thePart->production_vertex();
876 if (!partOriVert) return nullptr;
877
878 long partPDG = thePart->pdg_id();
879 long MotherPDG(0);
880
881 auto MothOriVert = partOriVert;
882 MothOriVert = nullptr;
883 T theMoth(nullptr);
884
885 size_t itr = 0;
886 do {
887 if (itr != 0) partOriVert = MothOriVert;
888 for ( const auto& p : particles_in(partOriVert) ) {
889 theMoth = p;
890 if (!theMoth) continue;
891 MotherPDG = theMoth->pdg_id();
892 MothOriVert = theMoth->production_vertex();
893 if (MotherPDG == partPDG) break;
894 }
895 itr++;
896 if (itr > 100) {
897 break;
898 }
899 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
900 MothOriVert != partOriVert);
901 return theMoth;
902 }
903
905
906 template <class C, class T> T findMatching(C TruthContainer, T p) {
907 T ptrPart = nullptr;
908 if (!p) return ptrPart;
909 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
910 for (T truthParticle : *TruthContainer) {
911 if (HepMC::is_sim_descendant(p,truthParticle)) {
912 ptrPart = truthParticle;
913 break;
914 }
915 }
916 }
917 else {
918 for (T truthParticle : TruthContainer) {
919 if (HepMC::is_sim_descendant(p,truthParticle)) {
920 ptrPart = truthParticle;
921 break;
922 }
923 }
924 }
925 return ptrPart;
926 }
928
929 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
930 auto prodVtx = thePart->production_vertex();
931 if (!prodVtx) return;
932 for (const auto& theMother: prodVtx->particles_in()) {
933 if (!theMother) continue;
934 allancestors.insert(theMother);
935 findParticleAncestors(theMother, allancestors);
936 }
937 }
938
940
941 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
942 auto endVtx = thePart->end_vertex();
943 if (!endVtx) return;
944 for (const auto& theDaughter: endVtx->particles_out()) {
945 if (!theDaughter) continue;
946 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
947 allstabledescendants.insert(theDaughter);
948 }
949 findParticleStableDescendants(theDaughter, allstabledescendants);
950 }
951 }
952
956
957 template <class T> bool isHardScatteringVertex(T pVert) {
958 if (pVert == nullptr) return false;
959 T pV = pVert;
960 int numOfPartIn(0);
961 int pdg(0);
962
963 do {
964 pVert = pV;
965 auto incoming = pVert->particles_in();
966 numOfPartIn = incoming.size();
967 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
968 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
969
970 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
971
972 if (numOfPartIn == 2) {
973 auto incoming = pVert->particles_in();
974 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
975 }
976 return false;
977}
978
982
983 template <class T, class U>
984 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
985 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
986 auto vtx = p->production_vertex();
987 if (!vtx) return false;
988 bool fromHad = false;
989 for ( const auto& parent : particles_in(vtx) ) {
990 if (!parent) continue;
991 // should this really go into parton-level territory?
992 // probably depends where BSM particles are being decayed
993 fromBSM |= isBSM(parent);
994 if (!isPhysical(parent)) return false;
995 fromTau |= isTau(parent);
996 if (isHadron(parent)&&!isBeam(parent)) {
997 if (!hadron) hadron = parent; // assumes linear hadron parentage
998 return true;
999 }
1000 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1001 }
1002 return fromHad;
1003 }
1004
1007
1008 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1009 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1010 decltype(thePart->end_vertex()) pVert(nullptr);
1011 if (EndVert != nullptr) {
1012 do {
1013 bool samePart = false;
1014 pVert = nullptr;
1015 auto outgoing = EndVert->particles_out();
1016 auto incoming = EndVert->particles_in();
1017 for (const auto& itrDaug: outgoing) {
1018 if (!itrDaug) continue;
1019 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1020 // brem on generator level for tau
1021 (outgoing.size() == 1 && incoming.size() == 1 &&
1023 itrDaug->pdg_id() == thePart->pdg_id()) {
1024 samePart = true;
1025 pVert = itrDaug->end_vertex();
1026 }
1027 }
1028 if (samePart) EndVert = pVert;
1029 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1030 }
1031 return EndVert;
1032 }
1033
1035
1036 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1037 if (!theVert) return {};
1038 decltype(theVert->particles_out()) finalStatePart;
1039 auto outgoing = theVert->particles_out();
1040 for (const auto& thePart: outgoing) {
1041 if (!thePart) continue;
1042 finalStatePart.push_back(thePart);
1043 if (isStable(thePart)) continue;
1044 V pVert = findSimulatedEndVertex(thePart);
1045 if (pVert == theVert) break; // to prevent Sherpa loop
1046 if (pVert != nullptr) {
1047 auto vecPart = findFinalStateParticles<V>(pVert);
1048 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1049 }
1050 }
1051 return finalStatePart;
1052 }
1053
1054}
1055#endif

◆ baryonNumber3() [3/3]

template<class T>
int MC::baryonNumber3 ( const T & p)
inline

Definition at line 749 of file HepMCHelpers.h.

770{
771inline
772auto particles_in (const HepMC::GenVertex* p) {
773 return std::ranges::subrange (p->particles_in_const_begin(),
774 p->particles_in_const_end());
775}
776}
777#endif
778
779namespace MC
780{
781 template <class VTX>
782 auto particles_in (const VTX* p) { return p->particles_in(); }
783 template <class VTX>
784 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
785
786 namespace Pythia8
787 {
789 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
790
791 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
792
793 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
794 }
795
796#include "AtlasPID.h"
797
799 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
800
802 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
803
805 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
806
808 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
809
811 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
812
814 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
815
817 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
818
820 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
821
823 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
824
826 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
827
831 template <class T> inline bool isStableOrSimDecayed(const T& p) {
832 const auto vertex = p->end_vertex();
833 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
834 }
835
837 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
838
840 template <class T> inline bool isSpecialNonInteracting(const T& p) {
841 const int apid = std::abs(p->pdg_id());
842 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
843 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
844 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
845 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
846 return false;
847 }
848
850
851 template <class T> T findMother(T thePart) {
852 auto partOriVert = thePart->production_vertex();
853 if (!partOriVert) return nullptr;
854
855 long partPDG = thePart->pdg_id();
856 long MotherPDG(0);
857
858 auto MothOriVert = partOriVert;
859 MothOriVert = nullptr;
860 T theMoth(nullptr);
861
862 size_t itr = 0;
863 do {
864 if (itr != 0) partOriVert = MothOriVert;
865 for ( const auto& p : particles_in(partOriVert) ) {
866 theMoth = p;
867 if (!theMoth) continue;
868 MotherPDG = theMoth->pdg_id();
869 MothOriVert = theMoth->production_vertex();
870 if (MotherPDG == partPDG) break;
871 }
872 itr++;
873 if (itr > 100) {
874 break;
875 }
876 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
877 MothOriVert != partOriVert);
878 return theMoth;
879 }
880
882
883 template <class C, class T> T findMatching(C TruthContainer, T p) {
884 T ptrPart = nullptr;
885 if (!p) return ptrPart;
886 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
887 for (T truthParticle : *TruthContainer) {
888 if (HepMC::is_sim_descendant(p,truthParticle)) {
889 ptrPart = truthParticle;
890 break;
891 }
892 }
893 }
894 else {
895 for (T truthParticle : TruthContainer) {
896 if (HepMC::is_sim_descendant(p,truthParticle)) {
897 ptrPart = truthParticle;
898 break;
899 }
900 }
901 }
902 return ptrPart;
903 }
905
906 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
907 auto prodVtx = thePart->production_vertex();
908 if (!prodVtx) return;
909 for (const auto& theMother: prodVtx->particles_in()) {
910 if (!theMother) continue;
911 allancestors.insert(theMother);
912 findParticleAncestors(theMother, allancestors);
913 }
914 }
915
917
918 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
919 auto endVtx = thePart->end_vertex();
920 if (!endVtx) return;
921 for (const auto& theDaughter: endVtx->particles_out()) {
922 if (!theDaughter) continue;
923 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
924 allstabledescendants.insert(theDaughter);
925 }
926 findParticleStableDescendants(theDaughter, allstabledescendants);
927 }
928 }
929
933
934 template <class T> bool isHardScatteringVertex(T pVert) {
935 if (pVert == nullptr) return false;
936 T pV = pVert;
937 int numOfPartIn(0);
938 int pdg(0);
939
940 do {
941 pVert = pV;
942 auto incoming = pVert->particles_in();
943 numOfPartIn = incoming.size();
944 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
945 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
946
947 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
948
949 if (numOfPartIn == 2) {
950 auto incoming = pVert->particles_in();
951 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
952 }
953 return false;
954}
955
959
960 template <class T, class U>
961 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
962 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
963 auto vtx = p->production_vertex();
964 if (!vtx) return false;
965 bool fromHad = false;
966 for ( const auto& parent : particles_in(vtx) ) {
967 if (!parent) continue;
968 // should this really go into parton-level territory?
969 // probably depends where BSM particles are being decayed
970 fromBSM |= isBSM(parent);
971 if (!isPhysical(parent)) return false;
972 fromTau |= isTau(parent);
973 if (isHadron(parent)&&!isBeam(parent)) {
974 if (!hadron) hadron = parent; // assumes linear hadron parentage
975 return true;
976 }
977 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
978 }
979 return fromHad;
980 }
981
984
985 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
986 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
987 decltype(thePart->end_vertex()) pVert(nullptr);
988 if (EndVert != nullptr) {
989 do {
990 bool samePart = false;
991 pVert = nullptr;
992 auto outgoing = EndVert->particles_out();
993 auto incoming = EndVert->particles_in();
994 for (const auto& itrDaug: outgoing) {
995 if (!itrDaug) continue;
996 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
997 // brem on generator level for tau
998 (outgoing.size() == 1 && incoming.size() == 1 &&
1000 itrDaug->pdg_id() == thePart->pdg_id()) {
1001 samePart = true;
1002 pVert = itrDaug->end_vertex();
1003 }
1004 }
1005 if (samePart) EndVert = pVert;
1006 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1007 }
1008 return EndVert;
1009 }
1010
1012
1013 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1014 if (!theVert) return {};
1015 decltype(theVert->particles_out()) finalStatePart;
1016 auto outgoing = theVert->particles_out();
1017 for (const auto& thePart: outgoing) {
1018 if (!thePart) continue;
1019 finalStatePart.push_back(thePart);
1020 if (isStable(thePart)) continue;
1021 V pVert = findSimulatedEndVertex(thePart);
1022 if (pVert == theVert) break; // to prevent Sherpa loop
1023 if (pVert != nullptr) {
1024 auto vecPart = findFinalStateParticles<V>(pVert);
1025 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1026 }
1027 }
1028 return finalStatePart;
1029 }
1030
1031}
1032#endif

◆ charge()

template<class T>
double MC::charge ( const T & p)
inline

Definition at line 998 of file HepMCHelpers.h.

1019 {
1020inline
1021auto particles_in (const HepMC::GenVertex* p) {
1022 return std::ranges::subrange (p->particles_in_const_begin(),
1023 p->particles_in_const_end());
1024}
1025}
1026#endif
1027
1028namespace MC
1029{
1030 template <class VTX>
1031 auto particles_in (const VTX* p) { return p->particles_in(); }
1032 template <class VTX>
1033 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1034
1035 namespace Pythia8
1036 {
1038 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1039
1040 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1041
1042 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1043 }
1044
1045#include "AtlasPID.h"
1046
1048 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1049
1051 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1052
1054 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1055
1057 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1058
1060 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1061
1063 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1064
1066 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1067
1069 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1070
1072 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1073
1075 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1076
1080 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1081 const auto vertex = p->end_vertex();
1082 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1083 }
1084
1086 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1087
1089 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1090 const int apid = std::abs(p->pdg_id());
1091 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1092 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1093 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1094 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1095 return false;
1096 }
1097
1099
1100 template <class T> T findMother(T thePart) {
1101 auto partOriVert = thePart->production_vertex();
1102 if (!partOriVert) return nullptr;
1103
1104 long partPDG = thePart->pdg_id();
1105 long MotherPDG(0);
1106
1107 auto MothOriVert = partOriVert;
1108 MothOriVert = nullptr;
1109 T theMoth(nullptr);
1110
1111 size_t itr = 0;
1112 do {
1113 if (itr != 0) partOriVert = MothOriVert;
1114 for ( const auto& p : particles_in(partOriVert) ) {
1115 theMoth = p;
1116 if (!theMoth) continue;
1117 MotherPDG = theMoth->pdg_id();
1118 MothOriVert = theMoth->production_vertex();
1119 if (MotherPDG == partPDG) break;
1120 }
1121 itr++;
1122 if (itr > 100) {
1123 break;
1124 }
1125 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1126 MothOriVert != partOriVert);
1127 return theMoth;
1128 }
1129
1131
1132 template <class C, class T> T findMatching(C TruthContainer, T p) {
1133 T ptrPart = nullptr;
1134 if (!p) return ptrPart;
1135 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1136 for (T truthParticle : *TruthContainer) {
1137 if (HepMC::is_sim_descendant(p,truthParticle)) {
1138 ptrPart = truthParticle;
1139 break;
1140 }
1141 }
1142 }
1143 else {
1144 for (T truthParticle : TruthContainer) {
1145 if (HepMC::is_sim_descendant(p,truthParticle)) {
1146 ptrPart = truthParticle;
1147 break;
1148 }
1149 }
1150 }
1151 return ptrPart;
1152 }
1154
1155 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1156 auto prodVtx = thePart->production_vertex();
1157 if (!prodVtx) return;
1158 for (const auto& theMother: prodVtx->particles_in()) {
1159 if (!theMother) continue;
1160 allancestors.insert(theMother);
1161 findParticleAncestors(theMother, allancestors);
1162 }
1163 }
1164
1166
1167 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1168 auto endVtx = thePart->end_vertex();
1169 if (!endVtx) return;
1170 for (const auto& theDaughter: endVtx->particles_out()) {
1171 if (!theDaughter) continue;
1172 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1173 allstabledescendants.insert(theDaughter);
1174 }
1175 findParticleStableDescendants(theDaughter, allstabledescendants);
1176 }
1177 }
1178
1182
1183 template <class T> bool isHardScatteringVertex(T pVert) {
1184 if (pVert == nullptr) return false;
1185 T pV = pVert;
1186 int numOfPartIn(0);
1187 int pdg(0);
1188
1189 do {
1190 pVert = pV;
1191 auto incoming = pVert->particles_in();
1192 numOfPartIn = incoming.size();
1193 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1194 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1195
1196 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1197
1198 if (numOfPartIn == 2) {
1199 auto incoming = pVert->particles_in();
1200 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1201 }
1202 return false;
1203}
1204
1208
1209 template <class T, class U>
1210 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1211 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1212 auto vtx = p->production_vertex();
1213 if (!vtx) return false;
1214 bool fromHad = false;
1215 for ( const auto& parent : particles_in(vtx) ) {
1216 if (!parent) continue;
1217 // should this really go into parton-level territory?
1218 // probably depends where BSM particles are being decayed
1219 fromBSM |= isBSM(parent);
1220 if (!isPhysical(parent)) return false;
1221 fromTau |= isTau(parent);
1222 if (isHadron(parent)&&!isBeam(parent)) {
1223 if (!hadron) hadron = parent; // assumes linear hadron parentage
1224 return true;
1225 }
1226 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1227 }
1228 return fromHad;
1229 }
1230
1233
1234 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1235 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1236 decltype(thePart->end_vertex()) pVert(nullptr);
1237 if (EndVert != nullptr) {
1238 do {
1239 bool samePart = false;
1240 pVert = nullptr;
1241 auto outgoing = EndVert->particles_out();
1242 auto incoming = EndVert->particles_in();
1243 for (const auto& itrDaug: outgoing) {
1244 if (!itrDaug) continue;
1245 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1246 // brem on generator level for tau
1247 (outgoing.size() == 1 && incoming.size() == 1 &&
1249 itrDaug->pdg_id() == thePart->pdg_id()) {
1250 samePart = true;
1251 pVert = itrDaug->end_vertex();
1252 }
1253 }
1254 if (samePart) EndVert = pVert;
1255 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1256 }
1257 return EndVert;
1258 }
1259
1261
1262 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1263 if (!theVert) return {};
1264 decltype(theVert->particles_out()) finalStatePart;
1265 auto outgoing = theVert->particles_out();
1266 for (const auto& thePart: outgoing) {
1267 if (!thePart) continue;
1268 finalStatePart.push_back(thePart);
1269 if (isStable(thePart)) continue;
1270 V pVert = findSimulatedEndVertex(thePart);
1271 if (pVert == theVert) break; // to prevent Sherpa loop
1272 if (pVert != nullptr) {
1273 auto vecPart = findFinalStateParticles<V>(pVert);
1274 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1275 }
1276 }
1277 return finalStatePart;
1278 }
1279
1280}
1281#endif

◆ charge3() [1/3]

template<>
int MC::charge3 ( const DecodedPID & p)
inline

Codes 411nq1nq2 nq3 0 are then used when the magnetic and electrical charge sign agree and 412nq1nq2 nq3 0 when they disagree, with the overall sign of the particle set by the magnetic charge.

Definition at line 1008 of file HepMCHelpers.h.

1029 {
1030inline
1031auto particles_in (const HepMC::GenVertex* p) {
1032 return std::ranges::subrange (p->particles_in_const_begin(),
1033 p->particles_in_const_end());
1034}
1035}
1036#endif
1037
1038namespace MC
1039{
1040 template <class VTX>
1041 auto particles_in (const VTX* p) { return p->particles_in(); }
1042 template <class VTX>
1043 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1044
1045 namespace Pythia8
1046 {
1048 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1049
1050 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1051
1052 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1053 }
1054
1055#include "AtlasPID.h"
1056
1058 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1059
1061 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1062
1064 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1065
1067 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1068
1070 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1071
1073 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1074
1076 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1077
1079 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1080
1082 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1083
1085 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1086
1090 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1091 const auto vertex = p->end_vertex();
1092 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1093 }
1094
1096 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1097
1099 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1100 const int apid = std::abs(p->pdg_id());
1101 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1102 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1103 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1104 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1105 return false;
1106 }
1107
1109
1110 template <class T> T findMother(T thePart) {
1111 auto partOriVert = thePart->production_vertex();
1112 if (!partOriVert) return nullptr;
1113
1114 long partPDG = thePart->pdg_id();
1115 long MotherPDG(0);
1116
1117 auto MothOriVert = partOriVert;
1118 MothOriVert = nullptr;
1119 T theMoth(nullptr);
1120
1121 size_t itr = 0;
1122 do {
1123 if (itr != 0) partOriVert = MothOriVert;
1124 for ( const auto& p : particles_in(partOriVert) ) {
1125 theMoth = p;
1126 if (!theMoth) continue;
1127 MotherPDG = theMoth->pdg_id();
1128 MothOriVert = theMoth->production_vertex();
1129 if (MotherPDG == partPDG) break;
1130 }
1131 itr++;
1132 if (itr > 100) {
1133 break;
1134 }
1135 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1136 MothOriVert != partOriVert);
1137 return theMoth;
1138 }
1139
1141
1142 template <class C, class T> T findMatching(C TruthContainer, T p) {
1143 T ptrPart = nullptr;
1144 if (!p) return ptrPart;
1145 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1146 for (T truthParticle : *TruthContainer) {
1147 if (HepMC::is_sim_descendant(p,truthParticle)) {
1148 ptrPart = truthParticle;
1149 break;
1150 }
1151 }
1152 }
1153 else {
1154 for (T truthParticle : TruthContainer) {
1155 if (HepMC::is_sim_descendant(p,truthParticle)) {
1156 ptrPart = truthParticle;
1157 break;
1158 }
1159 }
1160 }
1161 return ptrPart;
1162 }
1164
1165 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1166 auto prodVtx = thePart->production_vertex();
1167 if (!prodVtx) return;
1168 for (const auto& theMother: prodVtx->particles_in()) {
1169 if (!theMother) continue;
1170 allancestors.insert(theMother);
1171 findParticleAncestors(theMother, allancestors);
1172 }
1173 }
1174
1176
1177 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1178 auto endVtx = thePart->end_vertex();
1179 if (!endVtx) return;
1180 for (const auto& theDaughter: endVtx->particles_out()) {
1181 if (!theDaughter) continue;
1182 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1183 allstabledescendants.insert(theDaughter);
1184 }
1185 findParticleStableDescendants(theDaughter, allstabledescendants);
1186 }
1187 }
1188
1192
1193 template <class T> bool isHardScatteringVertex(T pVert) {
1194 if (pVert == nullptr) return false;
1195 T pV = pVert;
1196 int numOfPartIn(0);
1197 int pdg(0);
1198
1199 do {
1200 pVert = pV;
1201 auto incoming = pVert->particles_in();
1202 numOfPartIn = incoming.size();
1203 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1204 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1205
1206 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1207
1208 if (numOfPartIn == 2) {
1209 auto incoming = pVert->particles_in();
1210 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1211 }
1212 return false;
1213}
1214
1218
1219 template <class T, class U>
1220 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1221 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1222 auto vtx = p->production_vertex();
1223 if (!vtx) return false;
1224 bool fromHad = false;
1225 for ( const auto& parent : particles_in(vtx) ) {
1226 if (!parent) continue;
1227 // should this really go into parton-level territory?
1228 // probably depends where BSM particles are being decayed
1229 fromBSM |= isBSM(parent);
1230 if (!isPhysical(parent)) return false;
1231 fromTau |= isTau(parent);
1232 if (isHadron(parent)&&!isBeam(parent)) {
1233 if (!hadron) hadron = parent; // assumes linear hadron parentage
1234 return true;
1235 }
1236 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1237 }
1238 return fromHad;
1239 }
1240
1243
1244 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1245 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1246 decltype(thePart->end_vertex()) pVert(nullptr);
1247 if (EndVert != nullptr) {
1248 do {
1249 bool samePart = false;
1250 pVert = nullptr;
1251 auto outgoing = EndVert->particles_out();
1252 auto incoming = EndVert->particles_in();
1253 for (const auto& itrDaug: outgoing) {
1254 if (!itrDaug) continue;
1255 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1256 // brem on generator level for tau
1257 (outgoing.size() == 1 && incoming.size() == 1 &&
1259 itrDaug->pdg_id() == thePart->pdg_id()) {
1260 samePart = true;
1261 pVert = itrDaug->end_vertex();
1262 }
1263 }
1264 if (samePart) EndVert = pVert;
1265 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1266 }
1267 return EndVert;
1268 }
1269
1271
1272 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1273 if (!theVert) return {};
1274 decltype(theVert->particles_out()) finalStatePart;
1275 auto outgoing = theVert->particles_out();
1276 for (const auto& thePart: outgoing) {
1277 if (!thePart) continue;
1278 finalStatePart.push_back(thePart);
1279 if (isStable(thePart)) continue;
1280 V pVert = findSimulatedEndVertex(thePart);
1281 if (pVert == theVert) break; // to prevent Sherpa loop
1282 if (pVert != nullptr) {
1283 auto vecPart = findFinalStateParticles<V>(pVert);
1284 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1285 }
1286 }
1287 return finalStatePart;
1288 }
1289
1290}
1291#endif

◆ charge3() [2/3]

template<>
int MC::charge3 ( const int & p)
inline

Definition at line 1078 of file HepMCHelpers.h.

1099 {
1100inline
1101auto particles_in (const HepMC::GenVertex* p) {
1102 return std::ranges::subrange (p->particles_in_const_begin(),
1103 p->particles_in_const_end());
1104}
1105}
1106#endif
1107
1108namespace MC
1109{
1110 template <class VTX>
1111 auto particles_in (const VTX* p) { return p->particles_in(); }
1112 template <class VTX>
1113 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1114
1115 namespace Pythia8
1116 {
1118 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1119
1120 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1121
1122 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1123 }
1124
1125#include "AtlasPID.h"
1126
1128 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1129
1131 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1132
1134 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1135
1137 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1138
1140 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1141
1143 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1144
1146 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1147
1149 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1150
1152 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1153
1155 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1156
1160 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1161 const auto vertex = p->end_vertex();
1162 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1163 }
1164
1166 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1167
1169 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1170 const int apid = std::abs(p->pdg_id());
1171 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1172 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1173 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1174 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1175 return false;
1176 }
1177
1179
1180 template <class T> T findMother(T thePart) {
1181 auto partOriVert = thePart->production_vertex();
1182 if (!partOriVert) return nullptr;
1183
1184 long partPDG = thePart->pdg_id();
1185 long MotherPDG(0);
1186
1187 auto MothOriVert = partOriVert;
1188 MothOriVert = nullptr;
1189 T theMoth(nullptr);
1190
1191 size_t itr = 0;
1192 do {
1193 if (itr != 0) partOriVert = MothOriVert;
1194 for ( const auto& p : particles_in(partOriVert) ) {
1195 theMoth = p;
1196 if (!theMoth) continue;
1197 MotherPDG = theMoth->pdg_id();
1198 MothOriVert = theMoth->production_vertex();
1199 if (MotherPDG == partPDG) break;
1200 }
1201 itr++;
1202 if (itr > 100) {
1203 break;
1204 }
1205 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1206 MothOriVert != partOriVert);
1207 return theMoth;
1208 }
1209
1211
1212 template <class C, class T> T findMatching(C TruthContainer, T p) {
1213 T ptrPart = nullptr;
1214 if (!p) return ptrPart;
1215 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1216 for (T truthParticle : *TruthContainer) {
1217 if (HepMC::is_sim_descendant(p,truthParticle)) {
1218 ptrPart = truthParticle;
1219 break;
1220 }
1221 }
1222 }
1223 else {
1224 for (T truthParticle : TruthContainer) {
1225 if (HepMC::is_sim_descendant(p,truthParticle)) {
1226 ptrPart = truthParticle;
1227 break;
1228 }
1229 }
1230 }
1231 return ptrPart;
1232 }
1234
1235 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1236 auto prodVtx = thePart->production_vertex();
1237 if (!prodVtx) return;
1238 for (const auto& theMother: prodVtx->particles_in()) {
1239 if (!theMother) continue;
1240 allancestors.insert(theMother);
1241 findParticleAncestors(theMother, allancestors);
1242 }
1243 }
1244
1246
1247 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1248 auto endVtx = thePart->end_vertex();
1249 if (!endVtx) return;
1250 for (const auto& theDaughter: endVtx->particles_out()) {
1251 if (!theDaughter) continue;
1252 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1253 allstabledescendants.insert(theDaughter);
1254 }
1255 findParticleStableDescendants(theDaughter, allstabledescendants);
1256 }
1257 }
1258
1262
1263 template <class T> bool isHardScatteringVertex(T pVert) {
1264 if (pVert == nullptr) return false;
1265 T pV = pVert;
1266 int numOfPartIn(0);
1267 int pdg(0);
1268
1269 do {
1270 pVert = pV;
1271 auto incoming = pVert->particles_in();
1272 numOfPartIn = incoming.size();
1273 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1274 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1275
1276 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1277
1278 if (numOfPartIn == 2) {
1279 auto incoming = pVert->particles_in();
1280 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1281 }
1282 return false;
1283}
1284
1288
1289 template <class T, class U>
1290 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1291 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1292 auto vtx = p->production_vertex();
1293 if (!vtx) return false;
1294 bool fromHad = false;
1295 for ( const auto& parent : particles_in(vtx) ) {
1296 if (!parent) continue;
1297 // should this really go into parton-level territory?
1298 // probably depends where BSM particles are being decayed
1299 fromBSM |= isBSM(parent);
1300 if (!isPhysical(parent)) return false;
1301 fromTau |= isTau(parent);
1302 if (isHadron(parent)&&!isBeam(parent)) {
1303 if (!hadron) hadron = parent; // assumes linear hadron parentage
1304 return true;
1305 }
1306 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1307 }
1308 return fromHad;
1309 }
1310
1313
1314 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1315 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1316 decltype(thePart->end_vertex()) pVert(nullptr);
1317 if (EndVert != nullptr) {
1318 do {
1319 bool samePart = false;
1320 pVert = nullptr;
1321 auto outgoing = EndVert->particles_out();
1322 auto incoming = EndVert->particles_in();
1323 for (const auto& itrDaug: outgoing) {
1324 if (!itrDaug) continue;
1325 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1326 // brem on generator level for tau
1327 (outgoing.size() == 1 && incoming.size() == 1 &&
1329 itrDaug->pdg_id() == thePart->pdg_id()) {
1330 samePart = true;
1331 pVert = itrDaug->end_vertex();
1332 }
1333 }
1334 if (samePart) EndVert = pVert;
1335 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1336 }
1337 return EndVert;
1338 }
1339
1341
1342 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1343 if (!theVert) return {};
1344 decltype(theVert->particles_out()) finalStatePart;
1345 auto outgoing = theVert->particles_out();
1346 for (const auto& thePart: outgoing) {
1347 if (!thePart) continue;
1348 finalStatePart.push_back(thePart);
1349 if (isStable(thePart)) continue;
1350 V pVert = findSimulatedEndVertex(thePart);
1351 if (pVert == theVert) break; // to prevent Sherpa loop
1352 if (pVert != nullptr) {
1353 auto vecPart = findFinalStateParticles<V>(pVert);
1354 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1355 }
1356 }
1357 return finalStatePart;
1358 }
1359
1360}
1361#endif

◆ charge3() [3/3]

template<class T>
int MC::charge3 ( const T & p)
inline

Definition at line 996 of file HepMCHelpers.h.

1017{
1018inline
1019auto particles_in (const HepMC::GenVertex* p) {
1020 return std::ranges::subrange (p->particles_in_const_begin(),
1021 p->particles_in_const_end());
1022}
1023}
1024#endif
1025
1026namespace MC
1027{
1028 template <class VTX>
1029 auto particles_in (const VTX* p) { return p->particles_in(); }
1030 template <class VTX>
1031 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1032
1033 namespace Pythia8
1034 {
1036 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1037
1038 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1039
1040 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1041 }
1042
1043#include "AtlasPID.h"
1044
1046 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1047
1049 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1050
1052 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1053
1055 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1056
1058 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1059
1061 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1062
1064 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1065
1067 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1068
1070 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1071
1073 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1074
1078 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1079 const auto vertex = p->end_vertex();
1080 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1081 }
1082
1084 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1085
1087 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1088 const int apid = std::abs(p->pdg_id());
1089 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1090 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1091 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1092 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1093 return false;
1094 }
1095
1097
1098 template <class T> T findMother(T thePart) {
1099 auto partOriVert = thePart->production_vertex();
1100 if (!partOriVert) return nullptr;
1101
1102 long partPDG = thePart->pdg_id();
1103 long MotherPDG(0);
1104
1105 auto MothOriVert = partOriVert;
1106 MothOriVert = nullptr;
1107 T theMoth(nullptr);
1108
1109 size_t itr = 0;
1110 do {
1111 if (itr != 0) partOriVert = MothOriVert;
1112 for ( const auto& p : particles_in(partOriVert) ) {
1113 theMoth = p;
1114 if (!theMoth) continue;
1115 MotherPDG = theMoth->pdg_id();
1116 MothOriVert = theMoth->production_vertex();
1117 if (MotherPDG == partPDG) break;
1118 }
1119 itr++;
1120 if (itr > 100) {
1121 break;
1122 }
1123 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1124 MothOriVert != partOriVert);
1125 return theMoth;
1126 }
1127
1129
1130 template <class C, class T> T findMatching(C TruthContainer, T p) {
1131 T ptrPart = nullptr;
1132 if (!p) return ptrPart;
1133 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1134 for (T truthParticle : *TruthContainer) {
1135 if (HepMC::is_sim_descendant(p,truthParticle)) {
1136 ptrPart = truthParticle;
1137 break;
1138 }
1139 }
1140 }
1141 else {
1142 for (T truthParticle : TruthContainer) {
1143 if (HepMC::is_sim_descendant(p,truthParticle)) {
1144 ptrPart = truthParticle;
1145 break;
1146 }
1147 }
1148 }
1149 return ptrPart;
1150 }
1152
1153 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1154 auto prodVtx = thePart->production_vertex();
1155 if (!prodVtx) return;
1156 for (const auto& theMother: prodVtx->particles_in()) {
1157 if (!theMother) continue;
1158 allancestors.insert(theMother);
1159 findParticleAncestors(theMother, allancestors);
1160 }
1161 }
1162
1164
1165 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1166 auto endVtx = thePart->end_vertex();
1167 if (!endVtx) return;
1168 for (const auto& theDaughter: endVtx->particles_out()) {
1169 if (!theDaughter) continue;
1170 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1171 allstabledescendants.insert(theDaughter);
1172 }
1173 findParticleStableDescendants(theDaughter, allstabledescendants);
1174 }
1175 }
1176
1180
1181 template <class T> bool isHardScatteringVertex(T pVert) {
1182 if (pVert == nullptr) return false;
1183 T pV = pVert;
1184 int numOfPartIn(0);
1185 int pdg(0);
1186
1187 do {
1188 pVert = pV;
1189 auto incoming = pVert->particles_in();
1190 numOfPartIn = incoming.size();
1191 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1192 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1193
1194 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1195
1196 if (numOfPartIn == 2) {
1197 auto incoming = pVert->particles_in();
1198 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1199 }
1200 return false;
1201}
1202
1206
1207 template <class T, class U>
1208 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1209 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1210 auto vtx = p->production_vertex();
1211 if (!vtx) return false;
1212 bool fromHad = false;
1213 for ( const auto& parent : particles_in(vtx) ) {
1214 if (!parent) continue;
1215 // should this really go into parton-level territory?
1216 // probably depends where BSM particles are being decayed
1217 fromBSM |= isBSM(parent);
1218 if (!isPhysical(parent)) return false;
1219 fromTau |= isTau(parent);
1220 if (isHadron(parent)&&!isBeam(parent)) {
1221 if (!hadron) hadron = parent; // assumes linear hadron parentage
1222 return true;
1223 }
1224 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1225 }
1226 return fromHad;
1227 }
1228
1231
1232 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1233 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1234 decltype(thePart->end_vertex()) pVert(nullptr);
1235 if (EndVert != nullptr) {
1236 do {
1237 bool samePart = false;
1238 pVert = nullptr;
1239 auto outgoing = EndVert->particles_out();
1240 auto incoming = EndVert->particles_in();
1241 for (const auto& itrDaug: outgoing) {
1242 if (!itrDaug) continue;
1243 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1244 // brem on generator level for tau
1245 (outgoing.size() == 1 && incoming.size() == 1 &&
1247 itrDaug->pdg_id() == thePart->pdg_id()) {
1248 samePart = true;
1249 pVert = itrDaug->end_vertex();
1250 }
1251 }
1252 if (samePart) EndVert = pVert;
1253 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1254 }
1255 return EndVert;
1256 }
1257
1259
1260 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1261 if (!theVert) return {};
1262 decltype(theVert->particles_out()) finalStatePart;
1263 auto outgoing = theVert->particles_out();
1264 for (const auto& thePart: outgoing) {
1265 if (!thePart) continue;
1266 finalStatePart.push_back(thePart);
1267 if (isStable(thePart)) continue;
1268 V pVert = findSimulatedEndVertex(thePart);
1269 if (pVert == theVert) break; // to prevent Sherpa loop
1270 if (pVert != nullptr) {
1271 auto vecPart = findFinalStateParticles<V>(pVert);
1272 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1273 }
1274 }
1275 return finalStatePart;
1276 }
1277
1278}
1279#endif

◆ containedQuarks() [1/3]

template<>
std::vector< int > MC::containedQuarks ( const DecodedPID & p)
inline

Definition at line 1177 of file HepMCHelpers.h.

1198{
1199inline
1200auto particles_in (const HepMC::GenVertex* p) {
1201 return std::ranges::subrange (p->particles_in_const_begin(),
1202 p->particles_in_const_end());
1203}
1204}
1205#endif
1206
1207namespace MC
1208{
1209 template <class VTX>
1210 auto particles_in (const VTX* p) { return p->particles_in(); }
1211 template <class VTX>
1212 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1213
1214 namespace Pythia8
1215 {
1217 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1218
1219 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1220
1221 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1222 }
1223
1224#include "AtlasPID.h"
1225
1227 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1228
1230 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1231
1233 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1234
1236 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1237
1239 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1240
1242 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1243
1245 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1246
1248 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1249
1251 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1252
1254 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1255
1259 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1260 const auto vertex = p->end_vertex();
1261 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1262 }
1263
1265 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1266
1268 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1269 const int apid = std::abs(p->pdg_id());
1270 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1271 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1272 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1273 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1274 return false;
1275 }
1276
1278
1279 template <class T> T findMother(T thePart) {
1280 auto partOriVert = thePart->production_vertex();
1281 if (!partOriVert) return nullptr;
1282
1283 long partPDG = thePart->pdg_id();
1284 long MotherPDG(0);
1285
1286 auto MothOriVert = partOriVert;
1287 MothOriVert = nullptr;
1288 T theMoth(nullptr);
1289
1290 size_t itr = 0;
1291 do {
1292 if (itr != 0) partOriVert = MothOriVert;
1293 for ( const auto& p : particles_in(partOriVert) ) {
1294 theMoth = p;
1295 if (!theMoth) continue;
1296 MotherPDG = theMoth->pdg_id();
1297 MothOriVert = theMoth->production_vertex();
1298 if (MotherPDG == partPDG) break;
1299 }
1300 itr++;
1301 if (itr > 100) {
1302 break;
1303 }
1304 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1305 MothOriVert != partOriVert);
1306 return theMoth;
1307 }
1308
1310
1311 template <class C, class T> T findMatching(C TruthContainer, T p) {
1312 T ptrPart = nullptr;
1313 if (!p) return ptrPart;
1314 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1315 for (T truthParticle : *TruthContainer) {
1316 if (HepMC::is_sim_descendant(p,truthParticle)) {
1317 ptrPart = truthParticle;
1318 break;
1319 }
1320 }
1321 }
1322 else {
1323 for (T truthParticle : TruthContainer) {
1324 if (HepMC::is_sim_descendant(p,truthParticle)) {
1325 ptrPart = truthParticle;
1326 break;
1327 }
1328 }
1329 }
1330 return ptrPart;
1331 }
1333
1334 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1335 auto prodVtx = thePart->production_vertex();
1336 if (!prodVtx) return;
1337 for (const auto& theMother: prodVtx->particles_in()) {
1338 if (!theMother) continue;
1339 allancestors.insert(theMother);
1340 findParticleAncestors(theMother, allancestors);
1341 }
1342 }
1343
1345
1346 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1347 auto endVtx = thePart->end_vertex();
1348 if (!endVtx) return;
1349 for (const auto& theDaughter: endVtx->particles_out()) {
1350 if (!theDaughter) continue;
1351 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1352 allstabledescendants.insert(theDaughter);
1353 }
1354 findParticleStableDescendants(theDaughter, allstabledescendants);
1355 }
1356 }
1357
1361
1362 template <class T> bool isHardScatteringVertex(T pVert) {
1363 if (pVert == nullptr) return false;
1364 T pV = pVert;
1365 int numOfPartIn(0);
1366 int pdg(0);
1367
1368 do {
1369 pVert = pV;
1370 auto incoming = pVert->particles_in();
1371 numOfPartIn = incoming.size();
1372 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1373 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1374
1375 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1376
1377 if (numOfPartIn == 2) {
1378 auto incoming = pVert->particles_in();
1379 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1380 }
1381 return false;
1382}
1383
1387
1388 template <class T, class U>
1389 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1390 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1391 auto vtx = p->production_vertex();
1392 if (!vtx) return false;
1393 bool fromHad = false;
1394 for ( const auto& parent : particles_in(vtx) ) {
1395 if (!parent) continue;
1396 // should this really go into parton-level territory?
1397 // probably depends where BSM particles are being decayed
1398 fromBSM |= isBSM(parent);
1399 if (!isPhysical(parent)) return false;
1400 fromTau |= isTau(parent);
1401 if (isHadron(parent)&&!isBeam(parent)) {
1402 if (!hadron) hadron = parent; // assumes linear hadron parentage
1403 return true;
1404 }
1405 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1406 }
1407 return fromHad;
1408 }
1409
1412
1413 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1414 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1415 decltype(thePart->end_vertex()) pVert(nullptr);
1416 if (EndVert != nullptr) {
1417 do {
1418 bool samePart = false;
1419 pVert = nullptr;
1420 auto outgoing = EndVert->particles_out();
1421 auto incoming = EndVert->particles_in();
1422 for (const auto& itrDaug: outgoing) {
1423 if (!itrDaug) continue;
1424 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1425 // brem on generator level for tau
1426 (outgoing.size() == 1 && incoming.size() == 1 &&
1428 itrDaug->pdg_id() == thePart->pdg_id()) {
1429 samePart = true;
1430 pVert = itrDaug->end_vertex();
1431 }
1432 }
1433 if (samePart) EndVert = pVert;
1434 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1435 }
1436 return EndVert;
1437 }
1438
1440
1441 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1442 if (!theVert) return {};
1443 decltype(theVert->particles_out()) finalStatePart;
1444 auto outgoing = theVert->particles_out();
1445 for (const auto& thePart: outgoing) {
1446 if (!thePart) continue;
1447 finalStatePart.push_back(thePart);
1448 if (isStable(thePart)) continue;
1449 V pVert = findSimulatedEndVertex(thePart);
1450 if (pVert == theVert) break; // to prevent Sherpa loop
1451 if (pVert != nullptr) {
1452 auto vecPart = findFinalStateParticles<V>(pVert);
1453 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1454 }
1455 }
1456 return finalStatePart;
1457 }
1458
1459}
1460#endif

◆ containedQuarks() [2/3]

template<>
std::vector< int > MC::containedQuarks ( const int & p)
inline

Definition at line 1155 of file HepMCHelpers.h.

1176 {
1177inline
1178auto particles_in (const HepMC::GenVertex* p) {
1179 return std::ranges::subrange (p->particles_in_const_begin(),
1180 p->particles_in_const_end());
1181}
1182}
1183#endif
1184
1185namespace MC
1186{
1187 template <class VTX>
1188 auto particles_in (const VTX* p) { return p->particles_in(); }
1189 template <class VTX>
1190 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1191
1192 namespace Pythia8
1193 {
1195 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1196
1197 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1198
1199 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1200 }
1201
1202#include "AtlasPID.h"
1203
1205 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1206
1208 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1209
1211 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1212
1214 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1215
1217 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1218
1220 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1221
1223 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1224
1226 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1227
1229 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1230
1232 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1233
1237 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1238 const auto vertex = p->end_vertex();
1239 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1240 }
1241
1243 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1244
1246 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1247 const int apid = std::abs(p->pdg_id());
1248 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1249 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1250 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1251 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1252 return false;
1253 }
1254
1256
1257 template <class T> T findMother(T thePart) {
1258 auto partOriVert = thePart->production_vertex();
1259 if (!partOriVert) return nullptr;
1260
1261 long partPDG = thePart->pdg_id();
1262 long MotherPDG(0);
1263
1264 auto MothOriVert = partOriVert;
1265 MothOriVert = nullptr;
1266 T theMoth(nullptr);
1267
1268 size_t itr = 0;
1269 do {
1270 if (itr != 0) partOriVert = MothOriVert;
1271 for ( const auto& p : particles_in(partOriVert) ) {
1272 theMoth = p;
1273 if (!theMoth) continue;
1274 MotherPDG = theMoth->pdg_id();
1275 MothOriVert = theMoth->production_vertex();
1276 if (MotherPDG == partPDG) break;
1277 }
1278 itr++;
1279 if (itr > 100) {
1280 break;
1281 }
1282 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1283 MothOriVert != partOriVert);
1284 return theMoth;
1285 }
1286
1288
1289 template <class C, class T> T findMatching(C TruthContainer, T p) {
1290 T ptrPart = nullptr;
1291 if (!p) return ptrPart;
1292 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1293 for (T truthParticle : *TruthContainer) {
1294 if (HepMC::is_sim_descendant(p,truthParticle)) {
1295 ptrPart = truthParticle;
1296 break;
1297 }
1298 }
1299 }
1300 else {
1301 for (T truthParticle : TruthContainer) {
1302 if (HepMC::is_sim_descendant(p,truthParticle)) {
1303 ptrPart = truthParticle;
1304 break;
1305 }
1306 }
1307 }
1308 return ptrPart;
1309 }
1311
1312 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1313 auto prodVtx = thePart->production_vertex();
1314 if (!prodVtx) return;
1315 for (const auto& theMother: prodVtx->particles_in()) {
1316 if (!theMother) continue;
1317 allancestors.insert(theMother);
1318 findParticleAncestors(theMother, allancestors);
1319 }
1320 }
1321
1323
1324 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1325 auto endVtx = thePart->end_vertex();
1326 if (!endVtx) return;
1327 for (const auto& theDaughter: endVtx->particles_out()) {
1328 if (!theDaughter) continue;
1329 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1330 allstabledescendants.insert(theDaughter);
1331 }
1332 findParticleStableDescendants(theDaughter, allstabledescendants);
1333 }
1334 }
1335
1339
1340 template <class T> bool isHardScatteringVertex(T pVert) {
1341 if (pVert == nullptr) return false;
1342 T pV = pVert;
1343 int numOfPartIn(0);
1344 int pdg(0);
1345
1346 do {
1347 pVert = pV;
1348 auto incoming = pVert->particles_in();
1349 numOfPartIn = incoming.size();
1350 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1351 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1352
1353 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1354
1355 if (numOfPartIn == 2) {
1356 auto incoming = pVert->particles_in();
1357 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1358 }
1359 return false;
1360}
1361
1365
1366 template <class T, class U>
1367 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1368 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1369 auto vtx = p->production_vertex();
1370 if (!vtx) return false;
1371 bool fromHad = false;
1372 for ( const auto& parent : particles_in(vtx) ) {
1373 if (!parent) continue;
1374 // should this really go into parton-level territory?
1375 // probably depends where BSM particles are being decayed
1376 fromBSM |= isBSM(parent);
1377 if (!isPhysical(parent)) return false;
1378 fromTau |= isTau(parent);
1379 if (isHadron(parent)&&!isBeam(parent)) {
1380 if (!hadron) hadron = parent; // assumes linear hadron parentage
1381 return true;
1382 }
1383 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1384 }
1385 return fromHad;
1386 }
1387
1390
1391 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1392 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1393 decltype(thePart->end_vertex()) pVert(nullptr);
1394 if (EndVert != nullptr) {
1395 do {
1396 bool samePart = false;
1397 pVert = nullptr;
1398 auto outgoing = EndVert->particles_out();
1399 auto incoming = EndVert->particles_in();
1400 for (const auto& itrDaug: outgoing) {
1401 if (!itrDaug) continue;
1402 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1403 // brem on generator level for tau
1404 (outgoing.size() == 1 && incoming.size() == 1 &&
1406 itrDaug->pdg_id() == thePart->pdg_id()) {
1407 samePart = true;
1408 pVert = itrDaug->end_vertex();
1409 }
1410 }
1411 if (samePart) EndVert = pVert;
1412 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1413 }
1414 return EndVert;
1415 }
1416
1418
1419 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1420 if (!theVert) return {};
1421 decltype(theVert->particles_out()) finalStatePart;
1422 auto outgoing = theVert->particles_out();
1423 for (const auto& thePart: outgoing) {
1424 if (!thePart) continue;
1425 finalStatePart.push_back(thePart);
1426 if (isStable(thePart)) continue;
1427 V pVert = findSimulatedEndVertex(thePart);
1428 if (pVert == theVert) break; // to prevent Sherpa loop
1429 if (pVert != nullptr) {
1430 auto vecPart = findFinalStateParticles<V>(pVert);
1431 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1432 }
1433 }
1434 return finalStatePart;
1435 }
1436
1437}
1438#endif

◆ containedQuarks() [3/3]

template<class T>
std::vector< int > MC::containedQuarks ( const T & p)
inline

Definition at line 1154 of file HepMCHelpers.h.

1175{
1176inline
1177auto particles_in (const HepMC::GenVertex* p) {
1178 return std::ranges::subrange (p->particles_in_const_begin(),
1179 p->particles_in_const_end());
1180}
1181}
1182#endif
1183
1184namespace MC
1185{
1186 template <class VTX>
1187 auto particles_in (const VTX* p) { return p->particles_in(); }
1188 template <class VTX>
1189 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1190
1191 namespace Pythia8
1192 {
1194 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1195
1196 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1197
1198 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1199 }
1200
1201#include "AtlasPID.h"
1202
1204 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1205
1207 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1208
1210 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1211
1213 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1214
1216 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1217
1219 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1220
1222 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1223
1225 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1226
1228 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1229
1231 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1232
1236 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1237 const auto vertex = p->end_vertex();
1238 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1239 }
1240
1242 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1243
1245 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1246 const int apid = std::abs(p->pdg_id());
1247 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1248 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1249 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1250 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1251 return false;
1252 }
1253
1255
1256 template <class T> T findMother(T thePart) {
1257 auto partOriVert = thePart->production_vertex();
1258 if (!partOriVert) return nullptr;
1259
1260 long partPDG = thePart->pdg_id();
1261 long MotherPDG(0);
1262
1263 auto MothOriVert = partOriVert;
1264 MothOriVert = nullptr;
1265 T theMoth(nullptr);
1266
1267 size_t itr = 0;
1268 do {
1269 if (itr != 0) partOriVert = MothOriVert;
1270 for ( const auto& p : particles_in(partOriVert) ) {
1271 theMoth = p;
1272 if (!theMoth) continue;
1273 MotherPDG = theMoth->pdg_id();
1274 MothOriVert = theMoth->production_vertex();
1275 if (MotherPDG == partPDG) break;
1276 }
1277 itr++;
1278 if (itr > 100) {
1279 break;
1280 }
1281 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1282 MothOriVert != partOriVert);
1283 return theMoth;
1284 }
1285
1287
1288 template <class C, class T> T findMatching(C TruthContainer, T p) {
1289 T ptrPart = nullptr;
1290 if (!p) return ptrPart;
1291 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1292 for (T truthParticle : *TruthContainer) {
1293 if (HepMC::is_sim_descendant(p,truthParticle)) {
1294 ptrPart = truthParticle;
1295 break;
1296 }
1297 }
1298 }
1299 else {
1300 for (T truthParticle : TruthContainer) {
1301 if (HepMC::is_sim_descendant(p,truthParticle)) {
1302 ptrPart = truthParticle;
1303 break;
1304 }
1305 }
1306 }
1307 return ptrPart;
1308 }
1310
1311 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1312 auto prodVtx = thePart->production_vertex();
1313 if (!prodVtx) return;
1314 for (const auto& theMother: prodVtx->particles_in()) {
1315 if (!theMother) continue;
1316 allancestors.insert(theMother);
1317 findParticleAncestors(theMother, allancestors);
1318 }
1319 }
1320
1322
1323 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1324 auto endVtx = thePart->end_vertex();
1325 if (!endVtx) return;
1326 for (const auto& theDaughter: endVtx->particles_out()) {
1327 if (!theDaughter) continue;
1328 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1329 allstabledescendants.insert(theDaughter);
1330 }
1331 findParticleStableDescendants(theDaughter, allstabledescendants);
1332 }
1333 }
1334
1338
1339 template <class T> bool isHardScatteringVertex(T pVert) {
1340 if (pVert == nullptr) return false;
1341 T pV = pVert;
1342 int numOfPartIn(0);
1343 int pdg(0);
1344
1345 do {
1346 pVert = pV;
1347 auto incoming = pVert->particles_in();
1348 numOfPartIn = incoming.size();
1349 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1350 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1351
1352 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1353
1354 if (numOfPartIn == 2) {
1355 auto incoming = pVert->particles_in();
1356 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1357 }
1358 return false;
1359}
1360
1364
1365 template <class T, class U>
1366 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1367 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1368 auto vtx = p->production_vertex();
1369 if (!vtx) return false;
1370 bool fromHad = false;
1371 for ( const auto& parent : particles_in(vtx) ) {
1372 if (!parent) continue;
1373 // should this really go into parton-level territory?
1374 // probably depends where BSM particles are being decayed
1375 fromBSM |= isBSM(parent);
1376 if (!isPhysical(parent)) return false;
1377 fromTau |= isTau(parent);
1378 if (isHadron(parent)&&!isBeam(parent)) {
1379 if (!hadron) hadron = parent; // assumes linear hadron parentage
1380 return true;
1381 }
1382 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1383 }
1384 return fromHad;
1385 }
1386
1389
1390 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1391 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1392 decltype(thePart->end_vertex()) pVert(nullptr);
1393 if (EndVert != nullptr) {
1394 do {
1395 bool samePart = false;
1396 pVert = nullptr;
1397 auto outgoing = EndVert->particles_out();
1398 auto incoming = EndVert->particles_in();
1399 for (const auto& itrDaug: outgoing) {
1400 if (!itrDaug) continue;
1401 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1402 // brem on generator level for tau
1403 (outgoing.size() == 1 && incoming.size() == 1 &&
1405 itrDaug->pdg_id() == thePart->pdg_id()) {
1406 samePart = true;
1407 pVert = itrDaug->end_vertex();
1408 }
1409 }
1410 if (samePart) EndVert = pVert;
1411 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1412 }
1413 return EndVert;
1414 }
1415
1417
1418 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1419 if (!theVert) return {};
1420 decltype(theVert->particles_out()) finalStatePart;
1421 auto outgoing = theVert->particles_out();
1422 for (const auto& thePart: outgoing) {
1423 if (!thePart) continue;
1424 finalStatePart.push_back(thePart);
1425 if (isStable(thePart)) continue;
1426 V pVert = findSimulatedEndVertex(thePart);
1427 if (pVert == theVert) break; // to prevent Sherpa loop
1428 if (pVert != nullptr) {
1429 auto vecPart = findFinalStateParticles<V>(pVert);
1430 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1431 }
1432 }
1433 return finalStatePart;
1434 }
1435
1436}
1437#endif

◆ findFinalStateParticles()

template<class V>
auto MC::findFinalStateParticles ( V theVert) -> decltype(theVert->particles_out())

Function to find the stable particle descendants of the given vertex..

This can be used for HepMC3::GenVertexPtr, HepMC3::ConstGenVertexPtr or xAOD::TruthVertex* and particle counterparts

Definition at line 265 of file HepMCHelpers.h.

265 {
266 if (!theVert) return {};
267 decltype(theVert->particles_out()) finalStatePart;
268 auto outgoing = theVert->particles_out();
269 for (const auto& thePart: outgoing) {
270 if (!thePart) continue;
271 finalStatePart.push_back(thePart);
272 if (isStable(thePart)) continue;
273 V pVert = findSimulatedEndVertex(thePart);
274 if (pVert == theVert) break; // to prevent Sherpa loop
275 if (pVert != nullptr) {
276 auto vecPart = findFinalStateParticles<V>(pVert);
277 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
278 }
279 }
280 return finalStatePart;
281 }

◆ findMatching()

template<class C, class T>
T MC::findMatching ( C TruthContainer,
T p )

Function to find a particle in container.

This can be used for HepMC3::GenVertexPtr, HepMC3::ConstGenVertexPtr or xAOD::TruthVertex*

Definition at line 135 of file HepMCHelpers.h.

135 {
136 T ptrPart = nullptr;
137 if (!p) return ptrPart;
138 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
139 for (T truthParticle : *TruthContainer) {
140 if (HepMC::is_sim_descendant(p,truthParticle)) {
141 ptrPart = truthParticle;
142 break;
143 }
144 }
145 }
146 else {
147 for (T truthParticle : TruthContainer) {
148 if (HepMC::is_sim_descendant(p,truthParticle)) {
149 ptrPart = truthParticle;
150 break;
151 }
152 }
153 }
154 return ptrPart;
155 }

◆ findMother()

template<class T>
T MC::findMother ( T thePart)

Function to get a mother of particle. MCTruthClassifier legacy.

This can be used for HepMC3::GenVertexPtr, HepMC3::ConstGenVertexPtr or xAOD::TruthVertex*

Definition at line 103 of file HepMCHelpers.h.

103 {
104 auto partOriVert = thePart->production_vertex();
105 if (!partOriVert) return nullptr;
106
107 long partPDG = thePart->pdg_id();
108 long MotherPDG(0);
109
110 auto MothOriVert = partOriVert;
111 MothOriVert = nullptr;
112 T theMoth(nullptr);
113
114 size_t itr = 0;
115 do {
116 if (itr != 0) partOriVert = MothOriVert;
117 for ( const auto& p : particles_in(partOriVert) ) {
118 theMoth = p;
119 if (!theMoth) continue;
120 MotherPDG = theMoth->pdg_id();
121 MothOriVert = theMoth->production_vertex();
122 if (MotherPDG == partPDG) break;
123 }
124 itr++;
125 if (itr > 100) {
126 break;
127 }
128 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
129 MothOriVert != partOriVert);
130 return theMoth;
131 }

◆ findParticleAncestors()

template<class T>
void MC::findParticleAncestors ( T thePart,
std::set< T > & allancestors )

Function to find all ancestors of the particle.

This can be used for HepMC3::GenParticlePtr, HepMC3::ConstGenParticlePtr or xAOD::TruthParticle*

Definition at line 158 of file HepMCHelpers.h.

158 {
159 auto prodVtx = thePart->production_vertex();
160 if (!prodVtx) return;
161 for (const auto& theMother: prodVtx->particles_in()) {
162 if (!theMother) continue;
163 allancestors.insert(theMother);
164 findParticleAncestors(theMother, allancestors);
165 }
166 }

◆ findParticleStableDescendants()

template<class T>
void MC::findParticleStableDescendants ( T thePart,
std::set< T > & allstabledescendants )

Function to get the particle stable MC daughters.

This can be used for HepMC3::GenParticlePtr, HepMC3::ConstGenParticlePtr or xAOD::TruthParticle*

Definition at line 170 of file HepMCHelpers.h.

170 {
171 auto endVtx = thePart->end_vertex();
172 if (!endVtx) return;
173 for (const auto& theDaughter: endVtx->particles_out()) {
174 if (!theDaughter) continue;
175 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
176 allstabledescendants.insert(theDaughter);
177 }
178 findParticleStableDescendants(theDaughter, allstabledescendants);
179 }
180 }

◆ findSimulatedEndVertex()

template<class T>
auto MC::findSimulatedEndVertex ( T thePart) -> decltype(thePart->end_vertex())

Function to find the end vertex of a particle.

This algorithm allows for 1->1 decays. This can be used for HepMC3::GenVertexPtr, HepMC3::ConstGenVertexPtr or xAOD::TruthVertex* and particle counterparts

Definition at line 237 of file HepMCHelpers.h.

237 {
238 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
239 decltype(thePart->end_vertex()) pVert(nullptr);
240 if (EndVert != nullptr) {
241 do {
242 bool samePart = false;
243 pVert = nullptr;
244 auto outgoing = EndVert->particles_out();
245 auto incoming = EndVert->particles_in();
246 for (const auto& itrDaug: outgoing) {
247 if (!itrDaug) continue;
248 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
249 // brem on generator level for tau
250 (outgoing.size() == 1 && incoming.size() == 1 &&
252 itrDaug->pdg_id() == thePart->pdg_id()) {
253 samePart = true;
254 pVert = itrDaug->end_vertex();
255 }
256 }
257 if (samePart) EndVert = pVert;
258 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
259 }
260 return EndVert;
261 }

◆ fractionalCharge() [1/3]

template<>
double MC::fractionalCharge ( const DecodedPID & p)
inline

Definition at line 1091 of file HepMCHelpers.h.

1112 {
1113inline
1114auto particles_in (const HepMC::GenVertex* p) {
1115 return std::ranges::subrange (p->particles_in_const_begin(),
1116 p->particles_in_const_end());
1117}
1118}
1119#endif
1120
1121namespace MC
1122{
1123 template <class VTX>
1124 auto particles_in (const VTX* p) { return p->particles_in(); }
1125 template <class VTX>
1126 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1127
1128 namespace Pythia8
1129 {
1131 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1132
1133 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1134
1135 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1136 }
1137
1138#include "AtlasPID.h"
1139
1141 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1142
1144 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1145
1147 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1148
1150 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1151
1153 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1154
1156 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1157
1159 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1160
1162 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1163
1165 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1166
1168 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1169
1173 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1174 const auto vertex = p->end_vertex();
1175 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1176 }
1177
1179 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1180
1182 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1183 const int apid = std::abs(p->pdg_id());
1184 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1185 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1186 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1187 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1188 return false;
1189 }
1190
1192
1193 template <class T> T findMother(T thePart) {
1194 auto partOriVert = thePart->production_vertex();
1195 if (!partOriVert) return nullptr;
1196
1197 long partPDG = thePart->pdg_id();
1198 long MotherPDG(0);
1199
1200 auto MothOriVert = partOriVert;
1201 MothOriVert = nullptr;
1202 T theMoth(nullptr);
1203
1204 size_t itr = 0;
1205 do {
1206 if (itr != 0) partOriVert = MothOriVert;
1207 for ( const auto& p : particles_in(partOriVert) ) {
1208 theMoth = p;
1209 if (!theMoth) continue;
1210 MotherPDG = theMoth->pdg_id();
1211 MothOriVert = theMoth->production_vertex();
1212 if (MotherPDG == partPDG) break;
1213 }
1214 itr++;
1215 if (itr > 100) {
1216 break;
1217 }
1218 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1219 MothOriVert != partOriVert);
1220 return theMoth;
1221 }
1222
1224
1225 template <class C, class T> T findMatching(C TruthContainer, T p) {
1226 T ptrPart = nullptr;
1227 if (!p) return ptrPart;
1228 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1229 for (T truthParticle : *TruthContainer) {
1230 if (HepMC::is_sim_descendant(p,truthParticle)) {
1231 ptrPart = truthParticle;
1232 break;
1233 }
1234 }
1235 }
1236 else {
1237 for (T truthParticle : TruthContainer) {
1238 if (HepMC::is_sim_descendant(p,truthParticle)) {
1239 ptrPart = truthParticle;
1240 break;
1241 }
1242 }
1243 }
1244 return ptrPart;
1245 }
1247
1248 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1249 auto prodVtx = thePart->production_vertex();
1250 if (!prodVtx) return;
1251 for (const auto& theMother: prodVtx->particles_in()) {
1252 if (!theMother) continue;
1253 allancestors.insert(theMother);
1254 findParticleAncestors(theMother, allancestors);
1255 }
1256 }
1257
1259
1260 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1261 auto endVtx = thePart->end_vertex();
1262 if (!endVtx) return;
1263 for (const auto& theDaughter: endVtx->particles_out()) {
1264 if (!theDaughter) continue;
1265 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1266 allstabledescendants.insert(theDaughter);
1267 }
1268 findParticleStableDescendants(theDaughter, allstabledescendants);
1269 }
1270 }
1271
1275
1276 template <class T> bool isHardScatteringVertex(T pVert) {
1277 if (pVert == nullptr) return false;
1278 T pV = pVert;
1279 int numOfPartIn(0);
1280 int pdg(0);
1281
1282 do {
1283 pVert = pV;
1284 auto incoming = pVert->particles_in();
1285 numOfPartIn = incoming.size();
1286 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1287 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1288
1289 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1290
1291 if (numOfPartIn == 2) {
1292 auto incoming = pVert->particles_in();
1293 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1294 }
1295 return false;
1296}
1297
1301
1302 template <class T, class U>
1303 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1304 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1305 auto vtx = p->production_vertex();
1306 if (!vtx) return false;
1307 bool fromHad = false;
1308 for ( const auto& parent : particles_in(vtx) ) {
1309 if (!parent) continue;
1310 // should this really go into parton-level territory?
1311 // probably depends where BSM particles are being decayed
1312 fromBSM |= isBSM(parent);
1313 if (!isPhysical(parent)) return false;
1314 fromTau |= isTau(parent);
1315 if (isHadron(parent)&&!isBeam(parent)) {
1316 if (!hadron) hadron = parent; // assumes linear hadron parentage
1317 return true;
1318 }
1319 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1320 }
1321 return fromHad;
1322 }
1323
1326
1327 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1328 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1329 decltype(thePart->end_vertex()) pVert(nullptr);
1330 if (EndVert != nullptr) {
1331 do {
1332 bool samePart = false;
1333 pVert = nullptr;
1334 auto outgoing = EndVert->particles_out();
1335 auto incoming = EndVert->particles_in();
1336 for (const auto& itrDaug: outgoing) {
1337 if (!itrDaug) continue;
1338 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1339 // brem on generator level for tau
1340 (outgoing.size() == 1 && incoming.size() == 1 &&
1342 itrDaug->pdg_id() == thePart->pdg_id()) {
1343 samePart = true;
1344 pVert = itrDaug->end_vertex();
1345 }
1346 }
1347 if (samePart) EndVert = pVert;
1348 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1349 }
1350 return EndVert;
1351 }
1352
1354
1355 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1356 if (!theVert) return {};
1357 decltype(theVert->particles_out()) finalStatePart;
1358 auto outgoing = theVert->particles_out();
1359 for (const auto& thePart: outgoing) {
1360 if (!thePart) continue;
1361 finalStatePart.push_back(thePart);
1362 if (isStable(thePart)) continue;
1363 V pVert = findSimulatedEndVertex(thePart);
1364 if (pVert == theVert) break; // to prevent Sherpa loop
1365 if (pVert != nullptr) {
1366 auto vecPart = findFinalStateParticles<V>(pVert);
1367 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1368 }
1369 }
1370 return finalStatePart;
1371 }
1372
1373}
1374#endif

◆ fractionalCharge() [2/3]

template<>
double MC::fractionalCharge ( const int & p)
inline

Definition at line 1098 of file HepMCHelpers.h.

1119{
1120inline
1121auto particles_in (const HepMC::GenVertex* p) {
1122 return std::ranges::subrange (p->particles_in_const_begin(),
1123 p->particles_in_const_end());
1124}
1125}
1126#endif
1127
1128namespace MC
1129{
1130 template <class VTX>
1131 auto particles_in (const VTX* p) { return p->particles_in(); }
1132 template <class VTX>
1133 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1134
1135 namespace Pythia8
1136 {
1138 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1139
1140 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1141
1142 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1143 }
1144
1145#include "AtlasPID.h"
1146
1148 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1149
1151 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1152
1154 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1155
1157 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1158
1160 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1161
1163 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1164
1166 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1167
1169 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1170
1172 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1173
1175 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1176
1180 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1181 const auto vertex = p->end_vertex();
1182 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1183 }
1184
1186 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1187
1189 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1190 const int apid = std::abs(p->pdg_id());
1191 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1192 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1193 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1194 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1195 return false;
1196 }
1197
1199
1200 template <class T> T findMother(T thePart) {
1201 auto partOriVert = thePart->production_vertex();
1202 if (!partOriVert) return nullptr;
1203
1204 long partPDG = thePart->pdg_id();
1205 long MotherPDG(0);
1206
1207 auto MothOriVert = partOriVert;
1208 MothOriVert = nullptr;
1209 T theMoth(nullptr);
1210
1211 size_t itr = 0;
1212 do {
1213 if (itr != 0) partOriVert = MothOriVert;
1214 for ( const auto& p : particles_in(partOriVert) ) {
1215 theMoth = p;
1216 if (!theMoth) continue;
1217 MotherPDG = theMoth->pdg_id();
1218 MothOriVert = theMoth->production_vertex();
1219 if (MotherPDG == partPDG) break;
1220 }
1221 itr++;
1222 if (itr > 100) {
1223 break;
1224 }
1225 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1226 MothOriVert != partOriVert);
1227 return theMoth;
1228 }
1229
1231
1232 template <class C, class T> T findMatching(C TruthContainer, T p) {
1233 T ptrPart = nullptr;
1234 if (!p) return ptrPart;
1235 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1236 for (T truthParticle : *TruthContainer) {
1237 if (HepMC::is_sim_descendant(p,truthParticle)) {
1238 ptrPart = truthParticle;
1239 break;
1240 }
1241 }
1242 }
1243 else {
1244 for (T truthParticle : TruthContainer) {
1245 if (HepMC::is_sim_descendant(p,truthParticle)) {
1246 ptrPart = truthParticle;
1247 break;
1248 }
1249 }
1250 }
1251 return ptrPart;
1252 }
1254
1255 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1256 auto prodVtx = thePart->production_vertex();
1257 if (!prodVtx) return;
1258 for (const auto& theMother: prodVtx->particles_in()) {
1259 if (!theMother) continue;
1260 allancestors.insert(theMother);
1261 findParticleAncestors(theMother, allancestors);
1262 }
1263 }
1264
1266
1267 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1268 auto endVtx = thePart->end_vertex();
1269 if (!endVtx) return;
1270 for (const auto& theDaughter: endVtx->particles_out()) {
1271 if (!theDaughter) continue;
1272 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1273 allstabledescendants.insert(theDaughter);
1274 }
1275 findParticleStableDescendants(theDaughter, allstabledescendants);
1276 }
1277 }
1278
1282
1283 template <class T> bool isHardScatteringVertex(T pVert) {
1284 if (pVert == nullptr) return false;
1285 T pV = pVert;
1286 int numOfPartIn(0);
1287 int pdg(0);
1288
1289 do {
1290 pVert = pV;
1291 auto incoming = pVert->particles_in();
1292 numOfPartIn = incoming.size();
1293 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1294 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1295
1296 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1297
1298 if (numOfPartIn == 2) {
1299 auto incoming = pVert->particles_in();
1300 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1301 }
1302 return false;
1303}
1304
1308
1309 template <class T, class U>
1310 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1311 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1312 auto vtx = p->production_vertex();
1313 if (!vtx) return false;
1314 bool fromHad = false;
1315 for ( const auto& parent : particles_in(vtx) ) {
1316 if (!parent) continue;
1317 // should this really go into parton-level territory?
1318 // probably depends where BSM particles are being decayed
1319 fromBSM |= isBSM(parent);
1320 if (!isPhysical(parent)) return false;
1321 fromTau |= isTau(parent);
1322 if (isHadron(parent)&&!isBeam(parent)) {
1323 if (!hadron) hadron = parent; // assumes linear hadron parentage
1324 return true;
1325 }
1326 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1327 }
1328 return fromHad;
1329 }
1330
1333
1334 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1335 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1336 decltype(thePart->end_vertex()) pVert(nullptr);
1337 if (EndVert != nullptr) {
1338 do {
1339 bool samePart = false;
1340 pVert = nullptr;
1341 auto outgoing = EndVert->particles_out();
1342 auto incoming = EndVert->particles_in();
1343 for (const auto& itrDaug: outgoing) {
1344 if (!itrDaug) continue;
1345 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1346 // brem on generator level for tau
1347 (outgoing.size() == 1 && incoming.size() == 1 &&
1349 itrDaug->pdg_id() == thePart->pdg_id()) {
1350 samePart = true;
1351 pVert = itrDaug->end_vertex();
1352 }
1353 }
1354 if (samePart) EndVert = pVert;
1355 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1356 }
1357 return EndVert;
1358 }
1359
1361
1362 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1363 if (!theVert) return {};
1364 decltype(theVert->particles_out()) finalStatePart;
1365 auto outgoing = theVert->particles_out();
1366 for (const auto& thePart: outgoing) {
1367 if (!thePart) continue;
1368 finalStatePart.push_back(thePart);
1369 if (isStable(thePart)) continue;
1370 V pVert = findSimulatedEndVertex(thePart);
1371 if (pVert == theVert) break; // to prevent Sherpa loop
1372 if (pVert != nullptr) {
1373 auto vecPart = findFinalStateParticles<V>(pVert);
1374 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1375 }
1376 }
1377 return finalStatePart;
1378 }
1379
1380}
1381#endif

◆ fractionalCharge() [3/3]

template<class T>
double MC::fractionalCharge ( const T & p)
inline

Definition at line 997 of file HepMCHelpers.h.

1018{
1019inline
1020auto particles_in (const HepMC::GenVertex* p) {
1021 return std::ranges::subrange (p->particles_in_const_begin(),
1022 p->particles_in_const_end());
1023}
1024}
1025#endif
1026
1027namespace MC
1028{
1029 template <class VTX>
1030 auto particles_in (const VTX* p) { return p->particles_in(); }
1031 template <class VTX>
1032 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1033
1034 namespace Pythia8
1035 {
1037 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1038
1039 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1040
1041 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1042 }
1043
1044#include "AtlasPID.h"
1045
1047 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1048
1050 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1051
1053 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1054
1056 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1057
1059 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1060
1062 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1063
1065 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1066
1068 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1069
1071 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1072
1074 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1075
1079 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1080 const auto vertex = p->end_vertex();
1081 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1082 }
1083
1085 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1086
1088 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1089 const int apid = std::abs(p->pdg_id());
1090 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1091 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1092 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1093 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1094 return false;
1095 }
1096
1098
1099 template <class T> T findMother(T thePart) {
1100 auto partOriVert = thePart->production_vertex();
1101 if (!partOriVert) return nullptr;
1102
1103 long partPDG = thePart->pdg_id();
1104 long MotherPDG(0);
1105
1106 auto MothOriVert = partOriVert;
1107 MothOriVert = nullptr;
1108 T theMoth(nullptr);
1109
1110 size_t itr = 0;
1111 do {
1112 if (itr != 0) partOriVert = MothOriVert;
1113 for ( const auto& p : particles_in(partOriVert) ) {
1114 theMoth = p;
1115 if (!theMoth) continue;
1116 MotherPDG = theMoth->pdg_id();
1117 MothOriVert = theMoth->production_vertex();
1118 if (MotherPDG == partPDG) break;
1119 }
1120 itr++;
1121 if (itr > 100) {
1122 break;
1123 }
1124 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1125 MothOriVert != partOriVert);
1126 return theMoth;
1127 }
1128
1130
1131 template <class C, class T> T findMatching(C TruthContainer, T p) {
1132 T ptrPart = nullptr;
1133 if (!p) return ptrPart;
1134 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1135 for (T truthParticle : *TruthContainer) {
1136 if (HepMC::is_sim_descendant(p,truthParticle)) {
1137 ptrPart = truthParticle;
1138 break;
1139 }
1140 }
1141 }
1142 else {
1143 for (T truthParticle : TruthContainer) {
1144 if (HepMC::is_sim_descendant(p,truthParticle)) {
1145 ptrPart = truthParticle;
1146 break;
1147 }
1148 }
1149 }
1150 return ptrPart;
1151 }
1153
1154 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1155 auto prodVtx = thePart->production_vertex();
1156 if (!prodVtx) return;
1157 for (const auto& theMother: prodVtx->particles_in()) {
1158 if (!theMother) continue;
1159 allancestors.insert(theMother);
1160 findParticleAncestors(theMother, allancestors);
1161 }
1162 }
1163
1165
1166 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1167 auto endVtx = thePart->end_vertex();
1168 if (!endVtx) return;
1169 for (const auto& theDaughter: endVtx->particles_out()) {
1170 if (!theDaughter) continue;
1171 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1172 allstabledescendants.insert(theDaughter);
1173 }
1174 findParticleStableDescendants(theDaughter, allstabledescendants);
1175 }
1176 }
1177
1181
1182 template <class T> bool isHardScatteringVertex(T pVert) {
1183 if (pVert == nullptr) return false;
1184 T pV = pVert;
1185 int numOfPartIn(0);
1186 int pdg(0);
1187
1188 do {
1189 pVert = pV;
1190 auto incoming = pVert->particles_in();
1191 numOfPartIn = incoming.size();
1192 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1193 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1194
1195 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1196
1197 if (numOfPartIn == 2) {
1198 auto incoming = pVert->particles_in();
1199 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1200 }
1201 return false;
1202}
1203
1207
1208 template <class T, class U>
1209 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1210 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1211 auto vtx = p->production_vertex();
1212 if (!vtx) return false;
1213 bool fromHad = false;
1214 for ( const auto& parent : particles_in(vtx) ) {
1215 if (!parent) continue;
1216 // should this really go into parton-level territory?
1217 // probably depends where BSM particles are being decayed
1218 fromBSM |= isBSM(parent);
1219 if (!isPhysical(parent)) return false;
1220 fromTau |= isTau(parent);
1221 if (isHadron(parent)&&!isBeam(parent)) {
1222 if (!hadron) hadron = parent; // assumes linear hadron parentage
1223 return true;
1224 }
1225 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1226 }
1227 return fromHad;
1228 }
1229
1232
1233 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1234 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1235 decltype(thePart->end_vertex()) pVert(nullptr);
1236 if (EndVert != nullptr) {
1237 do {
1238 bool samePart = false;
1239 pVert = nullptr;
1240 auto outgoing = EndVert->particles_out();
1241 auto incoming = EndVert->particles_in();
1242 for (const auto& itrDaug: outgoing) {
1243 if (!itrDaug) continue;
1244 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1245 // brem on generator level for tau
1246 (outgoing.size() == 1 && incoming.size() == 1 &&
1248 itrDaug->pdg_id() == thePart->pdg_id()) {
1249 samePart = true;
1250 pVert = itrDaug->end_vertex();
1251 }
1252 }
1253 if (samePart) EndVert = pVert;
1254 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1255 }
1256 return EndVert;
1257 }
1258
1260
1261 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1262 if (!theVert) return {};
1263 decltype(theVert->particles_out()) finalStatePart;
1264 auto outgoing = theVert->particles_out();
1265 for (const auto& thePart: outgoing) {
1266 if (!thePart) continue;
1267 finalStatePart.push_back(thePart);
1268 if (isStable(thePart)) continue;
1269 V pVert = findSimulatedEndVertex(thePart);
1270 if (pVert == theVert) break; // to prevent Sherpa loop
1271 if (pVert != nullptr) {
1272 auto vecPart = findFinalStateParticles<V>(pVert);
1273 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1274 }
1275 }
1276 return finalStatePart;
1277 }
1278
1279}
1280#endif

◆ hasBottom()

template<class T>
bool MC::hasBottom ( const T & p)
inline

Definition at line 739 of file HepMCHelpers.h.

760{
761inline
762auto particles_in (const HepMC::GenVertex* p) {
763 return std::ranges::subrange (p->particles_in_const_begin(),
764 p->particles_in_const_end());
765}
766}
767#endif
768
769namespace MC
770{
771 template <class VTX>
772 auto particles_in (const VTX* p) { return p->particles_in(); }
773 template <class VTX>
774 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
775
776 namespace Pythia8
777 {
779 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
780
781 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
782
783 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
784 }
785
786#include "AtlasPID.h"
787
789 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
790
792 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
793
795 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
796
798 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
799
801 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
802
804 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
805
807 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
808
810 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
811
813 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
814
816 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
817
821 template <class T> inline bool isStableOrSimDecayed(const T& p) {
822 const auto vertex = p->end_vertex();
823 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
824 }
825
827 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
828
830 template <class T> inline bool isSpecialNonInteracting(const T& p) {
831 const int apid = std::abs(p->pdg_id());
832 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
833 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
834 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
835 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
836 return false;
837 }
838
840
841 template <class T> T findMother(T thePart) {
842 auto partOriVert = thePart->production_vertex();
843 if (!partOriVert) return nullptr;
844
845 long partPDG = thePart->pdg_id();
846 long MotherPDG(0);
847
848 auto MothOriVert = partOriVert;
849 MothOriVert = nullptr;
850 T theMoth(nullptr);
851
852 size_t itr = 0;
853 do {
854 if (itr != 0) partOriVert = MothOriVert;
855 for ( const auto& p : particles_in(partOriVert) ) {
856 theMoth = p;
857 if (!theMoth) continue;
858 MotherPDG = theMoth->pdg_id();
859 MothOriVert = theMoth->production_vertex();
860 if (MotherPDG == partPDG) break;
861 }
862 itr++;
863 if (itr > 100) {
864 break;
865 }
866 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
867 MothOriVert != partOriVert);
868 return theMoth;
869 }
870
872
873 template <class C, class T> T findMatching(C TruthContainer, T p) {
874 T ptrPart = nullptr;
875 if (!p) return ptrPart;
876 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
877 for (T truthParticle : *TruthContainer) {
878 if (HepMC::is_sim_descendant(p,truthParticle)) {
879 ptrPart = truthParticle;
880 break;
881 }
882 }
883 }
884 else {
885 for (T truthParticle : TruthContainer) {
886 if (HepMC::is_sim_descendant(p,truthParticle)) {
887 ptrPart = truthParticle;
888 break;
889 }
890 }
891 }
892 return ptrPart;
893 }
895
896 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
897 auto prodVtx = thePart->production_vertex();
898 if (!prodVtx) return;
899 for (const auto& theMother: prodVtx->particles_in()) {
900 if (!theMother) continue;
901 allancestors.insert(theMother);
902 findParticleAncestors(theMother, allancestors);
903 }
904 }
905
907
908 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
909 auto endVtx = thePart->end_vertex();
910 if (!endVtx) return;
911 for (const auto& theDaughter: endVtx->particles_out()) {
912 if (!theDaughter) continue;
913 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
914 allstabledescendants.insert(theDaughter);
915 }
916 findParticleStableDescendants(theDaughter, allstabledescendants);
917 }
918 }
919
923
924 template <class T> bool isHardScatteringVertex(T pVert) {
925 if (pVert == nullptr) return false;
926 T pV = pVert;
927 int numOfPartIn(0);
928 int pdg(0);
929
930 do {
931 pVert = pV;
932 auto incoming = pVert->particles_in();
933 numOfPartIn = incoming.size();
934 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
935 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
936
937 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
938
939 if (numOfPartIn == 2) {
940 auto incoming = pVert->particles_in();
941 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
942 }
943 return false;
944}
945
949
950 template <class T, class U>
951 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
952 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
953 auto vtx = p->production_vertex();
954 if (!vtx) return false;
955 bool fromHad = false;
956 for ( const auto& parent : particles_in(vtx) ) {
957 if (!parent) continue;
958 // should this really go into parton-level territory?
959 // probably depends where BSM particles are being decayed
960 fromBSM |= isBSM(parent);
961 if (!isPhysical(parent)) return false;
962 fromTau |= isTau(parent);
963 if (isHadron(parent)&&!isBeam(parent)) {
964 if (!hadron) hadron = parent; // assumes linear hadron parentage
965 return true;
966 }
967 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
968 }
969 return fromHad;
970 }
971
974
975 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
976 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
977 decltype(thePart->end_vertex()) pVert(nullptr);
978 if (EndVert != nullptr) {
979 do {
980 bool samePart = false;
981 pVert = nullptr;
982 auto outgoing = EndVert->particles_out();
983 auto incoming = EndVert->particles_in();
984 for (const auto& itrDaug: outgoing) {
985 if (!itrDaug) continue;
986 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
987 // brem on generator level for tau
988 (outgoing.size() == 1 && incoming.size() == 1 &&
990 itrDaug->pdg_id() == thePart->pdg_id()) {
991 samePart = true;
992 pVert = itrDaug->end_vertex();
993 }
994 }
995 if (samePart) EndVert = pVert;
996 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
997 }
998 return EndVert;
999 }
1000
1002
1003 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1004 if (!theVert) return {};
1005 decltype(theVert->particles_out()) finalStatePart;
1006 auto outgoing = theVert->particles_out();
1007 for (const auto& thePart: outgoing) {
1008 if (!thePart) continue;
1009 finalStatePart.push_back(thePart);
1010 if (isStable(thePart)) continue;
1011 V pVert = findSimulatedEndVertex(thePart);
1012 if (pVert == theVert) break; // to prevent Sherpa loop
1013 if (pVert != nullptr) {
1014 auto vecPart = findFinalStateParticles<V>(pVert);
1015 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1016 }
1017 }
1018 return finalStatePart;
1019 }
1020
1021}
1022#endif

◆ hasCharm()

template<class T>
bool MC::hasCharm ( const T & p)
inline

Definition at line 738 of file HepMCHelpers.h.

759{
760inline
761auto particles_in (const HepMC::GenVertex* p) {
762 return std::ranges::subrange (p->particles_in_const_begin(),
763 p->particles_in_const_end());
764}
765}
766#endif
767
768namespace MC
769{
770 template <class VTX>
771 auto particles_in (const VTX* p) { return p->particles_in(); }
772 template <class VTX>
773 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
774
775 namespace Pythia8
776 {
778 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
779
780 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
781
782 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
783 }
784
785#include "AtlasPID.h"
786
788 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
789
791 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
792
794 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
795
797 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
798
800 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
801
803 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
804
806 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
807
809 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
810
812 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
813
815 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
816
820 template <class T> inline bool isStableOrSimDecayed(const T& p) {
821 const auto vertex = p->end_vertex();
822 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
823 }
824
826 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
827
829 template <class T> inline bool isSpecialNonInteracting(const T& p) {
830 const int apid = std::abs(p->pdg_id());
831 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
832 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
833 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
834 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
835 return false;
836 }
837
839
840 template <class T> T findMother(T thePart) {
841 auto partOriVert = thePart->production_vertex();
842 if (!partOriVert) return nullptr;
843
844 long partPDG = thePart->pdg_id();
845 long MotherPDG(0);
846
847 auto MothOriVert = partOriVert;
848 MothOriVert = nullptr;
849 T theMoth(nullptr);
850
851 size_t itr = 0;
852 do {
853 if (itr != 0) partOriVert = MothOriVert;
854 for ( const auto& p : particles_in(partOriVert) ) {
855 theMoth = p;
856 if (!theMoth) continue;
857 MotherPDG = theMoth->pdg_id();
858 MothOriVert = theMoth->production_vertex();
859 if (MotherPDG == partPDG) break;
860 }
861 itr++;
862 if (itr > 100) {
863 break;
864 }
865 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
866 MothOriVert != partOriVert);
867 return theMoth;
868 }
869
871
872 template <class C, class T> T findMatching(C TruthContainer, T p) {
873 T ptrPart = nullptr;
874 if (!p) return ptrPart;
875 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
876 for (T truthParticle : *TruthContainer) {
877 if (HepMC::is_sim_descendant(p,truthParticle)) {
878 ptrPart = truthParticle;
879 break;
880 }
881 }
882 }
883 else {
884 for (T truthParticle : TruthContainer) {
885 if (HepMC::is_sim_descendant(p,truthParticle)) {
886 ptrPart = truthParticle;
887 break;
888 }
889 }
890 }
891 return ptrPart;
892 }
894
895 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
896 auto prodVtx = thePart->production_vertex();
897 if (!prodVtx) return;
898 for (const auto& theMother: prodVtx->particles_in()) {
899 if (!theMother) continue;
900 allancestors.insert(theMother);
901 findParticleAncestors(theMother, allancestors);
902 }
903 }
904
906
907 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
908 auto endVtx = thePart->end_vertex();
909 if (!endVtx) return;
910 for (const auto& theDaughter: endVtx->particles_out()) {
911 if (!theDaughter) continue;
912 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
913 allstabledescendants.insert(theDaughter);
914 }
915 findParticleStableDescendants(theDaughter, allstabledescendants);
916 }
917 }
918
922
923 template <class T> bool isHardScatteringVertex(T pVert) {
924 if (pVert == nullptr) return false;
925 T pV = pVert;
926 int numOfPartIn(0);
927 int pdg(0);
928
929 do {
930 pVert = pV;
931 auto incoming = pVert->particles_in();
932 numOfPartIn = incoming.size();
933 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
934 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
935
936 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
937
938 if (numOfPartIn == 2) {
939 auto incoming = pVert->particles_in();
940 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
941 }
942 return false;
943}
944
948
949 template <class T, class U>
950 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
951 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
952 auto vtx = p->production_vertex();
953 if (!vtx) return false;
954 bool fromHad = false;
955 for ( const auto& parent : particles_in(vtx) ) {
956 if (!parent) continue;
957 // should this really go into parton-level territory?
958 // probably depends where BSM particles are being decayed
959 fromBSM |= isBSM(parent);
960 if (!isPhysical(parent)) return false;
961 fromTau |= isTau(parent);
962 if (isHadron(parent)&&!isBeam(parent)) {
963 if (!hadron) hadron = parent; // assumes linear hadron parentage
964 return true;
965 }
966 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
967 }
968 return fromHad;
969 }
970
973
974 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
975 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
976 decltype(thePart->end_vertex()) pVert(nullptr);
977 if (EndVert != nullptr) {
978 do {
979 bool samePart = false;
980 pVert = nullptr;
981 auto outgoing = EndVert->particles_out();
982 auto incoming = EndVert->particles_in();
983 for (const auto& itrDaug: outgoing) {
984 if (!itrDaug) continue;
985 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
986 // brem on generator level for tau
987 (outgoing.size() == 1 && incoming.size() == 1 &&
989 itrDaug->pdg_id() == thePart->pdg_id()) {
990 samePart = true;
991 pVert = itrDaug->end_vertex();
992 }
993 }
994 if (samePart) EndVert = pVert;
995 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
996 }
997 return EndVert;
998 }
999
1001
1002 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1003 if (!theVert) return {};
1004 decltype(theVert->particles_out()) finalStatePart;
1005 auto outgoing = theVert->particles_out();
1006 for (const auto& thePart: outgoing) {
1007 if (!thePart) continue;
1008 finalStatePart.push_back(thePart);
1009 if (isStable(thePart)) continue;
1010 V pVert = findSimulatedEndVertex(thePart);
1011 if (pVert == theVert) break; // to prevent Sherpa loop
1012 if (pVert != nullptr) {
1013 auto vecPart = findFinalStateParticles<V>(pVert);
1014 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1015 }
1016 }
1017 return finalStatePart;
1018 }
1019
1020}
1021#endif

◆ hasQuark() [1/3]

template<>
bool MC::hasQuark ( const DecodedPID & p,
const int & q )
inline

Definition at line 717 of file HepMCHelpers.h.

738 {
739inline
740auto particles_in (const HepMC::GenVertex* p) {
741 return std::ranges::subrange (p->particles_in_const_begin(),
742 p->particles_in_const_end());
743}
744}
745#endif
746
747namespace MC
748{
749 template <class VTX>
750 auto particles_in (const VTX* p) { return p->particles_in(); }
751 template <class VTX>
752 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
753
754 namespace Pythia8
755 {
757 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
758
759 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
760
761 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
762 }
763
764#include "AtlasPID.h"
765
767 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
768
770 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
771
773 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
774
776 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
777
779 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
780
782 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
783
785 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
786
788 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
789
791 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
792
794 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
795
799 template <class T> inline bool isStableOrSimDecayed(const T& p) {
800 const auto vertex = p->end_vertex();
801 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
802 }
803
805 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
806
808 template <class T> inline bool isSpecialNonInteracting(const T& p) {
809 const int apid = std::abs(p->pdg_id());
810 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
811 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
812 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
813 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
814 return false;
815 }
816
818
819 template <class T> T findMother(T thePart) {
820 auto partOriVert = thePart->production_vertex();
821 if (!partOriVert) return nullptr;
822
823 long partPDG = thePart->pdg_id();
824 long MotherPDG(0);
825
826 auto MothOriVert = partOriVert;
827 MothOriVert = nullptr;
828 T theMoth(nullptr);
829
830 size_t itr = 0;
831 do {
832 if (itr != 0) partOriVert = MothOriVert;
833 for ( const auto& p : particles_in(partOriVert) ) {
834 theMoth = p;
835 if (!theMoth) continue;
836 MotherPDG = theMoth->pdg_id();
837 MothOriVert = theMoth->production_vertex();
838 if (MotherPDG == partPDG) break;
839 }
840 itr++;
841 if (itr > 100) {
842 break;
843 }
844 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
845 MothOriVert != partOriVert);
846 return theMoth;
847 }
848
850
851 template <class C, class T> T findMatching(C TruthContainer, T p) {
852 T ptrPart = nullptr;
853 if (!p) return ptrPart;
854 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
855 for (T truthParticle : *TruthContainer) {
856 if (HepMC::is_sim_descendant(p,truthParticle)) {
857 ptrPart = truthParticle;
858 break;
859 }
860 }
861 }
862 else {
863 for (T truthParticle : TruthContainer) {
864 if (HepMC::is_sim_descendant(p,truthParticle)) {
865 ptrPart = truthParticle;
866 break;
867 }
868 }
869 }
870 return ptrPart;
871 }
873
874 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
875 auto prodVtx = thePart->production_vertex();
876 if (!prodVtx) return;
877 for (const auto& theMother: prodVtx->particles_in()) {
878 if (!theMother) continue;
879 allancestors.insert(theMother);
880 findParticleAncestors(theMother, allancestors);
881 }
882 }
883
885
886 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
887 auto endVtx = thePart->end_vertex();
888 if (!endVtx) return;
889 for (const auto& theDaughter: endVtx->particles_out()) {
890 if (!theDaughter) continue;
891 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
892 allstabledescendants.insert(theDaughter);
893 }
894 findParticleStableDescendants(theDaughter, allstabledescendants);
895 }
896 }
897
901
902 template <class T> bool isHardScatteringVertex(T pVert) {
903 if (pVert == nullptr) return false;
904 T pV = pVert;
905 int numOfPartIn(0);
906 int pdg(0);
907
908 do {
909 pVert = pV;
910 auto incoming = pVert->particles_in();
911 numOfPartIn = incoming.size();
912 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
913 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
914
915 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
916
917 if (numOfPartIn == 2) {
918 auto incoming = pVert->particles_in();
919 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
920 }
921 return false;
922}
923
927
928 template <class T, class U>
929 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
930 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
931 auto vtx = p->production_vertex();
932 if (!vtx) return false;
933 bool fromHad = false;
934 for ( const auto& parent : particles_in(vtx) ) {
935 if (!parent) continue;
936 // should this really go into parton-level territory?
937 // probably depends where BSM particles are being decayed
938 fromBSM |= isBSM(parent);
939 if (!isPhysical(parent)) return false;
940 fromTau |= isTau(parent);
941 if (isHadron(parent)&&!isBeam(parent)) {
942 if (!hadron) hadron = parent; // assumes linear hadron parentage
943 return true;
944 }
945 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
946 }
947 return fromHad;
948 }
949
952
953 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
954 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
955 decltype(thePart->end_vertex()) pVert(nullptr);
956 if (EndVert != nullptr) {
957 do {
958 bool samePart = false;
959 pVert = nullptr;
960 auto outgoing = EndVert->particles_out();
961 auto incoming = EndVert->particles_in();
962 for (const auto& itrDaug: outgoing) {
963 if (!itrDaug) continue;
964 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
965 // brem on generator level for tau
966 (outgoing.size() == 1 && incoming.size() == 1 &&
968 itrDaug->pdg_id() == thePart->pdg_id()) {
969 samePart = true;
970 pVert = itrDaug->end_vertex();
971 }
972 }
973 if (samePart) EndVert = pVert;
974 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
975 }
976 return EndVert;
977 }
978
980
981 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
982 if (!theVert) return {};
983 decltype(theVert->particles_out()) finalStatePart;
984 auto outgoing = theVert->particles_out();
985 for (const auto& thePart: outgoing) {
986 if (!thePart) continue;
987 finalStatePart.push_back(thePart);
988 if (isStable(thePart)) continue;
989 V pVert = findSimulatedEndVertex(thePart);
990 if (pVert == theVert) break; // to prevent Sherpa loop
991 if (pVert != nullptr) {
992 auto vecPart = findFinalStateParticles<V>(pVert);
993 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
994 }
995 }
996 return finalStatePart;
997 }
998
999}
1000#endif

◆ hasQuark() [2/3]

template<>
bool MC::hasQuark ( const int & p,
const int & q )
inline

Definition at line 735 of file HepMCHelpers.h.

756{
757inline
758auto particles_in (const HepMC::GenVertex* p) {
759 return std::ranges::subrange (p->particles_in_const_begin(),
760 p->particles_in_const_end());
761}
762}
763#endif
764
765namespace MC
766{
767 template <class VTX>
768 auto particles_in (const VTX* p) { return p->particles_in(); }
769 template <class VTX>
770 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
771
772 namespace Pythia8
773 {
775 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
776
777 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
778
779 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
780 }
781
782#include "AtlasPID.h"
783
785 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
786
788 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
789
791 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
792
794 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
795
797 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
798
800 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
801
803 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
804
806 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
807
809 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
810
812 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
813
817 template <class T> inline bool isStableOrSimDecayed(const T& p) {
818 const auto vertex = p->end_vertex();
819 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
820 }
821
823 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
824
826 template <class T> inline bool isSpecialNonInteracting(const T& p) {
827 const int apid = std::abs(p->pdg_id());
828 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
829 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
830 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
831 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
832 return false;
833 }
834
836
837 template <class T> T findMother(T thePart) {
838 auto partOriVert = thePart->production_vertex();
839 if (!partOriVert) return nullptr;
840
841 long partPDG = thePart->pdg_id();
842 long MotherPDG(0);
843
844 auto MothOriVert = partOriVert;
845 MothOriVert = nullptr;
846 T theMoth(nullptr);
847
848 size_t itr = 0;
849 do {
850 if (itr != 0) partOriVert = MothOriVert;
851 for ( const auto& p : particles_in(partOriVert) ) {
852 theMoth = p;
853 if (!theMoth) continue;
854 MotherPDG = theMoth->pdg_id();
855 MothOriVert = theMoth->production_vertex();
856 if (MotherPDG == partPDG) break;
857 }
858 itr++;
859 if (itr > 100) {
860 break;
861 }
862 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
863 MothOriVert != partOriVert);
864 return theMoth;
865 }
866
868
869 template <class C, class T> T findMatching(C TruthContainer, T p) {
870 T ptrPart = nullptr;
871 if (!p) return ptrPart;
872 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
873 for (T truthParticle : *TruthContainer) {
874 if (HepMC::is_sim_descendant(p,truthParticle)) {
875 ptrPart = truthParticle;
876 break;
877 }
878 }
879 }
880 else {
881 for (T truthParticle : TruthContainer) {
882 if (HepMC::is_sim_descendant(p,truthParticle)) {
883 ptrPart = truthParticle;
884 break;
885 }
886 }
887 }
888 return ptrPart;
889 }
891
892 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
893 auto prodVtx = thePart->production_vertex();
894 if (!prodVtx) return;
895 for (const auto& theMother: prodVtx->particles_in()) {
896 if (!theMother) continue;
897 allancestors.insert(theMother);
898 findParticleAncestors(theMother, allancestors);
899 }
900 }
901
903
904 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
905 auto endVtx = thePart->end_vertex();
906 if (!endVtx) return;
907 for (const auto& theDaughter: endVtx->particles_out()) {
908 if (!theDaughter) continue;
909 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
910 allstabledescendants.insert(theDaughter);
911 }
912 findParticleStableDescendants(theDaughter, allstabledescendants);
913 }
914 }
915
919
920 template <class T> bool isHardScatteringVertex(T pVert) {
921 if (pVert == nullptr) return false;
922 T pV = pVert;
923 int numOfPartIn(0);
924 int pdg(0);
925
926 do {
927 pVert = pV;
928 auto incoming = pVert->particles_in();
929 numOfPartIn = incoming.size();
930 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
931 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
932
933 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
934
935 if (numOfPartIn == 2) {
936 auto incoming = pVert->particles_in();
937 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
938 }
939 return false;
940}
941
945
946 template <class T, class U>
947 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
948 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
949 auto vtx = p->production_vertex();
950 if (!vtx) return false;
951 bool fromHad = false;
952 for ( const auto& parent : particles_in(vtx) ) {
953 if (!parent) continue;
954 // should this really go into parton-level territory?
955 // probably depends where BSM particles are being decayed
956 fromBSM |= isBSM(parent);
957 if (!isPhysical(parent)) return false;
958 fromTau |= isTau(parent);
959 if (isHadron(parent)&&!isBeam(parent)) {
960 if (!hadron) hadron = parent; // assumes linear hadron parentage
961 return true;
962 }
963 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
964 }
965 return fromHad;
966 }
967
970
971 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
972 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
973 decltype(thePart->end_vertex()) pVert(nullptr);
974 if (EndVert != nullptr) {
975 do {
976 bool samePart = false;
977 pVert = nullptr;
978 auto outgoing = EndVert->particles_out();
979 auto incoming = EndVert->particles_in();
980 for (const auto& itrDaug: outgoing) {
981 if (!itrDaug) continue;
982 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
983 // brem on generator level for tau
984 (outgoing.size() == 1 && incoming.size() == 1 &&
986 itrDaug->pdg_id() == thePart->pdg_id()) {
987 samePart = true;
988 pVert = itrDaug->end_vertex();
989 }
990 }
991 if (samePart) EndVert = pVert;
992 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
993 }
994 return EndVert;
995 }
996
998
999 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1000 if (!theVert) return {};
1001 decltype(theVert->particles_out()) finalStatePart;
1002 auto outgoing = theVert->particles_out();
1003 for (const auto& thePart: outgoing) {
1004 if (!thePart) continue;
1005 finalStatePart.push_back(thePart);
1006 if (isStable(thePart)) continue;
1007 V pVert = findSimulatedEndVertex(thePart);
1008 if (pVert == theVert) break; // to prevent Sherpa loop
1009 if (pVert != nullptr) {
1010 auto vecPart = findFinalStateParticles<V>(pVert);
1011 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1012 }
1013 }
1014 return finalStatePart;
1015 }
1016
1017}
1018#endif

◆ hasQuark() [3/3]

template<class T>
bool MC::hasQuark ( const T & p,
const int & q )
inline

◆ hasSquark() [1/3]

template<>
bool MC::hasSquark ( const DecodedPID & p,
const int & q )
inline

Definition at line 612 of file HepMCHelpers.h.

633 {
634inline
635auto particles_in (const HepMC::GenVertex* p) {
636 return std::ranges::subrange (p->particles_in_const_begin(),
637 p->particles_in_const_end());
638}
639}
640#endif
641
642namespace MC
643{
644 template <class VTX>
645 auto particles_in (const VTX* p) { return p->particles_in(); }
646 template <class VTX>
647 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
648
649 namespace Pythia8
650 {
652 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
653
654 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
655
656 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
657 }
658
659#include "AtlasPID.h"
660
662 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
663
665 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
666
668 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
669
671 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
672
674 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
675
677 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
678
680 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
681
683 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
684
686 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
687
689 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
690
694 template <class T> inline bool isStableOrSimDecayed(const T& p) {
695 const auto vertex = p->end_vertex();
696 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
697 }
698
700 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
701
703 template <class T> inline bool isSpecialNonInteracting(const T& p) {
704 const int apid = std::abs(p->pdg_id());
705 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
706 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
707 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
708 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
709 return false;
710 }
711
713
714 template <class T> T findMother(T thePart) {
715 auto partOriVert = thePart->production_vertex();
716 if (!partOriVert) return nullptr;
717
718 long partPDG = thePart->pdg_id();
719 long MotherPDG(0);
720
721 auto MothOriVert = partOriVert;
722 MothOriVert = nullptr;
723 T theMoth(nullptr);
724
725 size_t itr = 0;
726 do {
727 if (itr != 0) partOriVert = MothOriVert;
728 for ( const auto& p : particles_in(partOriVert) ) {
729 theMoth = p;
730 if (!theMoth) continue;
731 MotherPDG = theMoth->pdg_id();
732 MothOriVert = theMoth->production_vertex();
733 if (MotherPDG == partPDG) break;
734 }
735 itr++;
736 if (itr > 100) {
737 break;
738 }
739 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
740 MothOriVert != partOriVert);
741 return theMoth;
742 }
743
745
746 template <class C, class T> T findMatching(C TruthContainer, T p) {
747 T ptrPart = nullptr;
748 if (!p) return ptrPart;
749 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
750 for (T truthParticle : *TruthContainer) {
751 if (HepMC::is_sim_descendant(p,truthParticle)) {
752 ptrPart = truthParticle;
753 break;
754 }
755 }
756 }
757 else {
758 for (T truthParticle : TruthContainer) {
759 if (HepMC::is_sim_descendant(p,truthParticle)) {
760 ptrPart = truthParticle;
761 break;
762 }
763 }
764 }
765 return ptrPart;
766 }
768
769 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
770 auto prodVtx = thePart->production_vertex();
771 if (!prodVtx) return;
772 for (const auto& theMother: prodVtx->particles_in()) {
773 if (!theMother) continue;
774 allancestors.insert(theMother);
775 findParticleAncestors(theMother, allancestors);
776 }
777 }
778
780
781 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
782 auto endVtx = thePart->end_vertex();
783 if (!endVtx) return;
784 for (const auto& theDaughter: endVtx->particles_out()) {
785 if (!theDaughter) continue;
786 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
787 allstabledescendants.insert(theDaughter);
788 }
789 findParticleStableDescendants(theDaughter, allstabledescendants);
790 }
791 }
792
796
797 template <class T> bool isHardScatteringVertex(T pVert) {
798 if (pVert == nullptr) return false;
799 T pV = pVert;
800 int numOfPartIn(0);
801 int pdg(0);
802
803 do {
804 pVert = pV;
805 auto incoming = pVert->particles_in();
806 numOfPartIn = incoming.size();
807 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
808 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
809
810 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
811
812 if (numOfPartIn == 2) {
813 auto incoming = pVert->particles_in();
814 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
815 }
816 return false;
817}
818
822
823 template <class T, class U>
824 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
825 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
826 auto vtx = p->production_vertex();
827 if (!vtx) return false;
828 bool fromHad = false;
829 for ( const auto& parent : particles_in(vtx) ) {
830 if (!parent) continue;
831 // should this really go into parton-level territory?
832 // probably depends where BSM particles are being decayed
833 fromBSM |= isBSM(parent);
834 if (!isPhysical(parent)) return false;
835 fromTau |= isTau(parent);
836 if (isHadron(parent)&&!isBeam(parent)) {
837 if (!hadron) hadron = parent; // assumes linear hadron parentage
838 return true;
839 }
840 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
841 }
842 return fromHad;
843 }
844
847
848 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
849 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
850 decltype(thePart->end_vertex()) pVert(nullptr);
851 if (EndVert != nullptr) {
852 do {
853 bool samePart = false;
854 pVert = nullptr;
855 auto outgoing = EndVert->particles_out();
856 auto incoming = EndVert->particles_in();
857 for (const auto& itrDaug: outgoing) {
858 if (!itrDaug) continue;
859 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
860 // brem on generator level for tau
861 (outgoing.size() == 1 && incoming.size() == 1 &&
863 itrDaug->pdg_id() == thePart->pdg_id()) {
864 samePart = true;
865 pVert = itrDaug->end_vertex();
866 }
867 }
868 if (samePart) EndVert = pVert;
869 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
870 }
871 return EndVert;
872 }
873
875
876 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
877 if (!theVert) return {};
878 decltype(theVert->particles_out()) finalStatePart;
879 auto outgoing = theVert->particles_out();
880 for (const auto& thePart: outgoing) {
881 if (!thePart) continue;
882 finalStatePart.push_back(thePart);
883 if (isStable(thePart)) continue;
884 V pVert = findSimulatedEndVertex(thePart);
885 if (pVert == theVert) break; // to prevent Sherpa loop
886 if (pVert != nullptr) {
887 auto vecPart = findFinalStateParticles<V>(pVert);
888 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
889 }
890 }
891 return finalStatePart;
892 }
893
894}
895#endif

◆ hasSquark() [2/3]

template<>
bool MC::hasSquark ( const int & p,
const int & q )
inline

Definition at line 619 of file HepMCHelpers.h.

640{
641inline
642auto particles_in (const HepMC::GenVertex* p) {
643 return std::ranges::subrange (p->particles_in_const_begin(),
644 p->particles_in_const_end());
645}
646}
647#endif
648
649namespace MC
650{
651 template <class VTX>
652 auto particles_in (const VTX* p) { return p->particles_in(); }
653 template <class VTX>
654 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
655
656 namespace Pythia8
657 {
659 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
660
661 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
662
663 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
664 }
665
666#include "AtlasPID.h"
667
669 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
670
672 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
673
675 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
676
678 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
679
681 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
682
684 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
685
687 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
688
690 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
691
693 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
694
696 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
697
701 template <class T> inline bool isStableOrSimDecayed(const T& p) {
702 const auto vertex = p->end_vertex();
703 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
704 }
705
707 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
708
710 template <class T> inline bool isSpecialNonInteracting(const T& p) {
711 const int apid = std::abs(p->pdg_id());
712 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
713 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
714 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
715 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
716 return false;
717 }
718
720
721 template <class T> T findMother(T thePart) {
722 auto partOriVert = thePart->production_vertex();
723 if (!partOriVert) return nullptr;
724
725 long partPDG = thePart->pdg_id();
726 long MotherPDG(0);
727
728 auto MothOriVert = partOriVert;
729 MothOriVert = nullptr;
730 T theMoth(nullptr);
731
732 size_t itr = 0;
733 do {
734 if (itr != 0) partOriVert = MothOriVert;
735 for ( const auto& p : particles_in(partOriVert) ) {
736 theMoth = p;
737 if (!theMoth) continue;
738 MotherPDG = theMoth->pdg_id();
739 MothOriVert = theMoth->production_vertex();
740 if (MotherPDG == partPDG) break;
741 }
742 itr++;
743 if (itr > 100) {
744 break;
745 }
746 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
747 MothOriVert != partOriVert);
748 return theMoth;
749 }
750
752
753 template <class C, class T> T findMatching(C TruthContainer, T p) {
754 T ptrPart = nullptr;
755 if (!p) return ptrPart;
756 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
757 for (T truthParticle : *TruthContainer) {
758 if (HepMC::is_sim_descendant(p,truthParticle)) {
759 ptrPart = truthParticle;
760 break;
761 }
762 }
763 }
764 else {
765 for (T truthParticle : TruthContainer) {
766 if (HepMC::is_sim_descendant(p,truthParticle)) {
767 ptrPart = truthParticle;
768 break;
769 }
770 }
771 }
772 return ptrPart;
773 }
775
776 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
777 auto prodVtx = thePart->production_vertex();
778 if (!prodVtx) return;
779 for (const auto& theMother: prodVtx->particles_in()) {
780 if (!theMother) continue;
781 allancestors.insert(theMother);
782 findParticleAncestors(theMother, allancestors);
783 }
784 }
785
787
788 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
789 auto endVtx = thePart->end_vertex();
790 if (!endVtx) return;
791 for (const auto& theDaughter: endVtx->particles_out()) {
792 if (!theDaughter) continue;
793 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
794 allstabledescendants.insert(theDaughter);
795 }
796 findParticleStableDescendants(theDaughter, allstabledescendants);
797 }
798 }
799
803
804 template <class T> bool isHardScatteringVertex(T pVert) {
805 if (pVert == nullptr) return false;
806 T pV = pVert;
807 int numOfPartIn(0);
808 int pdg(0);
809
810 do {
811 pVert = pV;
812 auto incoming = pVert->particles_in();
813 numOfPartIn = incoming.size();
814 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
815 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
816
817 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
818
819 if (numOfPartIn == 2) {
820 auto incoming = pVert->particles_in();
821 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
822 }
823 return false;
824}
825
829
830 template <class T, class U>
831 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
832 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
833 auto vtx = p->production_vertex();
834 if (!vtx) return false;
835 bool fromHad = false;
836 for ( const auto& parent : particles_in(vtx) ) {
837 if (!parent) continue;
838 // should this really go into parton-level territory?
839 // probably depends where BSM particles are being decayed
840 fromBSM |= isBSM(parent);
841 if (!isPhysical(parent)) return false;
842 fromTau |= isTau(parent);
843 if (isHadron(parent)&&!isBeam(parent)) {
844 if (!hadron) hadron = parent; // assumes linear hadron parentage
845 return true;
846 }
847 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
848 }
849 return fromHad;
850 }
851
854
855 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
856 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
857 decltype(thePart->end_vertex()) pVert(nullptr);
858 if (EndVert != nullptr) {
859 do {
860 bool samePart = false;
861 pVert = nullptr;
862 auto outgoing = EndVert->particles_out();
863 auto incoming = EndVert->particles_in();
864 for (const auto& itrDaug: outgoing) {
865 if (!itrDaug) continue;
866 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
867 // brem on generator level for tau
868 (outgoing.size() == 1 && incoming.size() == 1 &&
870 itrDaug->pdg_id() == thePart->pdg_id()) {
871 samePart = true;
872 pVert = itrDaug->end_vertex();
873 }
874 }
875 if (samePart) EndVert = pVert;
876 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
877 }
878 return EndVert;
879 }
880
882
883 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
884 if (!theVert) return {};
885 decltype(theVert->particles_out()) finalStatePart;
886 auto outgoing = theVert->particles_out();
887 for (const auto& thePart: outgoing) {
888 if (!thePart) continue;
889 finalStatePart.push_back(thePart);
890 if (isStable(thePart)) continue;
891 V pVert = findSimulatedEndVertex(thePart);
892 if (pVert == theVert) break; // to prevent Sherpa loop
893 if (pVert != nullptr) {
894 auto vecPart = findFinalStateParticles<V>(pVert);
895 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
896 }
897 }
898 return finalStatePart;
899 }
900
901}
902#endif

◆ hasSquark() [3/3]

template<class T>
bool MC::hasSquark ( const T & p,
const int & q )
inline

Definition at line 611 of file HepMCHelpers.h.

632{
633inline
634auto particles_in (const HepMC::GenVertex* p) {
635 return std::ranges::subrange (p->particles_in_const_begin(),
636 p->particles_in_const_end());
637}
638}
639#endif
640
641namespace MC
642{
643 template <class VTX>
644 auto particles_in (const VTX* p) { return p->particles_in(); }
645 template <class VTX>
646 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
647
648 namespace Pythia8
649 {
651 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
652
653 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
654
655 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
656 }
657
658#include "AtlasPID.h"
659
661 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
662
664 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
665
667 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
668
670 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
671
673 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
674
676 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
677
679 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
680
682 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
683
685 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
686
688 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
689
693 template <class T> inline bool isStableOrSimDecayed(const T& p) {
694 const auto vertex = p->end_vertex();
695 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
696 }
697
699 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
700
702 template <class T> inline bool isSpecialNonInteracting(const T& p) {
703 const int apid = std::abs(p->pdg_id());
704 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
705 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
706 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
707 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
708 return false;
709 }
710
712
713 template <class T> T findMother(T thePart) {
714 auto partOriVert = thePart->production_vertex();
715 if (!partOriVert) return nullptr;
716
717 long partPDG = thePart->pdg_id();
718 long MotherPDG(0);
719
720 auto MothOriVert = partOriVert;
721 MothOriVert = nullptr;
722 T theMoth(nullptr);
723
724 size_t itr = 0;
725 do {
726 if (itr != 0) partOriVert = MothOriVert;
727 for ( const auto& p : particles_in(partOriVert) ) {
728 theMoth = p;
729 if (!theMoth) continue;
730 MotherPDG = theMoth->pdg_id();
731 MothOriVert = theMoth->production_vertex();
732 if (MotherPDG == partPDG) break;
733 }
734 itr++;
735 if (itr > 100) {
736 break;
737 }
738 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
739 MothOriVert != partOriVert);
740 return theMoth;
741 }
742
744
745 template <class C, class T> T findMatching(C TruthContainer, T p) {
746 T ptrPart = nullptr;
747 if (!p) return ptrPart;
748 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
749 for (T truthParticle : *TruthContainer) {
750 if (HepMC::is_sim_descendant(p,truthParticle)) {
751 ptrPart = truthParticle;
752 break;
753 }
754 }
755 }
756 else {
757 for (T truthParticle : TruthContainer) {
758 if (HepMC::is_sim_descendant(p,truthParticle)) {
759 ptrPart = truthParticle;
760 break;
761 }
762 }
763 }
764 return ptrPart;
765 }
767
768 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
769 auto prodVtx = thePart->production_vertex();
770 if (!prodVtx) return;
771 for (const auto& theMother: prodVtx->particles_in()) {
772 if (!theMother) continue;
773 allancestors.insert(theMother);
774 findParticleAncestors(theMother, allancestors);
775 }
776 }
777
779
780 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
781 auto endVtx = thePart->end_vertex();
782 if (!endVtx) return;
783 for (const auto& theDaughter: endVtx->particles_out()) {
784 if (!theDaughter) continue;
785 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
786 allstabledescendants.insert(theDaughter);
787 }
788 findParticleStableDescendants(theDaughter, allstabledescendants);
789 }
790 }
791
795
796 template <class T> bool isHardScatteringVertex(T pVert) {
797 if (pVert == nullptr) return false;
798 T pV = pVert;
799 int numOfPartIn(0);
800 int pdg(0);
801
802 do {
803 pVert = pV;
804 auto incoming = pVert->particles_in();
805 numOfPartIn = incoming.size();
806 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
807 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
808
809 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
810
811 if (numOfPartIn == 2) {
812 auto incoming = pVert->particles_in();
813 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
814 }
815 return false;
816}
817
821
822 template <class T, class U>
823 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
824 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
825 auto vtx = p->production_vertex();
826 if (!vtx) return false;
827 bool fromHad = false;
828 for ( const auto& parent : particles_in(vtx) ) {
829 if (!parent) continue;
830 // should this really go into parton-level territory?
831 // probably depends where BSM particles are being decayed
832 fromBSM |= isBSM(parent);
833 if (!isPhysical(parent)) return false;
834 fromTau |= isTau(parent);
835 if (isHadron(parent)&&!isBeam(parent)) {
836 if (!hadron) hadron = parent; // assumes linear hadron parentage
837 return true;
838 }
839 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
840 }
841 return fromHad;
842 }
843
846
847 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
848 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
849 decltype(thePart->end_vertex()) pVert(nullptr);
850 if (EndVert != nullptr) {
851 do {
852 bool samePart = false;
853 pVert = nullptr;
854 auto outgoing = EndVert->particles_out();
855 auto incoming = EndVert->particles_in();
856 for (const auto& itrDaug: outgoing) {
857 if (!itrDaug) continue;
858 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
859 // brem on generator level for tau
860 (outgoing.size() == 1 && incoming.size() == 1 &&
862 itrDaug->pdg_id() == thePart->pdg_id()) {
863 samePart = true;
864 pVert = itrDaug->end_vertex();
865 }
866 }
867 if (samePart) EndVert = pVert;
868 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
869 }
870 return EndVert;
871 }
872
874
875 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
876 if (!theVert) return {};
877 decltype(theVert->particles_out()) finalStatePart;
878 auto outgoing = theVert->particles_out();
879 for (const auto& thePart: outgoing) {
880 if (!thePart) continue;
881 finalStatePart.push_back(thePart);
882 if (isStable(thePart)) continue;
883 V pVert = findSimulatedEndVertex(thePart);
884 if (pVert == theVert) break; // to prevent Sherpa loop
885 if (pVert != nullptr) {
886 auto vecPart = findFinalStateParticles<V>(pVert);
887 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
888 }
889 }
890 return finalStatePart;
891 }
892
893}
894#endif

◆ hasStrange()

template<class T>
bool MC::hasStrange ( const T & p)
inline

Definition at line 737 of file HepMCHelpers.h.

758{
759inline
760auto particles_in (const HepMC::GenVertex* p) {
761 return std::ranges::subrange (p->particles_in_const_begin(),
762 p->particles_in_const_end());
763}
764}
765#endif
766
767namespace MC
768{
769 template <class VTX>
770 auto particles_in (const VTX* p) { return p->particles_in(); }
771 template <class VTX>
772 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
773
774 namespace Pythia8
775 {
777 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
778
779 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
780
781 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
782 }
783
784#include "AtlasPID.h"
785
787 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
788
790 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
791
793 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
794
796 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
797
799 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
800
802 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
803
805 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
806
808 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
809
811 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
812
814 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
815
819 template <class T> inline bool isStableOrSimDecayed(const T& p) {
820 const auto vertex = p->end_vertex();
821 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
822 }
823
825 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
826
828 template <class T> inline bool isSpecialNonInteracting(const T& p) {
829 const int apid = std::abs(p->pdg_id());
830 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
831 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
832 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
833 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
834 return false;
835 }
836
838
839 template <class T> T findMother(T thePart) {
840 auto partOriVert = thePart->production_vertex();
841 if (!partOriVert) return nullptr;
842
843 long partPDG = thePart->pdg_id();
844 long MotherPDG(0);
845
846 auto MothOriVert = partOriVert;
847 MothOriVert = nullptr;
848 T theMoth(nullptr);
849
850 size_t itr = 0;
851 do {
852 if (itr != 0) partOriVert = MothOriVert;
853 for ( const auto& p : particles_in(partOriVert) ) {
854 theMoth = p;
855 if (!theMoth) continue;
856 MotherPDG = theMoth->pdg_id();
857 MothOriVert = theMoth->production_vertex();
858 if (MotherPDG == partPDG) break;
859 }
860 itr++;
861 if (itr > 100) {
862 break;
863 }
864 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
865 MothOriVert != partOriVert);
866 return theMoth;
867 }
868
870
871 template <class C, class T> T findMatching(C TruthContainer, T p) {
872 T ptrPart = nullptr;
873 if (!p) return ptrPart;
874 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
875 for (T truthParticle : *TruthContainer) {
876 if (HepMC::is_sim_descendant(p,truthParticle)) {
877 ptrPart = truthParticle;
878 break;
879 }
880 }
881 }
882 else {
883 for (T truthParticle : TruthContainer) {
884 if (HepMC::is_sim_descendant(p,truthParticle)) {
885 ptrPart = truthParticle;
886 break;
887 }
888 }
889 }
890 return ptrPart;
891 }
893
894 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
895 auto prodVtx = thePart->production_vertex();
896 if (!prodVtx) return;
897 for (const auto& theMother: prodVtx->particles_in()) {
898 if (!theMother) continue;
899 allancestors.insert(theMother);
900 findParticleAncestors(theMother, allancestors);
901 }
902 }
903
905
906 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
907 auto endVtx = thePart->end_vertex();
908 if (!endVtx) return;
909 for (const auto& theDaughter: endVtx->particles_out()) {
910 if (!theDaughter) continue;
911 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
912 allstabledescendants.insert(theDaughter);
913 }
914 findParticleStableDescendants(theDaughter, allstabledescendants);
915 }
916 }
917
921
922 template <class T> bool isHardScatteringVertex(T pVert) {
923 if (pVert == nullptr) return false;
924 T pV = pVert;
925 int numOfPartIn(0);
926 int pdg(0);
927
928 do {
929 pVert = pV;
930 auto incoming = pVert->particles_in();
931 numOfPartIn = incoming.size();
932 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
933 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
934
935 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
936
937 if (numOfPartIn == 2) {
938 auto incoming = pVert->particles_in();
939 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
940 }
941 return false;
942}
943
947
948 template <class T, class U>
949 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
950 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
951 auto vtx = p->production_vertex();
952 if (!vtx) return false;
953 bool fromHad = false;
954 for ( const auto& parent : particles_in(vtx) ) {
955 if (!parent) continue;
956 // should this really go into parton-level territory?
957 // probably depends where BSM particles are being decayed
958 fromBSM |= isBSM(parent);
959 if (!isPhysical(parent)) return false;
960 fromTau |= isTau(parent);
961 if (isHadron(parent)&&!isBeam(parent)) {
962 if (!hadron) hadron = parent; // assumes linear hadron parentage
963 return true;
964 }
965 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
966 }
967 return fromHad;
968 }
969
972
973 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
974 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
975 decltype(thePart->end_vertex()) pVert(nullptr);
976 if (EndVert != nullptr) {
977 do {
978 bool samePart = false;
979 pVert = nullptr;
980 auto outgoing = EndVert->particles_out();
981 auto incoming = EndVert->particles_in();
982 for (const auto& itrDaug: outgoing) {
983 if (!itrDaug) continue;
984 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
985 // brem on generator level for tau
986 (outgoing.size() == 1 && incoming.size() == 1 &&
988 itrDaug->pdg_id() == thePart->pdg_id()) {
989 samePart = true;
990 pVert = itrDaug->end_vertex();
991 }
992 }
993 if (samePart) EndVert = pVert;
994 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
995 }
996 return EndVert;
997 }
998
1000
1001 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1002 if (!theVert) return {};
1003 decltype(theVert->particles_out()) finalStatePart;
1004 auto outgoing = theVert->particles_out();
1005 for (const auto& thePart: outgoing) {
1006 if (!thePart) continue;
1007 finalStatePart.push_back(thePart);
1008 if (isStable(thePart)) continue;
1009 V pVert = findSimulatedEndVertex(thePart);
1010 if (pVert == theVert) break; // to prevent Sherpa loop
1011 if (pVert != nullptr) {
1012 auto vecPart = findFinalStateParticles<V>(pVert);
1013 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1014 }
1015 }
1016 return finalStatePart;
1017 }
1018
1019}
1020#endif

◆ hasTop()

template<class T>
bool MC::hasTop ( const T & p)
inline

Definition at line 740 of file HepMCHelpers.h.

761{
762inline
763auto particles_in (const HepMC::GenVertex* p) {
764 return std::ranges::subrange (p->particles_in_const_begin(),
765 p->particles_in_const_end());
766}
767}
768#endif
769
770namespace MC
771{
772 template <class VTX>
773 auto particles_in (const VTX* p) { return p->particles_in(); }
774 template <class VTX>
775 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
776
777 namespace Pythia8
778 {
780 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
781
782 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
783
784 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
785 }
786
787#include "AtlasPID.h"
788
790 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
791
793 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
794
796 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
797
799 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
800
802 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
803
805 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
806
808 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
809
811 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
812
814 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
815
817 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
818
822 template <class T> inline bool isStableOrSimDecayed(const T& p) {
823 const auto vertex = p->end_vertex();
824 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
825 }
826
828 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
829
831 template <class T> inline bool isSpecialNonInteracting(const T& p) {
832 const int apid = std::abs(p->pdg_id());
833 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
834 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
835 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
836 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
837 return false;
838 }
839
841
842 template <class T> T findMother(T thePart) {
843 auto partOriVert = thePart->production_vertex();
844 if (!partOriVert) return nullptr;
845
846 long partPDG = thePart->pdg_id();
847 long MotherPDG(0);
848
849 auto MothOriVert = partOriVert;
850 MothOriVert = nullptr;
851 T theMoth(nullptr);
852
853 size_t itr = 0;
854 do {
855 if (itr != 0) partOriVert = MothOriVert;
856 for ( const auto& p : particles_in(partOriVert) ) {
857 theMoth = p;
858 if (!theMoth) continue;
859 MotherPDG = theMoth->pdg_id();
860 MothOriVert = theMoth->production_vertex();
861 if (MotherPDG == partPDG) break;
862 }
863 itr++;
864 if (itr > 100) {
865 break;
866 }
867 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
868 MothOriVert != partOriVert);
869 return theMoth;
870 }
871
873
874 template <class C, class T> T findMatching(C TruthContainer, T p) {
875 T ptrPart = nullptr;
876 if (!p) return ptrPart;
877 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
878 for (T truthParticle : *TruthContainer) {
879 if (HepMC::is_sim_descendant(p,truthParticle)) {
880 ptrPart = truthParticle;
881 break;
882 }
883 }
884 }
885 else {
886 for (T truthParticle : TruthContainer) {
887 if (HepMC::is_sim_descendant(p,truthParticle)) {
888 ptrPart = truthParticle;
889 break;
890 }
891 }
892 }
893 return ptrPart;
894 }
896
897 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
898 auto prodVtx = thePart->production_vertex();
899 if (!prodVtx) return;
900 for (const auto& theMother: prodVtx->particles_in()) {
901 if (!theMother) continue;
902 allancestors.insert(theMother);
903 findParticleAncestors(theMother, allancestors);
904 }
905 }
906
908
909 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
910 auto endVtx = thePart->end_vertex();
911 if (!endVtx) return;
912 for (const auto& theDaughter: endVtx->particles_out()) {
913 if (!theDaughter) continue;
914 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
915 allstabledescendants.insert(theDaughter);
916 }
917 findParticleStableDescendants(theDaughter, allstabledescendants);
918 }
919 }
920
924
925 template <class T> bool isHardScatteringVertex(T pVert) {
926 if (pVert == nullptr) return false;
927 T pV = pVert;
928 int numOfPartIn(0);
929 int pdg(0);
930
931 do {
932 pVert = pV;
933 auto incoming = pVert->particles_in();
934 numOfPartIn = incoming.size();
935 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
936 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
937
938 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
939
940 if (numOfPartIn == 2) {
941 auto incoming = pVert->particles_in();
942 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
943 }
944 return false;
945}
946
950
951 template <class T, class U>
952 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
953 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
954 auto vtx = p->production_vertex();
955 if (!vtx) return false;
956 bool fromHad = false;
957 for ( const auto& parent : particles_in(vtx) ) {
958 if (!parent) continue;
959 // should this really go into parton-level territory?
960 // probably depends where BSM particles are being decayed
961 fromBSM |= isBSM(parent);
962 if (!isPhysical(parent)) return false;
963 fromTau |= isTau(parent);
964 if (isHadron(parent)&&!isBeam(parent)) {
965 if (!hadron) hadron = parent; // assumes linear hadron parentage
966 return true;
967 }
968 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
969 }
970 return fromHad;
971 }
972
975
976 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
977 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
978 decltype(thePart->end_vertex()) pVert(nullptr);
979 if (EndVert != nullptr) {
980 do {
981 bool samePart = false;
982 pVert = nullptr;
983 auto outgoing = EndVert->particles_out();
984 auto incoming = EndVert->particles_in();
985 for (const auto& itrDaug: outgoing) {
986 if (!itrDaug) continue;
987 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
988 // brem on generator level for tau
989 (outgoing.size() == 1 && incoming.size() == 1 &&
991 itrDaug->pdg_id() == thePart->pdg_id()) {
992 samePart = true;
993 pVert = itrDaug->end_vertex();
994 }
995 }
996 if (samePart) EndVert = pVert;
997 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
998 }
999 return EndVert;
1000 }
1001
1003
1004 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1005 if (!theVert) return {};
1006 decltype(theVert->particles_out()) finalStatePart;
1007 auto outgoing = theVert->particles_out();
1008 for (const auto& thePart: outgoing) {
1009 if (!thePart) continue;
1010 finalStatePart.push_back(thePart);
1011 if (isStable(thePart)) continue;
1012 V pVert = findSimulatedEndVertex(thePart);
1013 if (pVert == theVert) break; // to prevent Sherpa loop
1014 if (pVert != nullptr) {
1015 auto vecPart = findFinalStateParticles<V>(pVert);
1016 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1017 }
1018 }
1019 return finalStatePart;
1020 }
1021
1022}
1023#endif

◆ isBaryon() [1/3]

template<>
bool MC::isBaryon ( const DecodedPID & p)
inline

Definition at line 284 of file HepMCHelpers.h.

◆ isBaryon() [2/3]

template<>
bool MC::isBaryon ( const int & p)
inline

Definition at line 317 of file HepMCHelpers.h.

338{
339inline
340auto particles_in (const HepMC::GenVertex* p) {
341 return std::ranges::subrange (p->particles_in_const_begin(),
342 p->particles_in_const_end());
343}
344}
345#endif
346
347namespace MC
348{
349 template <class VTX>
350 auto particles_in (const VTX* p) { return p->particles_in(); }
351 template <class VTX>
352 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
353
354 namespace Pythia8
355 {
357 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
358
359 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
360
361 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
362 }
363
364#include "AtlasPID.h"
365
367 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
368
370 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
371
373 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
374
376 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
377
379 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
380
382 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
383
385 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
386
388 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
389
391 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
392
394 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
395
399 template <class T> inline bool isStableOrSimDecayed(const T& p) {
400 const auto vertex = p->end_vertex();
401 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
402 }
403
405 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
406
408 template <class T> inline bool isSpecialNonInteracting(const T& p) {
409 const int apid = std::abs(p->pdg_id());
410 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
411 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
412 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
413 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
414 return false;
415 }
416
418
419 template <class T> T findMother(T thePart) {
420 auto partOriVert = thePart->production_vertex();
421 if (!partOriVert) return nullptr;
422
423 long partPDG = thePart->pdg_id();
424 long MotherPDG(0);
425
426 auto MothOriVert = partOriVert;
427 MothOriVert = nullptr;
428 T theMoth(nullptr);
429
430 size_t itr = 0;
431 do {
432 if (itr != 0) partOriVert = MothOriVert;
433 for ( const auto& p : particles_in(partOriVert) ) {
434 theMoth = p;
435 if (!theMoth) continue;
436 MotherPDG = theMoth->pdg_id();
437 MothOriVert = theMoth->production_vertex();
438 if (MotherPDG == partPDG) break;
439 }
440 itr++;
441 if (itr > 100) {
442 break;
443 }
444 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
445 MothOriVert != partOriVert);
446 return theMoth;
447 }
448
450
451 template <class C, class T> T findMatching(C TruthContainer, T p) {
452 T ptrPart = nullptr;
453 if (!p) return ptrPart;
454 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
455 for (T truthParticle : *TruthContainer) {
456 if (HepMC::is_sim_descendant(p,truthParticle)) {
457 ptrPart = truthParticle;
458 break;
459 }
460 }
461 }
462 else {
463 for (T truthParticle : TruthContainer) {
464 if (HepMC::is_sim_descendant(p,truthParticle)) {
465 ptrPart = truthParticle;
466 break;
467 }
468 }
469 }
470 return ptrPart;
471 }
473
474 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
475 auto prodVtx = thePart->production_vertex();
476 if (!prodVtx) return;
477 for (const auto& theMother: prodVtx->particles_in()) {
478 if (!theMother) continue;
479 allancestors.insert(theMother);
480 findParticleAncestors(theMother, allancestors);
481 }
482 }
483
485
486 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
487 auto endVtx = thePart->end_vertex();
488 if (!endVtx) return;
489 for (const auto& theDaughter: endVtx->particles_out()) {
490 if (!theDaughter) continue;
491 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
492 allstabledescendants.insert(theDaughter);
493 }
494 findParticleStableDescendants(theDaughter, allstabledescendants);
495 }
496 }
497
501
502 template <class T> bool isHardScatteringVertex(T pVert) {
503 if (pVert == nullptr) return false;
504 T pV = pVert;
505 int numOfPartIn(0);
506 int pdg(0);
507
508 do {
509 pVert = pV;
510 auto incoming = pVert->particles_in();
511 numOfPartIn = incoming.size();
512 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
513 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
514
515 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
516
517 if (numOfPartIn == 2) {
518 auto incoming = pVert->particles_in();
519 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
520 }
521 return false;
522}
523
527
528 template <class T, class U>
529 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
530 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
531 auto vtx = p->production_vertex();
532 if (!vtx) return false;
533 bool fromHad = false;
534 for ( const auto& parent : particles_in(vtx) ) {
535 if (!parent) continue;
536 // should this really go into parton-level territory?
537 // probably depends where BSM particles are being decayed
538 fromBSM |= isBSM(parent);
539 if (!isPhysical(parent)) return false;
540 fromTau |= isTau(parent);
541 if (isHadron(parent)&&!isBeam(parent)) {
542 if (!hadron) hadron = parent; // assumes linear hadron parentage
543 return true;
544 }
545 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
546 }
547 return fromHad;
548 }
549
552
553 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
554 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
555 decltype(thePart->end_vertex()) pVert(nullptr);
556 if (EndVert != nullptr) {
557 do {
558 bool samePart = false;
559 pVert = nullptr;
560 auto outgoing = EndVert->particles_out();
561 auto incoming = EndVert->particles_in();
562 for (const auto& itrDaug: outgoing) {
563 if (!itrDaug) continue;
564 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
565 // brem on generator level for tau
566 (outgoing.size() == 1 && incoming.size() == 1 &&
568 itrDaug->pdg_id() == thePart->pdg_id()) {
569 samePart = true;
570 pVert = itrDaug->end_vertex();
571 }
572 }
573 if (samePart) EndVert = pVert;
574 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
575 }
576 return EndVert;
577 }
578
580
581 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
582 if (!theVert) return {};
583 decltype(theVert->particles_out()) finalStatePart;
584 auto outgoing = theVert->particles_out();
585 for (const auto& thePart: outgoing) {
586 if (!thePart) continue;
587 finalStatePart.push_back(thePart);
588 if (isStable(thePart)) continue;
589 V pVert = findSimulatedEndVertex(thePart);
590 if (pVert == theVert) break; // to prevent Sherpa loop
591 if (pVert != nullptr) {
592 auto vecPart = findFinalStateParticles<V>(pVert);
593 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
594 }
595 }
596 return finalStatePart;
597 }
598
599}
600#endif

◆ isBaryon() [3/3]

template<class T>
bool MC::isBaryon ( const T & p)
inline

Table 43.2 APID: states with fourth generation quarks are not baryons.

Definition at line 283 of file HepMCHelpers.h.

◆ isBBbarMeson() [1/3]

template<>
bool MC::isBBbarMeson ( const DecodedPID & p)
inline

Definition at line 928 of file HepMCHelpers.h.

949{
950inline
951auto particles_in (const HepMC::GenVertex* p) {
952 return std::ranges::subrange (p->particles_in_const_begin(),
953 p->particles_in_const_end());
954}
955}
956#endif
957
958namespace MC
959{
960 template <class VTX>
961 auto particles_in (const VTX* p) { return p->particles_in(); }
962 template <class VTX>
963 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
964
965 namespace Pythia8
966 {
968 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
969
970 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
971
972 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
973 }
974
975#include "AtlasPID.h"
976
978 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
979
981 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
982
984 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
985
987 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
988
990 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
991
993 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
994
996 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
997
999 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1000
1002 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1003
1005 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1006
1010 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1011 const auto vertex = p->end_vertex();
1012 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1013 }
1014
1016 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1017
1019 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1020 const int apid = std::abs(p->pdg_id());
1021 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1022 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1023 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1024 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1025 return false;
1026 }
1027
1029
1030 template <class T> T findMother(T thePart) {
1031 auto partOriVert = thePart->production_vertex();
1032 if (!partOriVert) return nullptr;
1033
1034 long partPDG = thePart->pdg_id();
1035 long MotherPDG(0);
1036
1037 auto MothOriVert = partOriVert;
1038 MothOriVert = nullptr;
1039 T theMoth(nullptr);
1040
1041 size_t itr = 0;
1042 do {
1043 if (itr != 0) partOriVert = MothOriVert;
1044 for ( const auto& p : particles_in(partOriVert) ) {
1045 theMoth = p;
1046 if (!theMoth) continue;
1047 MotherPDG = theMoth->pdg_id();
1048 MothOriVert = theMoth->production_vertex();
1049 if (MotherPDG == partPDG) break;
1050 }
1051 itr++;
1052 if (itr > 100) {
1053 break;
1054 }
1055 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1056 MothOriVert != partOriVert);
1057 return theMoth;
1058 }
1059
1061
1062 template <class C, class T> T findMatching(C TruthContainer, T p) {
1063 T ptrPart = nullptr;
1064 if (!p) return ptrPart;
1065 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1066 for (T truthParticle : *TruthContainer) {
1067 if (HepMC::is_sim_descendant(p,truthParticle)) {
1068 ptrPart = truthParticle;
1069 break;
1070 }
1071 }
1072 }
1073 else {
1074 for (T truthParticle : TruthContainer) {
1075 if (HepMC::is_sim_descendant(p,truthParticle)) {
1076 ptrPart = truthParticle;
1077 break;
1078 }
1079 }
1080 }
1081 return ptrPart;
1082 }
1084
1085 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1086 auto prodVtx = thePart->production_vertex();
1087 if (!prodVtx) return;
1088 for (const auto& theMother: prodVtx->particles_in()) {
1089 if (!theMother) continue;
1090 allancestors.insert(theMother);
1091 findParticleAncestors(theMother, allancestors);
1092 }
1093 }
1094
1096
1097 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1098 auto endVtx = thePart->end_vertex();
1099 if (!endVtx) return;
1100 for (const auto& theDaughter: endVtx->particles_out()) {
1101 if (!theDaughter) continue;
1102 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1103 allstabledescendants.insert(theDaughter);
1104 }
1105 findParticleStableDescendants(theDaughter, allstabledescendants);
1106 }
1107 }
1108
1112
1113 template <class T> bool isHardScatteringVertex(T pVert) {
1114 if (pVert == nullptr) return false;
1115 T pV = pVert;
1116 int numOfPartIn(0);
1117 int pdg(0);
1118
1119 do {
1120 pVert = pV;
1121 auto incoming = pVert->particles_in();
1122 numOfPartIn = incoming.size();
1123 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1124 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1125
1126 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1127
1128 if (numOfPartIn == 2) {
1129 auto incoming = pVert->particles_in();
1130 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1131 }
1132 return false;
1133}
1134
1138
1139 template <class T, class U>
1140 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1141 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1142 auto vtx = p->production_vertex();
1143 if (!vtx) return false;
1144 bool fromHad = false;
1145 for ( const auto& parent : particles_in(vtx) ) {
1146 if (!parent) continue;
1147 // should this really go into parton-level territory?
1148 // probably depends where BSM particles are being decayed
1149 fromBSM |= isBSM(parent);
1150 if (!isPhysical(parent)) return false;
1151 fromTau |= isTau(parent);
1152 if (isHadron(parent)&&!isBeam(parent)) {
1153 if (!hadron) hadron = parent; // assumes linear hadron parentage
1154 return true;
1155 }
1156 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1157 }
1158 return fromHad;
1159 }
1160
1163
1164 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1165 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1166 decltype(thePart->end_vertex()) pVert(nullptr);
1167 if (EndVert != nullptr) {
1168 do {
1169 bool samePart = false;
1170 pVert = nullptr;
1171 auto outgoing = EndVert->particles_out();
1172 auto incoming = EndVert->particles_in();
1173 for (const auto& itrDaug: outgoing) {
1174 if (!itrDaug) continue;
1175 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1176 // brem on generator level for tau
1177 (outgoing.size() == 1 && incoming.size() == 1 &&
1179 itrDaug->pdg_id() == thePart->pdg_id()) {
1180 samePart = true;
1181 pVert = itrDaug->end_vertex();
1182 }
1183 }
1184 if (samePart) EndVert = pVert;
1185 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1186 }
1187 return EndVert;
1188 }
1189
1191
1192 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1193 if (!theVert) return {};
1194 decltype(theVert->particles_out()) finalStatePart;
1195 auto outgoing = theVert->particles_out();
1196 for (const auto& thePart: outgoing) {
1197 if (!thePart) continue;
1198 finalStatePart.push_back(thePart);
1199 if (isStable(thePart)) continue;
1200 V pVert = findSimulatedEndVertex(thePart);
1201 if (pVert == theVert) break; // to prevent Sherpa loop
1202 if (pVert != nullptr) {
1203 auto vecPart = findFinalStateParticles<V>(pVert);
1204 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1205 }
1206 }
1207 return finalStatePart;
1208 }
1209
1210}
1211#endif

◆ isBBbarMeson() [2/3]

template<>
bool MC::isBBbarMeson ( const int & p)
inline

Definition at line 929 of file HepMCHelpers.h.

950{
951inline
952auto particles_in (const HepMC::GenVertex* p) {
953 return std::ranges::subrange (p->particles_in_const_begin(),
954 p->particles_in_const_end());
955}
956}
957#endif
958
959namespace MC
960{
961 template <class VTX>
962 auto particles_in (const VTX* p) { return p->particles_in(); }
963 template <class VTX>
964 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
965
966 namespace Pythia8
967 {
969 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
970
971 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
972
973 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
974 }
975
976#include "AtlasPID.h"
977
979 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
980
982 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
983
985 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
986
988 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
989
991 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
992
994 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
995
997 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
998
1000 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1001
1003 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1004
1006 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1007
1011 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1012 const auto vertex = p->end_vertex();
1013 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1014 }
1015
1017 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1018
1020 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1021 const int apid = std::abs(p->pdg_id());
1022 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1023 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1024 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1025 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1026 return false;
1027 }
1028
1030
1031 template <class T> T findMother(T thePart) {
1032 auto partOriVert = thePart->production_vertex();
1033 if (!partOriVert) return nullptr;
1034
1035 long partPDG = thePart->pdg_id();
1036 long MotherPDG(0);
1037
1038 auto MothOriVert = partOriVert;
1039 MothOriVert = nullptr;
1040 T theMoth(nullptr);
1041
1042 size_t itr = 0;
1043 do {
1044 if (itr != 0) partOriVert = MothOriVert;
1045 for ( const auto& p : particles_in(partOriVert) ) {
1046 theMoth = p;
1047 if (!theMoth) continue;
1048 MotherPDG = theMoth->pdg_id();
1049 MothOriVert = theMoth->production_vertex();
1050 if (MotherPDG == partPDG) break;
1051 }
1052 itr++;
1053 if (itr > 100) {
1054 break;
1055 }
1056 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1057 MothOriVert != partOriVert);
1058 return theMoth;
1059 }
1060
1062
1063 template <class C, class T> T findMatching(C TruthContainer, T p) {
1064 T ptrPart = nullptr;
1065 if (!p) return ptrPart;
1066 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1067 for (T truthParticle : *TruthContainer) {
1068 if (HepMC::is_sim_descendant(p,truthParticle)) {
1069 ptrPart = truthParticle;
1070 break;
1071 }
1072 }
1073 }
1074 else {
1075 for (T truthParticle : TruthContainer) {
1076 if (HepMC::is_sim_descendant(p,truthParticle)) {
1077 ptrPart = truthParticle;
1078 break;
1079 }
1080 }
1081 }
1082 return ptrPart;
1083 }
1085
1086 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1087 auto prodVtx = thePart->production_vertex();
1088 if (!prodVtx) return;
1089 for (const auto& theMother: prodVtx->particles_in()) {
1090 if (!theMother) continue;
1091 allancestors.insert(theMother);
1092 findParticleAncestors(theMother, allancestors);
1093 }
1094 }
1095
1097
1098 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1099 auto endVtx = thePart->end_vertex();
1100 if (!endVtx) return;
1101 for (const auto& theDaughter: endVtx->particles_out()) {
1102 if (!theDaughter) continue;
1103 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1104 allstabledescendants.insert(theDaughter);
1105 }
1106 findParticleStableDescendants(theDaughter, allstabledescendants);
1107 }
1108 }
1109
1113
1114 template <class T> bool isHardScatteringVertex(T pVert) {
1115 if (pVert == nullptr) return false;
1116 T pV = pVert;
1117 int numOfPartIn(0);
1118 int pdg(0);
1119
1120 do {
1121 pVert = pV;
1122 auto incoming = pVert->particles_in();
1123 numOfPartIn = incoming.size();
1124 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1125 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1126
1127 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1128
1129 if (numOfPartIn == 2) {
1130 auto incoming = pVert->particles_in();
1131 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1132 }
1133 return false;
1134}
1135
1139
1140 template <class T, class U>
1141 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1142 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1143 auto vtx = p->production_vertex();
1144 if (!vtx) return false;
1145 bool fromHad = false;
1146 for ( const auto& parent : particles_in(vtx) ) {
1147 if (!parent) continue;
1148 // should this really go into parton-level territory?
1149 // probably depends where BSM particles are being decayed
1150 fromBSM |= isBSM(parent);
1151 if (!isPhysical(parent)) return false;
1152 fromTau |= isTau(parent);
1153 if (isHadron(parent)&&!isBeam(parent)) {
1154 if (!hadron) hadron = parent; // assumes linear hadron parentage
1155 return true;
1156 }
1157 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1158 }
1159 return fromHad;
1160 }
1161
1164
1165 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1166 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1167 decltype(thePart->end_vertex()) pVert(nullptr);
1168 if (EndVert != nullptr) {
1169 do {
1170 bool samePart = false;
1171 pVert = nullptr;
1172 auto outgoing = EndVert->particles_out();
1173 auto incoming = EndVert->particles_in();
1174 for (const auto& itrDaug: outgoing) {
1175 if (!itrDaug) continue;
1176 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1177 // brem on generator level for tau
1178 (outgoing.size() == 1 && incoming.size() == 1 &&
1180 itrDaug->pdg_id() == thePart->pdg_id()) {
1181 samePart = true;
1182 pVert = itrDaug->end_vertex();
1183 }
1184 }
1185 if (samePart) EndVert = pVert;
1186 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1187 }
1188 return EndVert;
1189 }
1190
1192
1193 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1194 if (!theVert) return {};
1195 decltype(theVert->particles_out()) finalStatePart;
1196 auto outgoing = theVert->particles_out();
1197 for (const auto& thePart: outgoing) {
1198 if (!thePart) continue;
1199 finalStatePart.push_back(thePart);
1200 if (isStable(thePart)) continue;
1201 V pVert = findSimulatedEndVertex(thePart);
1202 if (pVert == theVert) break; // to prevent Sherpa loop
1203 if (pVert != nullptr) {
1204 auto vecPart = findFinalStateParticles<V>(pVert);
1205 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1206 }
1207 }
1208 return finalStatePart;
1209 }
1210
1211}
1212#endif

◆ isBBbarMeson() [3/3]

template<class T>
bool MC::isBBbarMeson ( const T & p)
inline

Definition at line 927 of file HepMCHelpers.h.

948{
949inline
950auto particles_in (const HepMC::GenVertex* p) {
951 return std::ranges::subrange (p->particles_in_const_begin(),
952 p->particles_in_const_end());
953}
954}
955#endif
956
957namespace MC
958{
959 template <class VTX>
960 auto particles_in (const VTX* p) { return p->particles_in(); }
961 template <class VTX>
962 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
963
964 namespace Pythia8
965 {
967 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
968
969 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
970
971 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
972 }
973
974#include "AtlasPID.h"
975
977 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
978
980 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
981
983 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
984
986 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
987
989 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
990
992 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
993
995 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
996
998 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
999
1001 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1002
1004 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1005
1009 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1010 const auto vertex = p->end_vertex();
1011 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1012 }
1013
1015 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1016
1018 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1019 const int apid = std::abs(p->pdg_id());
1020 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1021 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1022 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1023 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1024 return false;
1025 }
1026
1028
1029 template <class T> T findMother(T thePart) {
1030 auto partOriVert = thePart->production_vertex();
1031 if (!partOriVert) return nullptr;
1032
1033 long partPDG = thePart->pdg_id();
1034 long MotherPDG(0);
1035
1036 auto MothOriVert = partOriVert;
1037 MothOriVert = nullptr;
1038 T theMoth(nullptr);
1039
1040 size_t itr = 0;
1041 do {
1042 if (itr != 0) partOriVert = MothOriVert;
1043 for ( const auto& p : particles_in(partOriVert) ) {
1044 theMoth = p;
1045 if (!theMoth) continue;
1046 MotherPDG = theMoth->pdg_id();
1047 MothOriVert = theMoth->production_vertex();
1048 if (MotherPDG == partPDG) break;
1049 }
1050 itr++;
1051 if (itr > 100) {
1052 break;
1053 }
1054 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1055 MothOriVert != partOriVert);
1056 return theMoth;
1057 }
1058
1060
1061 template <class C, class T> T findMatching(C TruthContainer, T p) {
1062 T ptrPart = nullptr;
1063 if (!p) return ptrPart;
1064 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1065 for (T truthParticle : *TruthContainer) {
1066 if (HepMC::is_sim_descendant(p,truthParticle)) {
1067 ptrPart = truthParticle;
1068 break;
1069 }
1070 }
1071 }
1072 else {
1073 for (T truthParticle : TruthContainer) {
1074 if (HepMC::is_sim_descendant(p,truthParticle)) {
1075 ptrPart = truthParticle;
1076 break;
1077 }
1078 }
1079 }
1080 return ptrPart;
1081 }
1083
1084 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1085 auto prodVtx = thePart->production_vertex();
1086 if (!prodVtx) return;
1087 for (const auto& theMother: prodVtx->particles_in()) {
1088 if (!theMother) continue;
1089 allancestors.insert(theMother);
1090 findParticleAncestors(theMother, allancestors);
1091 }
1092 }
1093
1095
1096 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1097 auto endVtx = thePart->end_vertex();
1098 if (!endVtx) return;
1099 for (const auto& theDaughter: endVtx->particles_out()) {
1100 if (!theDaughter) continue;
1101 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1102 allstabledescendants.insert(theDaughter);
1103 }
1104 findParticleStableDescendants(theDaughter, allstabledescendants);
1105 }
1106 }
1107
1111
1112 template <class T> bool isHardScatteringVertex(T pVert) {
1113 if (pVert == nullptr) return false;
1114 T pV = pVert;
1115 int numOfPartIn(0);
1116 int pdg(0);
1117
1118 do {
1119 pVert = pV;
1120 auto incoming = pVert->particles_in();
1121 numOfPartIn = incoming.size();
1122 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1123 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1124
1125 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1126
1127 if (numOfPartIn == 2) {
1128 auto incoming = pVert->particles_in();
1129 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1130 }
1131 return false;
1132}
1133
1137
1138 template <class T, class U>
1139 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1140 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1141 auto vtx = p->production_vertex();
1142 if (!vtx) return false;
1143 bool fromHad = false;
1144 for ( const auto& parent : particles_in(vtx) ) {
1145 if (!parent) continue;
1146 // should this really go into parton-level territory?
1147 // probably depends where BSM particles are being decayed
1148 fromBSM |= isBSM(parent);
1149 if (!isPhysical(parent)) return false;
1150 fromTau |= isTau(parent);
1151 if (isHadron(parent)&&!isBeam(parent)) {
1152 if (!hadron) hadron = parent; // assumes linear hadron parentage
1153 return true;
1154 }
1155 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1156 }
1157 return fromHad;
1158 }
1159
1162
1163 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1164 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1165 decltype(thePart->end_vertex()) pVert(nullptr);
1166 if (EndVert != nullptr) {
1167 do {
1168 bool samePart = false;
1169 pVert = nullptr;
1170 auto outgoing = EndVert->particles_out();
1171 auto incoming = EndVert->particles_in();
1172 for (const auto& itrDaug: outgoing) {
1173 if (!itrDaug) continue;
1174 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1175 // brem on generator level for tau
1176 (outgoing.size() == 1 && incoming.size() == 1 &&
1178 itrDaug->pdg_id() == thePart->pdg_id()) {
1179 samePart = true;
1180 pVert = itrDaug->end_vertex();
1181 }
1182 }
1183 if (samePart) EndVert = pVert;
1184 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1185 }
1186 return EndVert;
1187 }
1188
1190
1191 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1192 if (!theVert) return {};
1193 decltype(theVert->particles_out()) finalStatePart;
1194 auto outgoing = theVert->particles_out();
1195 for (const auto& thePart: outgoing) {
1196 if (!thePart) continue;
1197 finalStatePart.push_back(thePart);
1198 if (isStable(thePart)) continue;
1199 V pVert = findSimulatedEndVertex(thePart);
1200 if (pVert == theVert) break; // to prevent Sherpa loop
1201 if (pVert != nullptr) {
1202 auto vecPart = findFinalStateParticles<V>(pVert);
1203 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1204 }
1205 }
1206 return finalStatePart;
1207 }
1208
1209}
1210#endif

◆ isBeam()

template<class T>
bool MC::isBeam ( const T & p)
inline

Identify if the particle is beam particle.

Definition at line 57 of file HepMCHelpers.h.

◆ isBoson() [1/3]

template<>
bool MC::isBoson ( const DecodedPID & p)
inline

Definition at line 372 of file HepMCHelpers.h.

393{
394inline
395auto particles_in (const HepMC::GenVertex* p) {
396 return std::ranges::subrange (p->particles_in_const_begin(),
397 p->particles_in_const_end());
398}
399}
400#endif
401
402namespace MC
403{
404 template <class VTX>
405 auto particles_in (const VTX* p) { return p->particles_in(); }
406 template <class VTX>
407 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
408
409 namespace Pythia8
410 {
412 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
413
414 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
415
416 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
417 }
418
419#include "AtlasPID.h"
420
422 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
423
425 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
426
428 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
429
431 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
432
434 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
435
437 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
438
440 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
441
443 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
444
446 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
447
449 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
450
454 template <class T> inline bool isStableOrSimDecayed(const T& p) {
455 const auto vertex = p->end_vertex();
456 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
457 }
458
460 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
461
463 template <class T> inline bool isSpecialNonInteracting(const T& p) {
464 const int apid = std::abs(p->pdg_id());
465 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
466 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
467 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
468 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
469 return false;
470 }
471
473
474 template <class T> T findMother(T thePart) {
475 auto partOriVert = thePart->production_vertex();
476 if (!partOriVert) return nullptr;
477
478 long partPDG = thePart->pdg_id();
479 long MotherPDG(0);
480
481 auto MothOriVert = partOriVert;
482 MothOriVert = nullptr;
483 T theMoth(nullptr);
484
485 size_t itr = 0;
486 do {
487 if (itr != 0) partOriVert = MothOriVert;
488 for ( const auto& p : particles_in(partOriVert) ) {
489 theMoth = p;
490 if (!theMoth) continue;
491 MotherPDG = theMoth->pdg_id();
492 MothOriVert = theMoth->production_vertex();
493 if (MotherPDG == partPDG) break;
494 }
495 itr++;
496 if (itr > 100) {
497 break;
498 }
499 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
500 MothOriVert != partOriVert);
501 return theMoth;
502 }
503
505
506 template <class C, class T> T findMatching(C TruthContainer, T p) {
507 T ptrPart = nullptr;
508 if (!p) return ptrPart;
509 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
510 for (T truthParticle : *TruthContainer) {
511 if (HepMC::is_sim_descendant(p,truthParticle)) {
512 ptrPart = truthParticle;
513 break;
514 }
515 }
516 }
517 else {
518 for (T truthParticle : TruthContainer) {
519 if (HepMC::is_sim_descendant(p,truthParticle)) {
520 ptrPart = truthParticle;
521 break;
522 }
523 }
524 }
525 return ptrPart;
526 }
528
529 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
530 auto prodVtx = thePart->production_vertex();
531 if (!prodVtx) return;
532 for (const auto& theMother: prodVtx->particles_in()) {
533 if (!theMother) continue;
534 allancestors.insert(theMother);
535 findParticleAncestors(theMother, allancestors);
536 }
537 }
538
540
541 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
542 auto endVtx = thePart->end_vertex();
543 if (!endVtx) return;
544 for (const auto& theDaughter: endVtx->particles_out()) {
545 if (!theDaughter) continue;
546 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
547 allstabledescendants.insert(theDaughter);
548 }
549 findParticleStableDescendants(theDaughter, allstabledescendants);
550 }
551 }
552
556
557 template <class T> bool isHardScatteringVertex(T pVert) {
558 if (pVert == nullptr) return false;
559 T pV = pVert;
560 int numOfPartIn(0);
561 int pdg(0);
562
563 do {
564 pVert = pV;
565 auto incoming = pVert->particles_in();
566 numOfPartIn = incoming.size();
567 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
568 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
569
570 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
571
572 if (numOfPartIn == 2) {
573 auto incoming = pVert->particles_in();
574 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
575 }
576 return false;
577}
578
582
583 template <class T, class U>
584 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
585 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
586 auto vtx = p->production_vertex();
587 if (!vtx) return false;
588 bool fromHad = false;
589 for ( const auto& parent : particles_in(vtx) ) {
590 if (!parent) continue;
591 // should this really go into parton-level territory?
592 // probably depends where BSM particles are being decayed
593 fromBSM |= isBSM(parent);
594 if (!isPhysical(parent)) return false;
595 fromTau |= isTau(parent);
596 if (isHadron(parent)&&!isBeam(parent)) {
597 if (!hadron) hadron = parent; // assumes linear hadron parentage
598 return true;
599 }
600 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
601 }
602 return fromHad;
603 }
604
607
608 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
609 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
610 decltype(thePart->end_vertex()) pVert(nullptr);
611 if (EndVert != nullptr) {
612 do {
613 bool samePart = false;
614 pVert = nullptr;
615 auto outgoing = EndVert->particles_out();
616 auto incoming = EndVert->particles_in();
617 for (const auto& itrDaug: outgoing) {
618 if (!itrDaug) continue;
619 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
620 // brem on generator level for tau
621 (outgoing.size() == 1 && incoming.size() == 1 &&
623 itrDaug->pdg_id() == thePart->pdg_id()) {
624 samePart = true;
625 pVert = itrDaug->end_vertex();
626 }
627 }
628 if (samePart) EndVert = pVert;
629 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
630 }
631 return EndVert;
632 }
633
635
636 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
637 if (!theVert) return {};
638 decltype(theVert->particles_out()) finalStatePart;
639 auto outgoing = theVert->particles_out();
640 for (const auto& thePart: outgoing) {
641 if (!thePart) continue;
642 finalStatePart.push_back(thePart);
643 if (isStable(thePart)) continue;
644 V pVert = findSimulatedEndVertex(thePart);
645 if (pVert == theVert) break; // to prevent Sherpa loop
646 if (pVert != nullptr) {
647 auto vecPart = findFinalStateParticles<V>(pVert);
648 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
649 }
650 }
651 return finalStatePart;
652 }
653
654}
655#endif

◆ isBoson() [2/3]

template<>
bool MC::isBoson ( const int & p)
inline

Definition at line 371 of file HepMCHelpers.h.

392{
393inline
394auto particles_in (const HepMC::GenVertex* p) {
395 return std::ranges::subrange (p->particles_in_const_begin(),
396 p->particles_in_const_end());
397}
398}
399#endif
400
401namespace MC
402{
403 template <class VTX>
404 auto particles_in (const VTX* p) { return p->particles_in(); }
405 template <class VTX>
406 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
407
408 namespace Pythia8
409 {
411 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
412
413 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
414
415 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
416 }
417
418#include "AtlasPID.h"
419
421 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
422
424 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
425
427 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
428
430 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
431
433 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
434
436 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
437
439 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
440
442 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
443
445 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
446
448 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
449
453 template <class T> inline bool isStableOrSimDecayed(const T& p) {
454 const auto vertex = p->end_vertex();
455 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
456 }
457
459 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
460
462 template <class T> inline bool isSpecialNonInteracting(const T& p) {
463 const int apid = std::abs(p->pdg_id());
464 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
465 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
466 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
467 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
468 return false;
469 }
470
472
473 template <class T> T findMother(T thePart) {
474 auto partOriVert = thePart->production_vertex();
475 if (!partOriVert) return nullptr;
476
477 long partPDG = thePart->pdg_id();
478 long MotherPDG(0);
479
480 auto MothOriVert = partOriVert;
481 MothOriVert = nullptr;
482 T theMoth(nullptr);
483
484 size_t itr = 0;
485 do {
486 if (itr != 0) partOriVert = MothOriVert;
487 for ( const auto& p : particles_in(partOriVert) ) {
488 theMoth = p;
489 if (!theMoth) continue;
490 MotherPDG = theMoth->pdg_id();
491 MothOriVert = theMoth->production_vertex();
492 if (MotherPDG == partPDG) break;
493 }
494 itr++;
495 if (itr > 100) {
496 break;
497 }
498 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
499 MothOriVert != partOriVert);
500 return theMoth;
501 }
502
504
505 template <class C, class T> T findMatching(C TruthContainer, T p) {
506 T ptrPart = nullptr;
507 if (!p) return ptrPart;
508 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
509 for (T truthParticle : *TruthContainer) {
510 if (HepMC::is_sim_descendant(p,truthParticle)) {
511 ptrPart = truthParticle;
512 break;
513 }
514 }
515 }
516 else {
517 for (T truthParticle : TruthContainer) {
518 if (HepMC::is_sim_descendant(p,truthParticle)) {
519 ptrPart = truthParticle;
520 break;
521 }
522 }
523 }
524 return ptrPart;
525 }
527
528 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
529 auto prodVtx = thePart->production_vertex();
530 if (!prodVtx) return;
531 for (const auto& theMother: prodVtx->particles_in()) {
532 if (!theMother) continue;
533 allancestors.insert(theMother);
534 findParticleAncestors(theMother, allancestors);
535 }
536 }
537
539
540 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
541 auto endVtx = thePart->end_vertex();
542 if (!endVtx) return;
543 for (const auto& theDaughter: endVtx->particles_out()) {
544 if (!theDaughter) continue;
545 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
546 allstabledescendants.insert(theDaughter);
547 }
548 findParticleStableDescendants(theDaughter, allstabledescendants);
549 }
550 }
551
555
556 template <class T> bool isHardScatteringVertex(T pVert) {
557 if (pVert == nullptr) return false;
558 T pV = pVert;
559 int numOfPartIn(0);
560 int pdg(0);
561
562 do {
563 pVert = pV;
564 auto incoming = pVert->particles_in();
565 numOfPartIn = incoming.size();
566 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
567 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
568
569 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
570
571 if (numOfPartIn == 2) {
572 auto incoming = pVert->particles_in();
573 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
574 }
575 return false;
576}
577
581
582 template <class T, class U>
583 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
584 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
585 auto vtx = p->production_vertex();
586 if (!vtx) return false;
587 bool fromHad = false;
588 for ( const auto& parent : particles_in(vtx) ) {
589 if (!parent) continue;
590 // should this really go into parton-level territory?
591 // probably depends where BSM particles are being decayed
592 fromBSM |= isBSM(parent);
593 if (!isPhysical(parent)) return false;
594 fromTau |= isTau(parent);
595 if (isHadron(parent)&&!isBeam(parent)) {
596 if (!hadron) hadron = parent; // assumes linear hadron parentage
597 return true;
598 }
599 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
600 }
601 return fromHad;
602 }
603
606
607 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
608 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
609 decltype(thePart->end_vertex()) pVert(nullptr);
610 if (EndVert != nullptr) {
611 do {
612 bool samePart = false;
613 pVert = nullptr;
614 auto outgoing = EndVert->particles_out();
615 auto incoming = EndVert->particles_in();
616 for (const auto& itrDaug: outgoing) {
617 if (!itrDaug) continue;
618 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
619 // brem on generator level for tau
620 (outgoing.size() == 1 && incoming.size() == 1 &&
622 itrDaug->pdg_id() == thePart->pdg_id()) {
623 samePart = true;
624 pVert = itrDaug->end_vertex();
625 }
626 }
627 if (samePart) EndVert = pVert;
628 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
629 }
630 return EndVert;
631 }
632
634
635 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
636 if (!theVert) return {};
637 decltype(theVert->particles_out()) finalStatePart;
638 auto outgoing = theVert->particles_out();
639 for (const auto& thePart: outgoing) {
640 if (!thePart) continue;
641 finalStatePart.push_back(thePart);
642 if (isStable(thePart)) continue;
643 V pVert = findSimulatedEndVertex(thePart);
644 if (pVert == theVert) break; // to prevent Sherpa loop
645 if (pVert != nullptr) {
646 auto vecPart = findFinalStateParticles<V>(pVert);
647 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
648 }
649 }
650 return finalStatePart;
651 }
652
653}
654#endif

◆ isBoson() [3/3]

template<class T>
bool MC::isBoson ( const T & p)
inline

PDG rule 9: Two-digit numbers in the range 21–30 are provided for the Standard Model gauge and Higgs bosons.

PDG rule 11b: The graviton and the boson content of a two-Higgs-doublet scenario and of additional SU(2)×U(1) groups are found in the range 31–40.

Definition at line 370 of file HepMCHelpers.h.

391{
392inline
393auto particles_in (const HepMC::GenVertex* p) {
394 return std::ranges::subrange (p->particles_in_const_begin(),
395 p->particles_in_const_end());
396}
397}
398#endif
399
400namespace MC
401{
402 template <class VTX>
403 auto particles_in (const VTX* p) { return p->particles_in(); }
404 template <class VTX>
405 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
406
407 namespace Pythia8
408 {
410 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
411
412 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
413
414 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
415 }
416
417#include "AtlasPID.h"
418
420 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
421
423 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
424
426 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
427
429 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
430
432 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
433
435 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
436
438 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
439
441 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
442
444 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
445
447 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
448
452 template <class T> inline bool isStableOrSimDecayed(const T& p) {
453 const auto vertex = p->end_vertex();
454 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
455 }
456
458 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
459
461 template <class T> inline bool isSpecialNonInteracting(const T& p) {
462 const int apid = std::abs(p->pdg_id());
463 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
464 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
465 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
466 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
467 return false;
468 }
469
471
472 template <class T> T findMother(T thePart) {
473 auto partOriVert = thePart->production_vertex();
474 if (!partOriVert) return nullptr;
475
476 long partPDG = thePart->pdg_id();
477 long MotherPDG(0);
478
479 auto MothOriVert = partOriVert;
480 MothOriVert = nullptr;
481 T theMoth(nullptr);
482
483 size_t itr = 0;
484 do {
485 if (itr != 0) partOriVert = MothOriVert;
486 for ( const auto& p : particles_in(partOriVert) ) {
487 theMoth = p;
488 if (!theMoth) continue;
489 MotherPDG = theMoth->pdg_id();
490 MothOriVert = theMoth->production_vertex();
491 if (MotherPDG == partPDG) break;
492 }
493 itr++;
494 if (itr > 100) {
495 break;
496 }
497 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
498 MothOriVert != partOriVert);
499 return theMoth;
500 }
501
503
504 template <class C, class T> T findMatching(C TruthContainer, T p) {
505 T ptrPart = nullptr;
506 if (!p) return ptrPart;
507 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
508 for (T truthParticle : *TruthContainer) {
509 if (HepMC::is_sim_descendant(p,truthParticle)) {
510 ptrPart = truthParticle;
511 break;
512 }
513 }
514 }
515 else {
516 for (T truthParticle : TruthContainer) {
517 if (HepMC::is_sim_descendant(p,truthParticle)) {
518 ptrPart = truthParticle;
519 break;
520 }
521 }
522 }
523 return ptrPart;
524 }
526
527 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
528 auto prodVtx = thePart->production_vertex();
529 if (!prodVtx) return;
530 for (const auto& theMother: prodVtx->particles_in()) {
531 if (!theMother) continue;
532 allancestors.insert(theMother);
533 findParticleAncestors(theMother, allancestors);
534 }
535 }
536
538
539 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
540 auto endVtx = thePart->end_vertex();
541 if (!endVtx) return;
542 for (const auto& theDaughter: endVtx->particles_out()) {
543 if (!theDaughter) continue;
544 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
545 allstabledescendants.insert(theDaughter);
546 }
547 findParticleStableDescendants(theDaughter, allstabledescendants);
548 }
549 }
550
554
555 template <class T> bool isHardScatteringVertex(T pVert) {
556 if (pVert == nullptr) return false;
557 T pV = pVert;
558 int numOfPartIn(0);
559 int pdg(0);
560
561 do {
562 pVert = pV;
563 auto incoming = pVert->particles_in();
564 numOfPartIn = incoming.size();
565 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
566 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
567
568 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
569
570 if (numOfPartIn == 2) {
571 auto incoming = pVert->particles_in();
572 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
573 }
574 return false;
575}
576
580
581 template <class T, class U>
582 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
583 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
584 auto vtx = p->production_vertex();
585 if (!vtx) return false;
586 bool fromHad = false;
587 for ( const auto& parent : particles_in(vtx) ) {
588 if (!parent) continue;
589 // should this really go into parton-level territory?
590 // probably depends where BSM particles are being decayed
591 fromBSM |= isBSM(parent);
592 if (!isPhysical(parent)) return false;
593 fromTau |= isTau(parent);
594 if (isHadron(parent)&&!isBeam(parent)) {
595 if (!hadron) hadron = parent; // assumes linear hadron parentage
596 return true;
597 }
598 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
599 }
600 return fromHad;
601 }
602
605
606 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
607 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
608 decltype(thePart->end_vertex()) pVert(nullptr);
609 if (EndVert != nullptr) {
610 do {
611 bool samePart = false;
612 pVert = nullptr;
613 auto outgoing = EndVert->particles_out();
614 auto incoming = EndVert->particles_in();
615 for (const auto& itrDaug: outgoing) {
616 if (!itrDaug) continue;
617 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
618 // brem on generator level for tau
619 (outgoing.size() == 1 && incoming.size() == 1 &&
621 itrDaug->pdg_id() == thePart->pdg_id()) {
622 samePart = true;
623 pVert = itrDaug->end_vertex();
624 }
625 }
626 if (samePart) EndVert = pVert;
627 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
628 }
629 return EndVert;
630 }
631
633
634 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
635 if (!theVert) return {};
636 decltype(theVert->particles_out()) finalStatePart;
637 auto outgoing = theVert->particles_out();
638 for (const auto& thePart: outgoing) {
639 if (!thePart) continue;
640 finalStatePart.push_back(thePart);
641 if (isStable(thePart)) continue;
642 V pVert = findSimulatedEndVertex(thePart);
643 if (pVert == theVert) break; // to prevent Sherpa loop
644 if (pVert != nullptr) {
645 auto vecPart = findFinalStateParticles<V>(pVert);
646 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
647 }
648 }
649 return finalStatePart;
650 }
651
652}
653#endif

◆ isBottom() [1/2]

template<>
bool MC::isBottom ( const int & p)
inline

Definition at line 184 of file HepMCHelpers.h.

◆ isBottom() [2/2]

template<class T>
bool MC::isBottom ( const T & p)
inline

Definition at line 183 of file HepMCHelpers.h.

◆ isBottomBaryon()

template<class T>
bool MC::isBottomBaryon ( const T & p)
inline

Definition at line 936 of file HepMCHelpers.h.

957{
958inline
959auto particles_in (const HepMC::GenVertex* p) {
960 return std::ranges::subrange (p->particles_in_const_begin(),
961 p->particles_in_const_end());
962}
963}
964#endif
965
966namespace MC
967{
968 template <class VTX>
969 auto particles_in (const VTX* p) { return p->particles_in(); }
970 template <class VTX>
971 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
972
973 namespace Pythia8
974 {
976 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
977
978 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
979
980 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
981 }
982
983#include "AtlasPID.h"
984
986 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
987
989 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
990
992 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
993
995 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
996
998 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
999
1001 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1002
1004 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1005
1007 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1008
1010 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1011
1013 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1014
1018 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1019 const auto vertex = p->end_vertex();
1020 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1021 }
1022
1024 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1025
1027 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1028 const int apid = std::abs(p->pdg_id());
1029 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1030 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1031 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1032 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1033 return false;
1034 }
1035
1037
1038 template <class T> T findMother(T thePart) {
1039 auto partOriVert = thePart->production_vertex();
1040 if (!partOriVert) return nullptr;
1041
1042 long partPDG = thePart->pdg_id();
1043 long MotherPDG(0);
1044
1045 auto MothOriVert = partOriVert;
1046 MothOriVert = nullptr;
1047 T theMoth(nullptr);
1048
1049 size_t itr = 0;
1050 do {
1051 if (itr != 0) partOriVert = MothOriVert;
1052 for ( const auto& p : particles_in(partOriVert) ) {
1053 theMoth = p;
1054 if (!theMoth) continue;
1055 MotherPDG = theMoth->pdg_id();
1056 MothOriVert = theMoth->production_vertex();
1057 if (MotherPDG == partPDG) break;
1058 }
1059 itr++;
1060 if (itr > 100) {
1061 break;
1062 }
1063 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1064 MothOriVert != partOriVert);
1065 return theMoth;
1066 }
1067
1069
1070 template <class C, class T> T findMatching(C TruthContainer, T p) {
1071 T ptrPart = nullptr;
1072 if (!p) return ptrPart;
1073 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1074 for (T truthParticle : *TruthContainer) {
1075 if (HepMC::is_sim_descendant(p,truthParticle)) {
1076 ptrPart = truthParticle;
1077 break;
1078 }
1079 }
1080 }
1081 else {
1082 for (T truthParticle : TruthContainer) {
1083 if (HepMC::is_sim_descendant(p,truthParticle)) {
1084 ptrPart = truthParticle;
1085 break;
1086 }
1087 }
1088 }
1089 return ptrPart;
1090 }
1092
1093 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1094 auto prodVtx = thePart->production_vertex();
1095 if (!prodVtx) return;
1096 for (const auto& theMother: prodVtx->particles_in()) {
1097 if (!theMother) continue;
1098 allancestors.insert(theMother);
1099 findParticleAncestors(theMother, allancestors);
1100 }
1101 }
1102
1104
1105 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1106 auto endVtx = thePart->end_vertex();
1107 if (!endVtx) return;
1108 for (const auto& theDaughter: endVtx->particles_out()) {
1109 if (!theDaughter) continue;
1110 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1111 allstabledescendants.insert(theDaughter);
1112 }
1113 findParticleStableDescendants(theDaughter, allstabledescendants);
1114 }
1115 }
1116
1120
1121 template <class T> bool isHardScatteringVertex(T pVert) {
1122 if (pVert == nullptr) return false;
1123 T pV = pVert;
1124 int numOfPartIn(0);
1125 int pdg(0);
1126
1127 do {
1128 pVert = pV;
1129 auto incoming = pVert->particles_in();
1130 numOfPartIn = incoming.size();
1131 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1132 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1133
1134 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1135
1136 if (numOfPartIn == 2) {
1137 auto incoming = pVert->particles_in();
1138 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1139 }
1140 return false;
1141}
1142
1146
1147 template <class T, class U>
1148 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1149 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1150 auto vtx = p->production_vertex();
1151 if (!vtx) return false;
1152 bool fromHad = false;
1153 for ( const auto& parent : particles_in(vtx) ) {
1154 if (!parent) continue;
1155 // should this really go into parton-level territory?
1156 // probably depends where BSM particles are being decayed
1157 fromBSM |= isBSM(parent);
1158 if (!isPhysical(parent)) return false;
1159 fromTau |= isTau(parent);
1160 if (isHadron(parent)&&!isBeam(parent)) {
1161 if (!hadron) hadron = parent; // assumes linear hadron parentage
1162 return true;
1163 }
1164 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1165 }
1166 return fromHad;
1167 }
1168
1171
1172 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1173 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1174 decltype(thePart->end_vertex()) pVert(nullptr);
1175 if (EndVert != nullptr) {
1176 do {
1177 bool samePart = false;
1178 pVert = nullptr;
1179 auto outgoing = EndVert->particles_out();
1180 auto incoming = EndVert->particles_in();
1181 for (const auto& itrDaug: outgoing) {
1182 if (!itrDaug) continue;
1183 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1184 // brem on generator level for tau
1185 (outgoing.size() == 1 && incoming.size() == 1 &&
1187 itrDaug->pdg_id() == thePart->pdg_id()) {
1188 samePart = true;
1189 pVert = itrDaug->end_vertex();
1190 }
1191 }
1192 if (samePart) EndVert = pVert;
1193 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1194 }
1195 return EndVert;
1196 }
1197
1199
1200 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1201 if (!theVert) return {};
1202 decltype(theVert->particles_out()) finalStatePart;
1203 auto outgoing = theVert->particles_out();
1204 for (const auto& thePart: outgoing) {
1205 if (!thePart) continue;
1206 finalStatePart.push_back(thePart);
1207 if (isStable(thePart)) continue;
1208 V pVert = findSimulatedEndVertex(thePart);
1209 if (pVert == theVert) break; // to prevent Sherpa loop
1210 if (pVert != nullptr) {
1211 auto vecPart = findFinalStateParticles<V>(pVert);
1212 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1213 }
1214 }
1215 return finalStatePart;
1216 }
1217
1218}
1219#endif

◆ isBottomHadron()

template<class T>
bool MC::isBottomHadron ( const T & p)
inline

Definition at line 913 of file HepMCHelpers.h.

934{
935inline
936auto particles_in (const HepMC::GenVertex* p) {
937 return std::ranges::subrange (p->particles_in_const_begin(),
938 p->particles_in_const_end());
939}
940}
941#endif
942
943namespace MC
944{
945 template <class VTX>
946 auto particles_in (const VTX* p) { return p->particles_in(); }
947 template <class VTX>
948 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
949
950 namespace Pythia8
951 {
953 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
954
955 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
956
957 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
958 }
959
960#include "AtlasPID.h"
961
963 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
964
966 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
967
969 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
970
972 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
973
975 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
976
978 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
979
981 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
982
984 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
985
987 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
988
990 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
991
995 template <class T> inline bool isStableOrSimDecayed(const T& p) {
996 const auto vertex = p->end_vertex();
997 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
998 }
999
1001 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1002
1004 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1005 const int apid = std::abs(p->pdg_id());
1006 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1007 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1008 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1009 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1010 return false;
1011 }
1012
1014
1015 template <class T> T findMother(T thePart) {
1016 auto partOriVert = thePart->production_vertex();
1017 if (!partOriVert) return nullptr;
1018
1019 long partPDG = thePart->pdg_id();
1020 long MotherPDG(0);
1021
1022 auto MothOriVert = partOriVert;
1023 MothOriVert = nullptr;
1024 T theMoth(nullptr);
1025
1026 size_t itr = 0;
1027 do {
1028 if (itr != 0) partOriVert = MothOriVert;
1029 for ( const auto& p : particles_in(partOriVert) ) {
1030 theMoth = p;
1031 if (!theMoth) continue;
1032 MotherPDG = theMoth->pdg_id();
1033 MothOriVert = theMoth->production_vertex();
1034 if (MotherPDG == partPDG) break;
1035 }
1036 itr++;
1037 if (itr > 100) {
1038 break;
1039 }
1040 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1041 MothOriVert != partOriVert);
1042 return theMoth;
1043 }
1044
1046
1047 template <class C, class T> T findMatching(C TruthContainer, T p) {
1048 T ptrPart = nullptr;
1049 if (!p) return ptrPart;
1050 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1051 for (T truthParticle : *TruthContainer) {
1052 if (HepMC::is_sim_descendant(p,truthParticle)) {
1053 ptrPart = truthParticle;
1054 break;
1055 }
1056 }
1057 }
1058 else {
1059 for (T truthParticle : TruthContainer) {
1060 if (HepMC::is_sim_descendant(p,truthParticle)) {
1061 ptrPart = truthParticle;
1062 break;
1063 }
1064 }
1065 }
1066 return ptrPart;
1067 }
1069
1070 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1071 auto prodVtx = thePart->production_vertex();
1072 if (!prodVtx) return;
1073 for (const auto& theMother: prodVtx->particles_in()) {
1074 if (!theMother) continue;
1075 allancestors.insert(theMother);
1076 findParticleAncestors(theMother, allancestors);
1077 }
1078 }
1079
1081
1082 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1083 auto endVtx = thePart->end_vertex();
1084 if (!endVtx) return;
1085 for (const auto& theDaughter: endVtx->particles_out()) {
1086 if (!theDaughter) continue;
1087 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1088 allstabledescendants.insert(theDaughter);
1089 }
1090 findParticleStableDescendants(theDaughter, allstabledescendants);
1091 }
1092 }
1093
1097
1098 template <class T> bool isHardScatteringVertex(T pVert) {
1099 if (pVert == nullptr) return false;
1100 T pV = pVert;
1101 int numOfPartIn(0);
1102 int pdg(0);
1103
1104 do {
1105 pVert = pV;
1106 auto incoming = pVert->particles_in();
1107 numOfPartIn = incoming.size();
1108 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1109 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1110
1111 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1112
1113 if (numOfPartIn == 2) {
1114 auto incoming = pVert->particles_in();
1115 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1116 }
1117 return false;
1118}
1119
1123
1124 template <class T, class U>
1125 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1126 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1127 auto vtx = p->production_vertex();
1128 if (!vtx) return false;
1129 bool fromHad = false;
1130 for ( const auto& parent : particles_in(vtx) ) {
1131 if (!parent) continue;
1132 // should this really go into parton-level territory?
1133 // probably depends where BSM particles are being decayed
1134 fromBSM |= isBSM(parent);
1135 if (!isPhysical(parent)) return false;
1136 fromTau |= isTau(parent);
1137 if (isHadron(parent)&&!isBeam(parent)) {
1138 if (!hadron) hadron = parent; // assumes linear hadron parentage
1139 return true;
1140 }
1141 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1142 }
1143 return fromHad;
1144 }
1145
1148
1149 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1150 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1151 decltype(thePart->end_vertex()) pVert(nullptr);
1152 if (EndVert != nullptr) {
1153 do {
1154 bool samePart = false;
1155 pVert = nullptr;
1156 auto outgoing = EndVert->particles_out();
1157 auto incoming = EndVert->particles_in();
1158 for (const auto& itrDaug: outgoing) {
1159 if (!itrDaug) continue;
1160 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1161 // brem on generator level for tau
1162 (outgoing.size() == 1 && incoming.size() == 1 &&
1164 itrDaug->pdg_id() == thePart->pdg_id()) {
1165 samePart = true;
1166 pVert = itrDaug->end_vertex();
1167 }
1168 }
1169 if (samePart) EndVert = pVert;
1170 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1171 }
1172 return EndVert;
1173 }
1174
1176
1177 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1178 if (!theVert) return {};
1179 decltype(theVert->particles_out()) finalStatePart;
1180 auto outgoing = theVert->particles_out();
1181 for (const auto& thePart: outgoing) {
1182 if (!thePart) continue;
1183 finalStatePart.push_back(thePart);
1184 if (isStable(thePart)) continue;
1185 V pVert = findSimulatedEndVertex(thePart);
1186 if (pVert == theVert) break; // to prevent Sherpa loop
1187 if (pVert != nullptr) {
1188 auto vecPart = findFinalStateParticles<V>(pVert);
1189 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1190 }
1191 }
1192 return finalStatePart;
1193 }
1194
1195}
1196#endif

◆ isBottomMeson()

template<class T>
bool MC::isBottomMeson ( const T & p)
inline

Definition at line 920 of file HepMCHelpers.h.

941{
942inline
943auto particles_in (const HepMC::GenVertex* p) {
944 return std::ranges::subrange (p->particles_in_const_begin(),
945 p->particles_in_const_end());
946}
947}
948#endif
949
950namespace MC
951{
952 template <class VTX>
953 auto particles_in (const VTX* p) { return p->particles_in(); }
954 template <class VTX>
955 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
956
957 namespace Pythia8
958 {
960 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
961
962 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
963
964 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
965 }
966
967#include "AtlasPID.h"
968
970 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
971
973 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
974
976 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
977
979 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
980
982 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
983
985 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
986
988 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
989
991 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
992
994 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
995
997 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
998
1002 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1003 const auto vertex = p->end_vertex();
1004 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1005 }
1006
1008 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1009
1011 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1012 const int apid = std::abs(p->pdg_id());
1013 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1014 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1015 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1016 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1017 return false;
1018 }
1019
1021
1022 template <class T> T findMother(T thePart) {
1023 auto partOriVert = thePart->production_vertex();
1024 if (!partOriVert) return nullptr;
1025
1026 long partPDG = thePart->pdg_id();
1027 long MotherPDG(0);
1028
1029 auto MothOriVert = partOriVert;
1030 MothOriVert = nullptr;
1031 T theMoth(nullptr);
1032
1033 size_t itr = 0;
1034 do {
1035 if (itr != 0) partOriVert = MothOriVert;
1036 for ( const auto& p : particles_in(partOriVert) ) {
1037 theMoth = p;
1038 if (!theMoth) continue;
1039 MotherPDG = theMoth->pdg_id();
1040 MothOriVert = theMoth->production_vertex();
1041 if (MotherPDG == partPDG) break;
1042 }
1043 itr++;
1044 if (itr > 100) {
1045 break;
1046 }
1047 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1048 MothOriVert != partOriVert);
1049 return theMoth;
1050 }
1051
1053
1054 template <class C, class T> T findMatching(C TruthContainer, T p) {
1055 T ptrPart = nullptr;
1056 if (!p) return ptrPart;
1057 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1058 for (T truthParticle : *TruthContainer) {
1059 if (HepMC::is_sim_descendant(p,truthParticle)) {
1060 ptrPart = truthParticle;
1061 break;
1062 }
1063 }
1064 }
1065 else {
1066 for (T truthParticle : TruthContainer) {
1067 if (HepMC::is_sim_descendant(p,truthParticle)) {
1068 ptrPart = truthParticle;
1069 break;
1070 }
1071 }
1072 }
1073 return ptrPart;
1074 }
1076
1077 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1078 auto prodVtx = thePart->production_vertex();
1079 if (!prodVtx) return;
1080 for (const auto& theMother: prodVtx->particles_in()) {
1081 if (!theMother) continue;
1082 allancestors.insert(theMother);
1083 findParticleAncestors(theMother, allancestors);
1084 }
1085 }
1086
1088
1089 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1090 auto endVtx = thePart->end_vertex();
1091 if (!endVtx) return;
1092 for (const auto& theDaughter: endVtx->particles_out()) {
1093 if (!theDaughter) continue;
1094 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1095 allstabledescendants.insert(theDaughter);
1096 }
1097 findParticleStableDescendants(theDaughter, allstabledescendants);
1098 }
1099 }
1100
1104
1105 template <class T> bool isHardScatteringVertex(T pVert) {
1106 if (pVert == nullptr) return false;
1107 T pV = pVert;
1108 int numOfPartIn(0);
1109 int pdg(0);
1110
1111 do {
1112 pVert = pV;
1113 auto incoming = pVert->particles_in();
1114 numOfPartIn = incoming.size();
1115 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1116 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1117
1118 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1119
1120 if (numOfPartIn == 2) {
1121 auto incoming = pVert->particles_in();
1122 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1123 }
1124 return false;
1125}
1126
1130
1131 template <class T, class U>
1132 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1133 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1134 auto vtx = p->production_vertex();
1135 if (!vtx) return false;
1136 bool fromHad = false;
1137 for ( const auto& parent : particles_in(vtx) ) {
1138 if (!parent) continue;
1139 // should this really go into parton-level territory?
1140 // probably depends where BSM particles are being decayed
1141 fromBSM |= isBSM(parent);
1142 if (!isPhysical(parent)) return false;
1143 fromTau |= isTau(parent);
1144 if (isHadron(parent)&&!isBeam(parent)) {
1145 if (!hadron) hadron = parent; // assumes linear hadron parentage
1146 return true;
1147 }
1148 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1149 }
1150 return fromHad;
1151 }
1152
1155
1156 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1157 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1158 decltype(thePart->end_vertex()) pVert(nullptr);
1159 if (EndVert != nullptr) {
1160 do {
1161 bool samePart = false;
1162 pVert = nullptr;
1163 auto outgoing = EndVert->particles_out();
1164 auto incoming = EndVert->particles_in();
1165 for (const auto& itrDaug: outgoing) {
1166 if (!itrDaug) continue;
1167 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1168 // brem on generator level for tau
1169 (outgoing.size() == 1 && incoming.size() == 1 &&
1171 itrDaug->pdg_id() == thePart->pdg_id()) {
1172 samePart = true;
1173 pVert = itrDaug->end_vertex();
1174 }
1175 }
1176 if (samePart) EndVert = pVert;
1177 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1178 }
1179 return EndVert;
1180 }
1181
1183
1184 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1185 if (!theVert) return {};
1186 decltype(theVert->particles_out()) finalStatePart;
1187 auto outgoing = theVert->particles_out();
1188 for (const auto& thePart: outgoing) {
1189 if (!thePart) continue;
1190 finalStatePart.push_back(thePart);
1191 if (isStable(thePart)) continue;
1192 V pVert = findSimulatedEndVertex(thePart);
1193 if (pVert == theVert) break; // to prevent Sherpa loop
1194 if (pVert != nullptr) {
1195 auto vecPart = findFinalStateParticles<V>(pVert);
1196 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1197 }
1198 }
1199 return finalStatePart;
1200 }
1201
1202}
1203#endif

◆ isBSM() [1/3]

template<>
bool MC::isBSM ( const DecodedPID & p)
inline

Definition at line 848 of file HepMCHelpers.h.

869 {
870inline
871auto particles_in (const HepMC::GenVertex* p) {
872 return std::ranges::subrange (p->particles_in_const_begin(),
873 p->particles_in_const_end());
874}
875}
876#endif
877
878namespace MC
879{
880 template <class VTX>
881 auto particles_in (const VTX* p) { return p->particles_in(); }
882 template <class VTX>
883 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
884
885 namespace Pythia8
886 {
888 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
889
890 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
891
892 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
893 }
894
895#include "AtlasPID.h"
896
898 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
899
901 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
902
904 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
905
907 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
908
910 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
911
913 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
914
916 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
917
919 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
920
922 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
923
925 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
926
930 template <class T> inline bool isStableOrSimDecayed(const T& p) {
931 const auto vertex = p->end_vertex();
932 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
933 }
934
936 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
937
939 template <class T> inline bool isSpecialNonInteracting(const T& p) {
940 const int apid = std::abs(p->pdg_id());
941 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
942 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
943 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
944 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
945 return false;
946 }
947
949
950 template <class T> T findMother(T thePart) {
951 auto partOriVert = thePart->production_vertex();
952 if (!partOriVert) return nullptr;
953
954 long partPDG = thePart->pdg_id();
955 long MotherPDG(0);
956
957 auto MothOriVert = partOriVert;
958 MothOriVert = nullptr;
959 T theMoth(nullptr);
960
961 size_t itr = 0;
962 do {
963 if (itr != 0) partOriVert = MothOriVert;
964 for ( const auto& p : particles_in(partOriVert) ) {
965 theMoth = p;
966 if (!theMoth) continue;
967 MotherPDG = theMoth->pdg_id();
968 MothOriVert = theMoth->production_vertex();
969 if (MotherPDG == partPDG) break;
970 }
971 itr++;
972 if (itr > 100) {
973 break;
974 }
975 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
976 MothOriVert != partOriVert);
977 return theMoth;
978 }
979
981
982 template <class C, class T> T findMatching(C TruthContainer, T p) {
983 T ptrPart = nullptr;
984 if (!p) return ptrPart;
985 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
986 for (T truthParticle : *TruthContainer) {
987 if (HepMC::is_sim_descendant(p,truthParticle)) {
988 ptrPart = truthParticle;
989 break;
990 }
991 }
992 }
993 else {
994 for (T truthParticle : TruthContainer) {
995 if (HepMC::is_sim_descendant(p,truthParticle)) {
996 ptrPart = truthParticle;
997 break;
998 }
999 }
1000 }
1001 return ptrPart;
1002 }
1004
1005 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1006 auto prodVtx = thePart->production_vertex();
1007 if (!prodVtx) return;
1008 for (const auto& theMother: prodVtx->particles_in()) {
1009 if (!theMother) continue;
1010 allancestors.insert(theMother);
1011 findParticleAncestors(theMother, allancestors);
1012 }
1013 }
1014
1016
1017 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1018 auto endVtx = thePart->end_vertex();
1019 if (!endVtx) return;
1020 for (const auto& theDaughter: endVtx->particles_out()) {
1021 if (!theDaughter) continue;
1022 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1023 allstabledescendants.insert(theDaughter);
1024 }
1025 findParticleStableDescendants(theDaughter, allstabledescendants);
1026 }
1027 }
1028
1032
1033 template <class T> bool isHardScatteringVertex(T pVert) {
1034 if (pVert == nullptr) return false;
1035 T pV = pVert;
1036 int numOfPartIn(0);
1037 int pdg(0);
1038
1039 do {
1040 pVert = pV;
1041 auto incoming = pVert->particles_in();
1042 numOfPartIn = incoming.size();
1043 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1044 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1045
1046 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1047
1048 if (numOfPartIn == 2) {
1049 auto incoming = pVert->particles_in();
1050 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1051 }
1052 return false;
1053}
1054
1058
1059 template <class T, class U>
1060 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1061 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1062 auto vtx = p->production_vertex();
1063 if (!vtx) return false;
1064 bool fromHad = false;
1065 for ( const auto& parent : particles_in(vtx) ) {
1066 if (!parent) continue;
1067 // should this really go into parton-level territory?
1068 // probably depends where BSM particles are being decayed
1069 fromBSM |= isBSM(parent);
1070 if (!isPhysical(parent)) return false;
1071 fromTau |= isTau(parent);
1072 if (isHadron(parent)&&!isBeam(parent)) {
1073 if (!hadron) hadron = parent; // assumes linear hadron parentage
1074 return true;
1075 }
1076 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1077 }
1078 return fromHad;
1079 }
1080
1083
1084 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1085 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1086 decltype(thePart->end_vertex()) pVert(nullptr);
1087 if (EndVert != nullptr) {
1088 do {
1089 bool samePart = false;
1090 pVert = nullptr;
1091 auto outgoing = EndVert->particles_out();
1092 auto incoming = EndVert->particles_in();
1093 for (const auto& itrDaug: outgoing) {
1094 if (!itrDaug) continue;
1095 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1096 // brem on generator level for tau
1097 (outgoing.size() == 1 && incoming.size() == 1 &&
1099 itrDaug->pdg_id() == thePart->pdg_id()) {
1100 samePart = true;
1101 pVert = itrDaug->end_vertex();
1102 }
1103 }
1104 if (samePart) EndVert = pVert;
1105 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1106 }
1107 return EndVert;
1108 }
1109
1111
1112 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1113 if (!theVert) return {};
1114 decltype(theVert->particles_out()) finalStatePart;
1115 auto outgoing = theVert->particles_out();
1116 for (const auto& thePart: outgoing) {
1117 if (!thePart) continue;
1118 finalStatePart.push_back(thePart);
1119 if (isStable(thePart)) continue;
1120 V pVert = findSimulatedEndVertex(thePart);
1121 if (pVert == theVert) break; // to prevent Sherpa loop
1122 if (pVert != nullptr) {
1123 auto vecPart = findFinalStateParticles<V>(pVert);
1124 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1125 }
1126 }
1127 return finalStatePart;
1128 }
1129
1130}
1131#endif

◆ isBSM() [2/3]

template<>
bool MC::isBSM ( const int & p)
inline

Definition at line 865 of file HepMCHelpers.h.

886 {
887inline
888auto particles_in (const HepMC::GenVertex* p) {
889 return std::ranges::subrange (p->particles_in_const_begin(),
890 p->particles_in_const_end());
891}
892}
893#endif
894
895namespace MC
896{
897 template <class VTX>
898 auto particles_in (const VTX* p) { return p->particles_in(); }
899 template <class VTX>
900 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
901
902 namespace Pythia8
903 {
905 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
906
907 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
908
909 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
910 }
911
912#include "AtlasPID.h"
913
915 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
916
918 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
919
921 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
922
924 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
925
927 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
928
930 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
931
933 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
934
936 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
937
939 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
940
942 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
943
947 template <class T> inline bool isStableOrSimDecayed(const T& p) {
948 const auto vertex = p->end_vertex();
949 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
950 }
951
953 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
954
956 template <class T> inline bool isSpecialNonInteracting(const T& p) {
957 const int apid = std::abs(p->pdg_id());
958 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
959 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
960 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
961 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
962 return false;
963 }
964
966
967 template <class T> T findMother(T thePart) {
968 auto partOriVert = thePart->production_vertex();
969 if (!partOriVert) return nullptr;
970
971 long partPDG = thePart->pdg_id();
972 long MotherPDG(0);
973
974 auto MothOriVert = partOriVert;
975 MothOriVert = nullptr;
976 T theMoth(nullptr);
977
978 size_t itr = 0;
979 do {
980 if (itr != 0) partOriVert = MothOriVert;
981 for ( const auto& p : particles_in(partOriVert) ) {
982 theMoth = p;
983 if (!theMoth) continue;
984 MotherPDG = theMoth->pdg_id();
985 MothOriVert = theMoth->production_vertex();
986 if (MotherPDG == partPDG) break;
987 }
988 itr++;
989 if (itr > 100) {
990 break;
991 }
992 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
993 MothOriVert != partOriVert);
994 return theMoth;
995 }
996
998
999 template <class C, class T> T findMatching(C TruthContainer, T p) {
1000 T ptrPart = nullptr;
1001 if (!p) return ptrPart;
1002 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1003 for (T truthParticle : *TruthContainer) {
1004 if (HepMC::is_sim_descendant(p,truthParticle)) {
1005 ptrPart = truthParticle;
1006 break;
1007 }
1008 }
1009 }
1010 else {
1011 for (T truthParticle : TruthContainer) {
1012 if (HepMC::is_sim_descendant(p,truthParticle)) {
1013 ptrPart = truthParticle;
1014 break;
1015 }
1016 }
1017 }
1018 return ptrPart;
1019 }
1021
1022 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1023 auto prodVtx = thePart->production_vertex();
1024 if (!prodVtx) return;
1025 for (const auto& theMother: prodVtx->particles_in()) {
1026 if (!theMother) continue;
1027 allancestors.insert(theMother);
1028 findParticleAncestors(theMother, allancestors);
1029 }
1030 }
1031
1033
1034 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1035 auto endVtx = thePart->end_vertex();
1036 if (!endVtx) return;
1037 for (const auto& theDaughter: endVtx->particles_out()) {
1038 if (!theDaughter) continue;
1039 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1040 allstabledescendants.insert(theDaughter);
1041 }
1042 findParticleStableDescendants(theDaughter, allstabledescendants);
1043 }
1044 }
1045
1049
1050 template <class T> bool isHardScatteringVertex(T pVert) {
1051 if (pVert == nullptr) return false;
1052 T pV = pVert;
1053 int numOfPartIn(0);
1054 int pdg(0);
1055
1056 do {
1057 pVert = pV;
1058 auto incoming = pVert->particles_in();
1059 numOfPartIn = incoming.size();
1060 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1061 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1062
1063 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1064
1065 if (numOfPartIn == 2) {
1066 auto incoming = pVert->particles_in();
1067 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1068 }
1069 return false;
1070}
1071
1075
1076 template <class T, class U>
1077 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1078 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1079 auto vtx = p->production_vertex();
1080 if (!vtx) return false;
1081 bool fromHad = false;
1082 for ( const auto& parent : particles_in(vtx) ) {
1083 if (!parent) continue;
1084 // should this really go into parton-level territory?
1085 // probably depends where BSM particles are being decayed
1086 fromBSM |= isBSM(parent);
1087 if (!isPhysical(parent)) return false;
1088 fromTau |= isTau(parent);
1089 if (isHadron(parent)&&!isBeam(parent)) {
1090 if (!hadron) hadron = parent; // assumes linear hadron parentage
1091 return true;
1092 }
1093 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1094 }
1095 return fromHad;
1096 }
1097
1100
1101 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1102 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1103 decltype(thePart->end_vertex()) pVert(nullptr);
1104 if (EndVert != nullptr) {
1105 do {
1106 bool samePart = false;
1107 pVert = nullptr;
1108 auto outgoing = EndVert->particles_out();
1109 auto incoming = EndVert->particles_in();
1110 for (const auto& itrDaug: outgoing) {
1111 if (!itrDaug) continue;
1112 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1113 // brem on generator level for tau
1114 (outgoing.size() == 1 && incoming.size() == 1 &&
1116 itrDaug->pdg_id() == thePart->pdg_id()) {
1117 samePart = true;
1118 pVert = itrDaug->end_vertex();
1119 }
1120 }
1121 if (samePart) EndVert = pVert;
1122 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1123 }
1124 return EndVert;
1125 }
1126
1128
1129 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1130 if (!theVert) return {};
1131 decltype(theVert->particles_out()) finalStatePart;
1132 auto outgoing = theVert->particles_out();
1133 for (const auto& thePart: outgoing) {
1134 if (!thePart) continue;
1135 finalStatePart.push_back(thePart);
1136 if (isStable(thePart)) continue;
1137 V pVert = findSimulatedEndVertex(thePart);
1138 if (pVert == theVert) break; // to prevent Sherpa loop
1139 if (pVert != nullptr) {
1140 auto vecPart = findFinalStateParticles<V>(pVert);
1141 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1142 }
1143 }
1144 return finalStatePart;
1145 }
1146
1147}
1148#endif

◆ isBSM() [3/3]

template<class T>
bool MC::isBSM ( const T & p)
inline

APID: graviton and all Higgs extensions are BSM.

Definition at line 847 of file HepMCHelpers.h.

868{
869inline
870auto particles_in (const HepMC::GenVertex* p) {
871 return std::ranges::subrange (p->particles_in_const_begin(),
872 p->particles_in_const_end());
873}
874}
875#endif
876
877namespace MC
878{
879 template <class VTX>
880 auto particles_in (const VTX* p) { return p->particles_in(); }
881 template <class VTX>
882 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
883
884 namespace Pythia8
885 {
887 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
888
889 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
890
891 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
892 }
893
894#include "AtlasPID.h"
895
897 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
898
900 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
901
903 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
904
906 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
907
909 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
910
912 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
913
915 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
916
918 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
919
921 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
922
924 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
925
929 template <class T> inline bool isStableOrSimDecayed(const T& p) {
930 const auto vertex = p->end_vertex();
931 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
932 }
933
935 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
936
938 template <class T> inline bool isSpecialNonInteracting(const T& p) {
939 const int apid = std::abs(p->pdg_id());
940 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
941 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
942 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
943 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
944 return false;
945 }
946
948
949 template <class T> T findMother(T thePart) {
950 auto partOriVert = thePart->production_vertex();
951 if (!partOriVert) return nullptr;
952
953 long partPDG = thePart->pdg_id();
954 long MotherPDG(0);
955
956 auto MothOriVert = partOriVert;
957 MothOriVert = nullptr;
958 T theMoth(nullptr);
959
960 size_t itr = 0;
961 do {
962 if (itr != 0) partOriVert = MothOriVert;
963 for ( const auto& p : particles_in(partOriVert) ) {
964 theMoth = p;
965 if (!theMoth) continue;
966 MotherPDG = theMoth->pdg_id();
967 MothOriVert = theMoth->production_vertex();
968 if (MotherPDG == partPDG) break;
969 }
970 itr++;
971 if (itr > 100) {
972 break;
973 }
974 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
975 MothOriVert != partOriVert);
976 return theMoth;
977 }
978
980
981 template <class C, class T> T findMatching(C TruthContainer, T p) {
982 T ptrPart = nullptr;
983 if (!p) return ptrPart;
984 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
985 for (T truthParticle : *TruthContainer) {
986 if (HepMC::is_sim_descendant(p,truthParticle)) {
987 ptrPart = truthParticle;
988 break;
989 }
990 }
991 }
992 else {
993 for (T truthParticle : TruthContainer) {
994 if (HepMC::is_sim_descendant(p,truthParticle)) {
995 ptrPart = truthParticle;
996 break;
997 }
998 }
999 }
1000 return ptrPart;
1001 }
1003
1004 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1005 auto prodVtx = thePart->production_vertex();
1006 if (!prodVtx) return;
1007 for (const auto& theMother: prodVtx->particles_in()) {
1008 if (!theMother) continue;
1009 allancestors.insert(theMother);
1010 findParticleAncestors(theMother, allancestors);
1011 }
1012 }
1013
1015
1016 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1017 auto endVtx = thePart->end_vertex();
1018 if (!endVtx) return;
1019 for (const auto& theDaughter: endVtx->particles_out()) {
1020 if (!theDaughter) continue;
1021 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1022 allstabledescendants.insert(theDaughter);
1023 }
1024 findParticleStableDescendants(theDaughter, allstabledescendants);
1025 }
1026 }
1027
1031
1032 template <class T> bool isHardScatteringVertex(T pVert) {
1033 if (pVert == nullptr) return false;
1034 T pV = pVert;
1035 int numOfPartIn(0);
1036 int pdg(0);
1037
1038 do {
1039 pVert = pV;
1040 auto incoming = pVert->particles_in();
1041 numOfPartIn = incoming.size();
1042 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1043 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1044
1045 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1046
1047 if (numOfPartIn == 2) {
1048 auto incoming = pVert->particles_in();
1049 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1050 }
1051 return false;
1052}
1053
1057
1058 template <class T, class U>
1059 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1060 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1061 auto vtx = p->production_vertex();
1062 if (!vtx) return false;
1063 bool fromHad = false;
1064 for ( const auto& parent : particles_in(vtx) ) {
1065 if (!parent) continue;
1066 // should this really go into parton-level territory?
1067 // probably depends where BSM particles are being decayed
1068 fromBSM |= isBSM(parent);
1069 if (!isPhysical(parent)) return false;
1070 fromTau |= isTau(parent);
1071 if (isHadron(parent)&&!isBeam(parent)) {
1072 if (!hadron) hadron = parent; // assumes linear hadron parentage
1073 return true;
1074 }
1075 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1076 }
1077 return fromHad;
1078 }
1079
1082
1083 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1084 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1085 decltype(thePart->end_vertex()) pVert(nullptr);
1086 if (EndVert != nullptr) {
1087 do {
1088 bool samePart = false;
1089 pVert = nullptr;
1090 auto outgoing = EndVert->particles_out();
1091 auto incoming = EndVert->particles_in();
1092 for (const auto& itrDaug: outgoing) {
1093 if (!itrDaug) continue;
1094 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1095 // brem on generator level for tau
1096 (outgoing.size() == 1 && incoming.size() == 1 &&
1098 itrDaug->pdg_id() == thePart->pdg_id()) {
1099 samePart = true;
1100 pVert = itrDaug->end_vertex();
1101 }
1102 }
1103 if (samePart) EndVert = pVert;
1104 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1105 }
1106 return EndVert;
1107 }
1108
1110
1111 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1112 if (!theVert) return {};
1113 decltype(theVert->particles_out()) finalStatePart;
1114 auto outgoing = theVert->particles_out();
1115 for (const auto& thePart: outgoing) {
1116 if (!thePart) continue;
1117 finalStatePart.push_back(thePart);
1118 if (isStable(thePart)) continue;
1119 V pVert = findSimulatedEndVertex(thePart);
1120 if (pVert == theVert) break; // to prevent Sherpa loop
1121 if (pVert != nullptr) {
1122 auto vecPart = findFinalStateParticles<V>(pVert);
1123 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1124 }
1125 }
1126 return finalStatePart;
1127 }
1128
1129}
1130#endif

◆ isCCbarMeson() [1/3]

template<>
bool MC::isCCbarMeson ( const DecodedPID & p)
inline

Definition at line 924 of file HepMCHelpers.h.

945{
946inline
947auto particles_in (const HepMC::GenVertex* p) {
948 return std::ranges::subrange (p->particles_in_const_begin(),
949 p->particles_in_const_end());
950}
951}
952#endif
953
954namespace MC
955{
956 template <class VTX>
957 auto particles_in (const VTX* p) { return p->particles_in(); }
958 template <class VTX>
959 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
960
961 namespace Pythia8
962 {
964 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
965
966 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
967
968 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
969 }
970
971#include "AtlasPID.h"
972
974 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
975
977 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
978
980 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
981
983 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
984
986 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
987
989 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
990
992 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
993
995 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
996
998 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
999
1001 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1002
1006 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1007 const auto vertex = p->end_vertex();
1008 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1009 }
1010
1012 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1013
1015 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1016 const int apid = std::abs(p->pdg_id());
1017 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1018 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1019 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1020 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1021 return false;
1022 }
1023
1025
1026 template <class T> T findMother(T thePart) {
1027 auto partOriVert = thePart->production_vertex();
1028 if (!partOriVert) return nullptr;
1029
1030 long partPDG = thePart->pdg_id();
1031 long MotherPDG(0);
1032
1033 auto MothOriVert = partOriVert;
1034 MothOriVert = nullptr;
1035 T theMoth(nullptr);
1036
1037 size_t itr = 0;
1038 do {
1039 if (itr != 0) partOriVert = MothOriVert;
1040 for ( const auto& p : particles_in(partOriVert) ) {
1041 theMoth = p;
1042 if (!theMoth) continue;
1043 MotherPDG = theMoth->pdg_id();
1044 MothOriVert = theMoth->production_vertex();
1045 if (MotherPDG == partPDG) break;
1046 }
1047 itr++;
1048 if (itr > 100) {
1049 break;
1050 }
1051 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1052 MothOriVert != partOriVert);
1053 return theMoth;
1054 }
1055
1057
1058 template <class C, class T> T findMatching(C TruthContainer, T p) {
1059 T ptrPart = nullptr;
1060 if (!p) return ptrPart;
1061 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1062 for (T truthParticle : *TruthContainer) {
1063 if (HepMC::is_sim_descendant(p,truthParticle)) {
1064 ptrPart = truthParticle;
1065 break;
1066 }
1067 }
1068 }
1069 else {
1070 for (T truthParticle : TruthContainer) {
1071 if (HepMC::is_sim_descendant(p,truthParticle)) {
1072 ptrPart = truthParticle;
1073 break;
1074 }
1075 }
1076 }
1077 return ptrPart;
1078 }
1080
1081 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1082 auto prodVtx = thePart->production_vertex();
1083 if (!prodVtx) return;
1084 for (const auto& theMother: prodVtx->particles_in()) {
1085 if (!theMother) continue;
1086 allancestors.insert(theMother);
1087 findParticleAncestors(theMother, allancestors);
1088 }
1089 }
1090
1092
1093 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1094 auto endVtx = thePart->end_vertex();
1095 if (!endVtx) return;
1096 for (const auto& theDaughter: endVtx->particles_out()) {
1097 if (!theDaughter) continue;
1098 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1099 allstabledescendants.insert(theDaughter);
1100 }
1101 findParticleStableDescendants(theDaughter, allstabledescendants);
1102 }
1103 }
1104
1108
1109 template <class T> bool isHardScatteringVertex(T pVert) {
1110 if (pVert == nullptr) return false;
1111 T pV = pVert;
1112 int numOfPartIn(0);
1113 int pdg(0);
1114
1115 do {
1116 pVert = pV;
1117 auto incoming = pVert->particles_in();
1118 numOfPartIn = incoming.size();
1119 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1120 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1121
1122 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1123
1124 if (numOfPartIn == 2) {
1125 auto incoming = pVert->particles_in();
1126 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1127 }
1128 return false;
1129}
1130
1134
1135 template <class T, class U>
1136 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1137 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1138 auto vtx = p->production_vertex();
1139 if (!vtx) return false;
1140 bool fromHad = false;
1141 for ( const auto& parent : particles_in(vtx) ) {
1142 if (!parent) continue;
1143 // should this really go into parton-level territory?
1144 // probably depends where BSM particles are being decayed
1145 fromBSM |= isBSM(parent);
1146 if (!isPhysical(parent)) return false;
1147 fromTau |= isTau(parent);
1148 if (isHadron(parent)&&!isBeam(parent)) {
1149 if (!hadron) hadron = parent; // assumes linear hadron parentage
1150 return true;
1151 }
1152 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1153 }
1154 return fromHad;
1155 }
1156
1159
1160 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1161 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1162 decltype(thePart->end_vertex()) pVert(nullptr);
1163 if (EndVert != nullptr) {
1164 do {
1165 bool samePart = false;
1166 pVert = nullptr;
1167 auto outgoing = EndVert->particles_out();
1168 auto incoming = EndVert->particles_in();
1169 for (const auto& itrDaug: outgoing) {
1170 if (!itrDaug) continue;
1171 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1172 // brem on generator level for tau
1173 (outgoing.size() == 1 && incoming.size() == 1 &&
1175 itrDaug->pdg_id() == thePart->pdg_id()) {
1176 samePart = true;
1177 pVert = itrDaug->end_vertex();
1178 }
1179 }
1180 if (samePart) EndVert = pVert;
1181 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1182 }
1183 return EndVert;
1184 }
1185
1187
1188 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1189 if (!theVert) return {};
1190 decltype(theVert->particles_out()) finalStatePart;
1191 auto outgoing = theVert->particles_out();
1192 for (const auto& thePart: outgoing) {
1193 if (!thePart) continue;
1194 finalStatePart.push_back(thePart);
1195 if (isStable(thePart)) continue;
1196 V pVert = findSimulatedEndVertex(thePart);
1197 if (pVert == theVert) break; // to prevent Sherpa loop
1198 if (pVert != nullptr) {
1199 auto vecPart = findFinalStateParticles<V>(pVert);
1200 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1201 }
1202 }
1203 return finalStatePart;
1204 }
1205
1206}
1207#endif

◆ isCCbarMeson() [2/3]

template<>
bool MC::isCCbarMeson ( const int & p)
inline

Definition at line 925 of file HepMCHelpers.h.

946{
947inline
948auto particles_in (const HepMC::GenVertex* p) {
949 return std::ranges::subrange (p->particles_in_const_begin(),
950 p->particles_in_const_end());
951}
952}
953#endif
954
955namespace MC
956{
957 template <class VTX>
958 auto particles_in (const VTX* p) { return p->particles_in(); }
959 template <class VTX>
960 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
961
962 namespace Pythia8
963 {
965 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
966
967 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
968
969 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
970 }
971
972#include "AtlasPID.h"
973
975 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
976
978 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
979
981 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
982
984 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
985
987 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
988
990 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
991
993 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
994
996 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
997
999 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1000
1002 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1003
1007 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1008 const auto vertex = p->end_vertex();
1009 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1010 }
1011
1013 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1014
1016 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1017 const int apid = std::abs(p->pdg_id());
1018 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1019 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1020 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1021 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1022 return false;
1023 }
1024
1026
1027 template <class T> T findMother(T thePart) {
1028 auto partOriVert = thePart->production_vertex();
1029 if (!partOriVert) return nullptr;
1030
1031 long partPDG = thePart->pdg_id();
1032 long MotherPDG(0);
1033
1034 auto MothOriVert = partOriVert;
1035 MothOriVert = nullptr;
1036 T theMoth(nullptr);
1037
1038 size_t itr = 0;
1039 do {
1040 if (itr != 0) partOriVert = MothOriVert;
1041 for ( const auto& p : particles_in(partOriVert) ) {
1042 theMoth = p;
1043 if (!theMoth) continue;
1044 MotherPDG = theMoth->pdg_id();
1045 MothOriVert = theMoth->production_vertex();
1046 if (MotherPDG == partPDG) break;
1047 }
1048 itr++;
1049 if (itr > 100) {
1050 break;
1051 }
1052 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1053 MothOriVert != partOriVert);
1054 return theMoth;
1055 }
1056
1058
1059 template <class C, class T> T findMatching(C TruthContainer, T p) {
1060 T ptrPart = nullptr;
1061 if (!p) return ptrPart;
1062 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1063 for (T truthParticle : *TruthContainer) {
1064 if (HepMC::is_sim_descendant(p,truthParticle)) {
1065 ptrPart = truthParticle;
1066 break;
1067 }
1068 }
1069 }
1070 else {
1071 for (T truthParticle : TruthContainer) {
1072 if (HepMC::is_sim_descendant(p,truthParticle)) {
1073 ptrPart = truthParticle;
1074 break;
1075 }
1076 }
1077 }
1078 return ptrPart;
1079 }
1081
1082 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1083 auto prodVtx = thePart->production_vertex();
1084 if (!prodVtx) return;
1085 for (const auto& theMother: prodVtx->particles_in()) {
1086 if (!theMother) continue;
1087 allancestors.insert(theMother);
1088 findParticleAncestors(theMother, allancestors);
1089 }
1090 }
1091
1093
1094 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1095 auto endVtx = thePart->end_vertex();
1096 if (!endVtx) return;
1097 for (const auto& theDaughter: endVtx->particles_out()) {
1098 if (!theDaughter) continue;
1099 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1100 allstabledescendants.insert(theDaughter);
1101 }
1102 findParticleStableDescendants(theDaughter, allstabledescendants);
1103 }
1104 }
1105
1109
1110 template <class T> bool isHardScatteringVertex(T pVert) {
1111 if (pVert == nullptr) return false;
1112 T pV = pVert;
1113 int numOfPartIn(0);
1114 int pdg(0);
1115
1116 do {
1117 pVert = pV;
1118 auto incoming = pVert->particles_in();
1119 numOfPartIn = incoming.size();
1120 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1121 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1122
1123 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1124
1125 if (numOfPartIn == 2) {
1126 auto incoming = pVert->particles_in();
1127 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1128 }
1129 return false;
1130}
1131
1135
1136 template <class T, class U>
1137 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1138 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1139 auto vtx = p->production_vertex();
1140 if (!vtx) return false;
1141 bool fromHad = false;
1142 for ( const auto& parent : particles_in(vtx) ) {
1143 if (!parent) continue;
1144 // should this really go into parton-level territory?
1145 // probably depends where BSM particles are being decayed
1146 fromBSM |= isBSM(parent);
1147 if (!isPhysical(parent)) return false;
1148 fromTau |= isTau(parent);
1149 if (isHadron(parent)&&!isBeam(parent)) {
1150 if (!hadron) hadron = parent; // assumes linear hadron parentage
1151 return true;
1152 }
1153 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1154 }
1155 return fromHad;
1156 }
1157
1160
1161 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1162 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1163 decltype(thePart->end_vertex()) pVert(nullptr);
1164 if (EndVert != nullptr) {
1165 do {
1166 bool samePart = false;
1167 pVert = nullptr;
1168 auto outgoing = EndVert->particles_out();
1169 auto incoming = EndVert->particles_in();
1170 for (const auto& itrDaug: outgoing) {
1171 if (!itrDaug) continue;
1172 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1173 // brem on generator level for tau
1174 (outgoing.size() == 1 && incoming.size() == 1 &&
1176 itrDaug->pdg_id() == thePart->pdg_id()) {
1177 samePart = true;
1178 pVert = itrDaug->end_vertex();
1179 }
1180 }
1181 if (samePart) EndVert = pVert;
1182 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1183 }
1184 return EndVert;
1185 }
1186
1188
1189 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1190 if (!theVert) return {};
1191 decltype(theVert->particles_out()) finalStatePart;
1192 auto outgoing = theVert->particles_out();
1193 for (const auto& thePart: outgoing) {
1194 if (!thePart) continue;
1195 finalStatePart.push_back(thePart);
1196 if (isStable(thePart)) continue;
1197 V pVert = findSimulatedEndVertex(thePart);
1198 if (pVert == theVert) break; // to prevent Sherpa loop
1199 if (pVert != nullptr) {
1200 auto vecPart = findFinalStateParticles<V>(pVert);
1201 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1202 }
1203 }
1204 return finalStatePart;
1205 }
1206
1207}
1208#endif

◆ isCCbarMeson() [3/3]

template<class T>
bool MC::isCCbarMeson ( const T & p)
inline

Definition at line 923 of file HepMCHelpers.h.

944{
945inline
946auto particles_in (const HepMC::GenVertex* p) {
947 return std::ranges::subrange (p->particles_in_const_begin(),
948 p->particles_in_const_end());
949}
950}
951#endif
952
953namespace MC
954{
955 template <class VTX>
956 auto particles_in (const VTX* p) { return p->particles_in(); }
957 template <class VTX>
958 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
959
960 namespace Pythia8
961 {
963 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
964
965 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
966
967 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
968 }
969
970#include "AtlasPID.h"
971
973 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
974
976 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
977
979 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
980
982 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
983
985 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
986
988 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
989
991 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
992
994 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
995
997 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
998
1000 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1001
1005 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1006 const auto vertex = p->end_vertex();
1007 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1008 }
1009
1011 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1012
1014 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1015 const int apid = std::abs(p->pdg_id());
1016 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1017 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1018 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1019 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1020 return false;
1021 }
1022
1024
1025 template <class T> T findMother(T thePart) {
1026 auto partOriVert = thePart->production_vertex();
1027 if (!partOriVert) return nullptr;
1028
1029 long partPDG = thePart->pdg_id();
1030 long MotherPDG(0);
1031
1032 auto MothOriVert = partOriVert;
1033 MothOriVert = nullptr;
1034 T theMoth(nullptr);
1035
1036 size_t itr = 0;
1037 do {
1038 if (itr != 0) partOriVert = MothOriVert;
1039 for ( const auto& p : particles_in(partOriVert) ) {
1040 theMoth = p;
1041 if (!theMoth) continue;
1042 MotherPDG = theMoth->pdg_id();
1043 MothOriVert = theMoth->production_vertex();
1044 if (MotherPDG == partPDG) break;
1045 }
1046 itr++;
1047 if (itr > 100) {
1048 break;
1049 }
1050 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1051 MothOriVert != partOriVert);
1052 return theMoth;
1053 }
1054
1056
1057 template <class C, class T> T findMatching(C TruthContainer, T p) {
1058 T ptrPart = nullptr;
1059 if (!p) return ptrPart;
1060 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1061 for (T truthParticle : *TruthContainer) {
1062 if (HepMC::is_sim_descendant(p,truthParticle)) {
1063 ptrPart = truthParticle;
1064 break;
1065 }
1066 }
1067 }
1068 else {
1069 for (T truthParticle : TruthContainer) {
1070 if (HepMC::is_sim_descendant(p,truthParticle)) {
1071 ptrPart = truthParticle;
1072 break;
1073 }
1074 }
1075 }
1076 return ptrPart;
1077 }
1079
1080 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1081 auto prodVtx = thePart->production_vertex();
1082 if (!prodVtx) return;
1083 for (const auto& theMother: prodVtx->particles_in()) {
1084 if (!theMother) continue;
1085 allancestors.insert(theMother);
1086 findParticleAncestors(theMother, allancestors);
1087 }
1088 }
1089
1091
1092 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1093 auto endVtx = thePart->end_vertex();
1094 if (!endVtx) return;
1095 for (const auto& theDaughter: endVtx->particles_out()) {
1096 if (!theDaughter) continue;
1097 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1098 allstabledescendants.insert(theDaughter);
1099 }
1100 findParticleStableDescendants(theDaughter, allstabledescendants);
1101 }
1102 }
1103
1107
1108 template <class T> bool isHardScatteringVertex(T pVert) {
1109 if (pVert == nullptr) return false;
1110 T pV = pVert;
1111 int numOfPartIn(0);
1112 int pdg(0);
1113
1114 do {
1115 pVert = pV;
1116 auto incoming = pVert->particles_in();
1117 numOfPartIn = incoming.size();
1118 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1119 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1120
1121 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1122
1123 if (numOfPartIn == 2) {
1124 auto incoming = pVert->particles_in();
1125 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1126 }
1127 return false;
1128}
1129
1133
1134 template <class T, class U>
1135 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1136 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1137 auto vtx = p->production_vertex();
1138 if (!vtx) return false;
1139 bool fromHad = false;
1140 for ( const auto& parent : particles_in(vtx) ) {
1141 if (!parent) continue;
1142 // should this really go into parton-level territory?
1143 // probably depends where BSM particles are being decayed
1144 fromBSM |= isBSM(parent);
1145 if (!isPhysical(parent)) return false;
1146 fromTau |= isTau(parent);
1147 if (isHadron(parent)&&!isBeam(parent)) {
1148 if (!hadron) hadron = parent; // assumes linear hadron parentage
1149 return true;
1150 }
1151 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1152 }
1153 return fromHad;
1154 }
1155
1158
1159 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1160 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1161 decltype(thePart->end_vertex()) pVert(nullptr);
1162 if (EndVert != nullptr) {
1163 do {
1164 bool samePart = false;
1165 pVert = nullptr;
1166 auto outgoing = EndVert->particles_out();
1167 auto incoming = EndVert->particles_in();
1168 for (const auto& itrDaug: outgoing) {
1169 if (!itrDaug) continue;
1170 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1171 // brem on generator level for tau
1172 (outgoing.size() == 1 && incoming.size() == 1 &&
1174 itrDaug->pdg_id() == thePart->pdg_id()) {
1175 samePart = true;
1176 pVert = itrDaug->end_vertex();
1177 }
1178 }
1179 if (samePart) EndVert = pVert;
1180 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1181 }
1182 return EndVert;
1183 }
1184
1186
1187 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1188 if (!theVert) return {};
1189 decltype(theVert->particles_out()) finalStatePart;
1190 auto outgoing = theVert->particles_out();
1191 for (const auto& thePart: outgoing) {
1192 if (!thePart) continue;
1193 finalStatePart.push_back(thePart);
1194 if (isStable(thePart)) continue;
1195 V pVert = findSimulatedEndVertex(thePart);
1196 if (pVert == theVert) break; // to prevent Sherpa loop
1197 if (pVert != nullptr) {
1198 auto vecPart = findFinalStateParticles<V>(pVert);
1199 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1200 }
1201 }
1202 return finalStatePart;
1203 }
1204
1205}
1206#endif

◆ isCharged()

template<class T>
bool MC::isCharged ( const T & p)
inline

Definition at line 1005 of file HepMCHelpers.h.

1026{
1027inline
1028auto particles_in (const HepMC::GenVertex* p) {
1029 return std::ranges::subrange (p->particles_in_const_begin(),
1030 p->particles_in_const_end());
1031}
1032}
1033#endif
1034
1035namespace MC
1036{
1037 template <class VTX>
1038 auto particles_in (const VTX* p) { return p->particles_in(); }
1039 template <class VTX>
1040 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1041
1042 namespace Pythia8
1043 {
1045 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1046
1047 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1048
1049 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1050 }
1051
1052#include "AtlasPID.h"
1053
1055 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1056
1058 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1059
1061 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1062
1064 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1065
1067 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1068
1070 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1071
1073 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1074
1076 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1077
1079 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1080
1082 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1083
1087 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1088 const auto vertex = p->end_vertex();
1089 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1090 }
1091
1093 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1094
1096 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1097 const int apid = std::abs(p->pdg_id());
1098 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1099 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1100 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1101 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1102 return false;
1103 }
1104
1106
1107 template <class T> T findMother(T thePart) {
1108 auto partOriVert = thePart->production_vertex();
1109 if (!partOriVert) return nullptr;
1110
1111 long partPDG = thePart->pdg_id();
1112 long MotherPDG(0);
1113
1114 auto MothOriVert = partOriVert;
1115 MothOriVert = nullptr;
1116 T theMoth(nullptr);
1117
1118 size_t itr = 0;
1119 do {
1120 if (itr != 0) partOriVert = MothOriVert;
1121 for ( const auto& p : particles_in(partOriVert) ) {
1122 theMoth = p;
1123 if (!theMoth) continue;
1124 MotherPDG = theMoth->pdg_id();
1125 MothOriVert = theMoth->production_vertex();
1126 if (MotherPDG == partPDG) break;
1127 }
1128 itr++;
1129 if (itr > 100) {
1130 break;
1131 }
1132 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1133 MothOriVert != partOriVert);
1134 return theMoth;
1135 }
1136
1138
1139 template <class C, class T> T findMatching(C TruthContainer, T p) {
1140 T ptrPart = nullptr;
1141 if (!p) return ptrPart;
1142 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1143 for (T truthParticle : *TruthContainer) {
1144 if (HepMC::is_sim_descendant(p,truthParticle)) {
1145 ptrPart = truthParticle;
1146 break;
1147 }
1148 }
1149 }
1150 else {
1151 for (T truthParticle : TruthContainer) {
1152 if (HepMC::is_sim_descendant(p,truthParticle)) {
1153 ptrPart = truthParticle;
1154 break;
1155 }
1156 }
1157 }
1158 return ptrPart;
1159 }
1161
1162 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1163 auto prodVtx = thePart->production_vertex();
1164 if (!prodVtx) return;
1165 for (const auto& theMother: prodVtx->particles_in()) {
1166 if (!theMother) continue;
1167 allancestors.insert(theMother);
1168 findParticleAncestors(theMother, allancestors);
1169 }
1170 }
1171
1173
1174 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1175 auto endVtx = thePart->end_vertex();
1176 if (!endVtx) return;
1177 for (const auto& theDaughter: endVtx->particles_out()) {
1178 if (!theDaughter) continue;
1179 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1180 allstabledescendants.insert(theDaughter);
1181 }
1182 findParticleStableDescendants(theDaughter, allstabledescendants);
1183 }
1184 }
1185
1189
1190 template <class T> bool isHardScatteringVertex(T pVert) {
1191 if (pVert == nullptr) return false;
1192 T pV = pVert;
1193 int numOfPartIn(0);
1194 int pdg(0);
1195
1196 do {
1197 pVert = pV;
1198 auto incoming = pVert->particles_in();
1199 numOfPartIn = incoming.size();
1200 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1201 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1202
1203 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1204
1205 if (numOfPartIn == 2) {
1206 auto incoming = pVert->particles_in();
1207 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1208 }
1209 return false;
1210}
1211
1215
1216 template <class T, class U>
1217 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1218 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1219 auto vtx = p->production_vertex();
1220 if (!vtx) return false;
1221 bool fromHad = false;
1222 for ( const auto& parent : particles_in(vtx) ) {
1223 if (!parent) continue;
1224 // should this really go into parton-level territory?
1225 // probably depends where BSM particles are being decayed
1226 fromBSM |= isBSM(parent);
1227 if (!isPhysical(parent)) return false;
1228 fromTau |= isTau(parent);
1229 if (isHadron(parent)&&!isBeam(parent)) {
1230 if (!hadron) hadron = parent; // assumes linear hadron parentage
1231 return true;
1232 }
1233 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1234 }
1235 return fromHad;
1236 }
1237
1240
1241 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1242 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1243 decltype(thePart->end_vertex()) pVert(nullptr);
1244 if (EndVert != nullptr) {
1245 do {
1246 bool samePart = false;
1247 pVert = nullptr;
1248 auto outgoing = EndVert->particles_out();
1249 auto incoming = EndVert->particles_in();
1250 for (const auto& itrDaug: outgoing) {
1251 if (!itrDaug) continue;
1252 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1253 // brem on generator level for tau
1254 (outgoing.size() == 1 && incoming.size() == 1 &&
1256 itrDaug->pdg_id() == thePart->pdg_id()) {
1257 samePart = true;
1258 pVert = itrDaug->end_vertex();
1259 }
1260 }
1261 if (samePart) EndVert = pVert;
1262 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1263 }
1264 return EndVert;
1265 }
1266
1268
1269 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1270 if (!theVert) return {};
1271 decltype(theVert->particles_out()) finalStatePart;
1272 auto outgoing = theVert->particles_out();
1273 for (const auto& thePart: outgoing) {
1274 if (!thePart) continue;
1275 finalStatePart.push_back(thePart);
1276 if (isStable(thePart)) continue;
1277 V pVert = findSimulatedEndVertex(thePart);
1278 if (pVert == theVert) break; // to prevent Sherpa loop
1279 if (pVert != nullptr) {
1280 auto vecPart = findFinalStateParticles<V>(pVert);
1281 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1282 }
1283 }
1284 return finalStatePart;
1285 }
1286
1287}
1288#endif

◆ isChargedNonShowering()

template<class T>
bool MC::isChargedNonShowering ( const T & p)
inline

Identify if the particle with given PDG ID would produce ID tracks but not shower in the detector if stable.

Definition at line 54 of file HepMCHelpers.h.

54{ return (isMuon<T>(p) || isSUSY<T>(p)); }

◆ isCharm() [1/2]

template<>
bool MC::isCharm ( const int & p)
inline

Definition at line 181 of file HepMCHelpers.h.

◆ isCharm() [2/2]

template<class T>
bool MC::isCharm ( const T & p)
inline

Definition at line 180 of file HepMCHelpers.h.

◆ isCharmBaryon()

template<class T>
bool MC::isCharmBaryon ( const T & p)
inline

Definition at line 935 of file HepMCHelpers.h.

956{
957inline
958auto particles_in (const HepMC::GenVertex* p) {
959 return std::ranges::subrange (p->particles_in_const_begin(),
960 p->particles_in_const_end());
961}
962}
963#endif
964
965namespace MC
966{
967 template <class VTX>
968 auto particles_in (const VTX* p) { return p->particles_in(); }
969 template <class VTX>
970 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
971
972 namespace Pythia8
973 {
975 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
976
977 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
978
979 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
980 }
981
982#include "AtlasPID.h"
983
985 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
986
988 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
989
991 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
992
994 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
995
997 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
998
1000 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1001
1003 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1004
1006 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1007
1009 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1010
1012 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1013
1017 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1018 const auto vertex = p->end_vertex();
1019 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1020 }
1021
1023 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1024
1026 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1027 const int apid = std::abs(p->pdg_id());
1028 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1029 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1030 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1031 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1032 return false;
1033 }
1034
1036
1037 template <class T> T findMother(T thePart) {
1038 auto partOriVert = thePart->production_vertex();
1039 if (!partOriVert) return nullptr;
1040
1041 long partPDG = thePart->pdg_id();
1042 long MotherPDG(0);
1043
1044 auto MothOriVert = partOriVert;
1045 MothOriVert = nullptr;
1046 T theMoth(nullptr);
1047
1048 size_t itr = 0;
1049 do {
1050 if (itr != 0) partOriVert = MothOriVert;
1051 for ( const auto& p : particles_in(partOriVert) ) {
1052 theMoth = p;
1053 if (!theMoth) continue;
1054 MotherPDG = theMoth->pdg_id();
1055 MothOriVert = theMoth->production_vertex();
1056 if (MotherPDG == partPDG) break;
1057 }
1058 itr++;
1059 if (itr > 100) {
1060 break;
1061 }
1062 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1063 MothOriVert != partOriVert);
1064 return theMoth;
1065 }
1066
1068
1069 template <class C, class T> T findMatching(C TruthContainer, T p) {
1070 T ptrPart = nullptr;
1071 if (!p) return ptrPart;
1072 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1073 for (T truthParticle : *TruthContainer) {
1074 if (HepMC::is_sim_descendant(p,truthParticle)) {
1075 ptrPart = truthParticle;
1076 break;
1077 }
1078 }
1079 }
1080 else {
1081 for (T truthParticle : TruthContainer) {
1082 if (HepMC::is_sim_descendant(p,truthParticle)) {
1083 ptrPart = truthParticle;
1084 break;
1085 }
1086 }
1087 }
1088 return ptrPart;
1089 }
1091
1092 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1093 auto prodVtx = thePart->production_vertex();
1094 if (!prodVtx) return;
1095 for (const auto& theMother: prodVtx->particles_in()) {
1096 if (!theMother) continue;
1097 allancestors.insert(theMother);
1098 findParticleAncestors(theMother, allancestors);
1099 }
1100 }
1101
1103
1104 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1105 auto endVtx = thePart->end_vertex();
1106 if (!endVtx) return;
1107 for (const auto& theDaughter: endVtx->particles_out()) {
1108 if (!theDaughter) continue;
1109 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1110 allstabledescendants.insert(theDaughter);
1111 }
1112 findParticleStableDescendants(theDaughter, allstabledescendants);
1113 }
1114 }
1115
1119
1120 template <class T> bool isHardScatteringVertex(T pVert) {
1121 if (pVert == nullptr) return false;
1122 T pV = pVert;
1123 int numOfPartIn(0);
1124 int pdg(0);
1125
1126 do {
1127 pVert = pV;
1128 auto incoming = pVert->particles_in();
1129 numOfPartIn = incoming.size();
1130 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1131 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1132
1133 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1134
1135 if (numOfPartIn == 2) {
1136 auto incoming = pVert->particles_in();
1137 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1138 }
1139 return false;
1140}
1141
1145
1146 template <class T, class U>
1147 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1148 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1149 auto vtx = p->production_vertex();
1150 if (!vtx) return false;
1151 bool fromHad = false;
1152 for ( const auto& parent : particles_in(vtx) ) {
1153 if (!parent) continue;
1154 // should this really go into parton-level territory?
1155 // probably depends where BSM particles are being decayed
1156 fromBSM |= isBSM(parent);
1157 if (!isPhysical(parent)) return false;
1158 fromTau |= isTau(parent);
1159 if (isHadron(parent)&&!isBeam(parent)) {
1160 if (!hadron) hadron = parent; // assumes linear hadron parentage
1161 return true;
1162 }
1163 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1164 }
1165 return fromHad;
1166 }
1167
1170
1171 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1172 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1173 decltype(thePart->end_vertex()) pVert(nullptr);
1174 if (EndVert != nullptr) {
1175 do {
1176 bool samePart = false;
1177 pVert = nullptr;
1178 auto outgoing = EndVert->particles_out();
1179 auto incoming = EndVert->particles_in();
1180 for (const auto& itrDaug: outgoing) {
1181 if (!itrDaug) continue;
1182 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1183 // brem on generator level for tau
1184 (outgoing.size() == 1 && incoming.size() == 1 &&
1186 itrDaug->pdg_id() == thePart->pdg_id()) {
1187 samePart = true;
1188 pVert = itrDaug->end_vertex();
1189 }
1190 }
1191 if (samePart) EndVert = pVert;
1192 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1193 }
1194 return EndVert;
1195 }
1196
1198
1199 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1200 if (!theVert) return {};
1201 decltype(theVert->particles_out()) finalStatePart;
1202 auto outgoing = theVert->particles_out();
1203 for (const auto& thePart: outgoing) {
1204 if (!thePart) continue;
1205 finalStatePart.push_back(thePart);
1206 if (isStable(thePart)) continue;
1207 V pVert = findSimulatedEndVertex(thePart);
1208 if (pVert == theVert) break; // to prevent Sherpa loop
1209 if (pVert != nullptr) {
1210 auto vecPart = findFinalStateParticles<V>(pVert);
1211 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1212 }
1213 }
1214 return finalStatePart;
1215 }
1216
1217}
1218#endif

◆ isCharmHadron()

template<class T>
bool MC::isCharmHadron ( const T & p)
inline

Definition at line 912 of file HepMCHelpers.h.

933{
934inline
935auto particles_in (const HepMC::GenVertex* p) {
936 return std::ranges::subrange (p->particles_in_const_begin(),
937 p->particles_in_const_end());
938}
939}
940#endif
941
942namespace MC
943{
944 template <class VTX>
945 auto particles_in (const VTX* p) { return p->particles_in(); }
946 template <class VTX>
947 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
948
949 namespace Pythia8
950 {
952 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
953
954 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
955
956 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
957 }
958
959#include "AtlasPID.h"
960
962 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
963
965 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
966
968 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
969
971 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
972
974 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
975
977 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
978
980 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
981
983 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
984
986 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
987
989 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
990
994 template <class T> inline bool isStableOrSimDecayed(const T& p) {
995 const auto vertex = p->end_vertex();
996 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
997 }
998
1000 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1001
1003 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1004 const int apid = std::abs(p->pdg_id());
1005 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1006 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1007 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1008 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1009 return false;
1010 }
1011
1013
1014 template <class T> T findMother(T thePart) {
1015 auto partOriVert = thePart->production_vertex();
1016 if (!partOriVert) return nullptr;
1017
1018 long partPDG = thePart->pdg_id();
1019 long MotherPDG(0);
1020
1021 auto MothOriVert = partOriVert;
1022 MothOriVert = nullptr;
1023 T theMoth(nullptr);
1024
1025 size_t itr = 0;
1026 do {
1027 if (itr != 0) partOriVert = MothOriVert;
1028 for ( const auto& p : particles_in(partOriVert) ) {
1029 theMoth = p;
1030 if (!theMoth) continue;
1031 MotherPDG = theMoth->pdg_id();
1032 MothOriVert = theMoth->production_vertex();
1033 if (MotherPDG == partPDG) break;
1034 }
1035 itr++;
1036 if (itr > 100) {
1037 break;
1038 }
1039 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1040 MothOriVert != partOriVert);
1041 return theMoth;
1042 }
1043
1045
1046 template <class C, class T> T findMatching(C TruthContainer, T p) {
1047 T ptrPart = nullptr;
1048 if (!p) return ptrPart;
1049 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1050 for (T truthParticle : *TruthContainer) {
1051 if (HepMC::is_sim_descendant(p,truthParticle)) {
1052 ptrPart = truthParticle;
1053 break;
1054 }
1055 }
1056 }
1057 else {
1058 for (T truthParticle : TruthContainer) {
1059 if (HepMC::is_sim_descendant(p,truthParticle)) {
1060 ptrPart = truthParticle;
1061 break;
1062 }
1063 }
1064 }
1065 return ptrPart;
1066 }
1068
1069 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1070 auto prodVtx = thePart->production_vertex();
1071 if (!prodVtx) return;
1072 for (const auto& theMother: prodVtx->particles_in()) {
1073 if (!theMother) continue;
1074 allancestors.insert(theMother);
1075 findParticleAncestors(theMother, allancestors);
1076 }
1077 }
1078
1080
1081 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1082 auto endVtx = thePart->end_vertex();
1083 if (!endVtx) return;
1084 for (const auto& theDaughter: endVtx->particles_out()) {
1085 if (!theDaughter) continue;
1086 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1087 allstabledescendants.insert(theDaughter);
1088 }
1089 findParticleStableDescendants(theDaughter, allstabledescendants);
1090 }
1091 }
1092
1096
1097 template <class T> bool isHardScatteringVertex(T pVert) {
1098 if (pVert == nullptr) return false;
1099 T pV = pVert;
1100 int numOfPartIn(0);
1101 int pdg(0);
1102
1103 do {
1104 pVert = pV;
1105 auto incoming = pVert->particles_in();
1106 numOfPartIn = incoming.size();
1107 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1108 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1109
1110 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1111
1112 if (numOfPartIn == 2) {
1113 auto incoming = pVert->particles_in();
1114 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1115 }
1116 return false;
1117}
1118
1122
1123 template <class T, class U>
1124 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1125 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1126 auto vtx = p->production_vertex();
1127 if (!vtx) return false;
1128 bool fromHad = false;
1129 for ( const auto& parent : particles_in(vtx) ) {
1130 if (!parent) continue;
1131 // should this really go into parton-level territory?
1132 // probably depends where BSM particles are being decayed
1133 fromBSM |= isBSM(parent);
1134 if (!isPhysical(parent)) return false;
1135 fromTau |= isTau(parent);
1136 if (isHadron(parent)&&!isBeam(parent)) {
1137 if (!hadron) hadron = parent; // assumes linear hadron parentage
1138 return true;
1139 }
1140 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1141 }
1142 return fromHad;
1143 }
1144
1147
1148 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1149 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1150 decltype(thePart->end_vertex()) pVert(nullptr);
1151 if (EndVert != nullptr) {
1152 do {
1153 bool samePart = false;
1154 pVert = nullptr;
1155 auto outgoing = EndVert->particles_out();
1156 auto incoming = EndVert->particles_in();
1157 for (const auto& itrDaug: outgoing) {
1158 if (!itrDaug) continue;
1159 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1160 // brem on generator level for tau
1161 (outgoing.size() == 1 && incoming.size() == 1 &&
1163 itrDaug->pdg_id() == thePart->pdg_id()) {
1164 samePart = true;
1165 pVert = itrDaug->end_vertex();
1166 }
1167 }
1168 if (samePart) EndVert = pVert;
1169 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1170 }
1171 return EndVert;
1172 }
1173
1175
1176 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1177 if (!theVert) return {};
1178 decltype(theVert->particles_out()) finalStatePart;
1179 auto outgoing = theVert->particles_out();
1180 for (const auto& thePart: outgoing) {
1181 if (!thePart) continue;
1182 finalStatePart.push_back(thePart);
1183 if (isStable(thePart)) continue;
1184 V pVert = findSimulatedEndVertex(thePart);
1185 if (pVert == theVert) break; // to prevent Sherpa loop
1186 if (pVert != nullptr) {
1187 auto vecPart = findFinalStateParticles<V>(pVert);
1188 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1189 }
1190 }
1191 return finalStatePart;
1192 }
1193
1194}
1195#endif

◆ isCharmMeson()

template<class T>
bool MC::isCharmMeson ( const T & p)
inline

Definition at line 919 of file HepMCHelpers.h.

940{
941inline
942auto particles_in (const HepMC::GenVertex* p) {
943 return std::ranges::subrange (p->particles_in_const_begin(),
944 p->particles_in_const_end());
945}
946}
947#endif
948
949namespace MC
950{
951 template <class VTX>
952 auto particles_in (const VTX* p) { return p->particles_in(); }
953 template <class VTX>
954 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
955
956 namespace Pythia8
957 {
959 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
960
961 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
962
963 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
964 }
965
966#include "AtlasPID.h"
967
969 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
970
972 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
973
975 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
976
978 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
979
981 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
982
984 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
985
987 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
988
990 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
991
993 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
994
996 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
997
1001 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1002 const auto vertex = p->end_vertex();
1003 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1004 }
1005
1007 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1008
1010 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1011 const int apid = std::abs(p->pdg_id());
1012 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1013 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1014 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1015 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1016 return false;
1017 }
1018
1020
1021 template <class T> T findMother(T thePart) {
1022 auto partOriVert = thePart->production_vertex();
1023 if (!partOriVert) return nullptr;
1024
1025 long partPDG = thePart->pdg_id();
1026 long MotherPDG(0);
1027
1028 auto MothOriVert = partOriVert;
1029 MothOriVert = nullptr;
1030 T theMoth(nullptr);
1031
1032 size_t itr = 0;
1033 do {
1034 if (itr != 0) partOriVert = MothOriVert;
1035 for ( const auto& p : particles_in(partOriVert) ) {
1036 theMoth = p;
1037 if (!theMoth) continue;
1038 MotherPDG = theMoth->pdg_id();
1039 MothOriVert = theMoth->production_vertex();
1040 if (MotherPDG == partPDG) break;
1041 }
1042 itr++;
1043 if (itr > 100) {
1044 break;
1045 }
1046 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1047 MothOriVert != partOriVert);
1048 return theMoth;
1049 }
1050
1052
1053 template <class C, class T> T findMatching(C TruthContainer, T p) {
1054 T ptrPart = nullptr;
1055 if (!p) return ptrPart;
1056 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1057 for (T truthParticle : *TruthContainer) {
1058 if (HepMC::is_sim_descendant(p,truthParticle)) {
1059 ptrPart = truthParticle;
1060 break;
1061 }
1062 }
1063 }
1064 else {
1065 for (T truthParticle : TruthContainer) {
1066 if (HepMC::is_sim_descendant(p,truthParticle)) {
1067 ptrPart = truthParticle;
1068 break;
1069 }
1070 }
1071 }
1072 return ptrPart;
1073 }
1075
1076 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1077 auto prodVtx = thePart->production_vertex();
1078 if (!prodVtx) return;
1079 for (const auto& theMother: prodVtx->particles_in()) {
1080 if (!theMother) continue;
1081 allancestors.insert(theMother);
1082 findParticleAncestors(theMother, allancestors);
1083 }
1084 }
1085
1087
1088 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1089 auto endVtx = thePart->end_vertex();
1090 if (!endVtx) return;
1091 for (const auto& theDaughter: endVtx->particles_out()) {
1092 if (!theDaughter) continue;
1093 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1094 allstabledescendants.insert(theDaughter);
1095 }
1096 findParticleStableDescendants(theDaughter, allstabledescendants);
1097 }
1098 }
1099
1103
1104 template <class T> bool isHardScatteringVertex(T pVert) {
1105 if (pVert == nullptr) return false;
1106 T pV = pVert;
1107 int numOfPartIn(0);
1108 int pdg(0);
1109
1110 do {
1111 pVert = pV;
1112 auto incoming = pVert->particles_in();
1113 numOfPartIn = incoming.size();
1114 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1115 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1116
1117 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1118
1119 if (numOfPartIn == 2) {
1120 auto incoming = pVert->particles_in();
1121 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1122 }
1123 return false;
1124}
1125
1129
1130 template <class T, class U>
1131 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1132 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1133 auto vtx = p->production_vertex();
1134 if (!vtx) return false;
1135 bool fromHad = false;
1136 for ( const auto& parent : particles_in(vtx) ) {
1137 if (!parent) continue;
1138 // should this really go into parton-level territory?
1139 // probably depends where BSM particles are being decayed
1140 fromBSM |= isBSM(parent);
1141 if (!isPhysical(parent)) return false;
1142 fromTau |= isTau(parent);
1143 if (isHadron(parent)&&!isBeam(parent)) {
1144 if (!hadron) hadron = parent; // assumes linear hadron parentage
1145 return true;
1146 }
1147 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1148 }
1149 return fromHad;
1150 }
1151
1154
1155 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1156 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1157 decltype(thePart->end_vertex()) pVert(nullptr);
1158 if (EndVert != nullptr) {
1159 do {
1160 bool samePart = false;
1161 pVert = nullptr;
1162 auto outgoing = EndVert->particles_out();
1163 auto incoming = EndVert->particles_in();
1164 for (const auto& itrDaug: outgoing) {
1165 if (!itrDaug) continue;
1166 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1167 // brem on generator level for tau
1168 (outgoing.size() == 1 && incoming.size() == 1 &&
1170 itrDaug->pdg_id() == thePart->pdg_id()) {
1171 samePart = true;
1172 pVert = itrDaug->end_vertex();
1173 }
1174 }
1175 if (samePart) EndVert = pVert;
1176 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1177 }
1178 return EndVert;
1179 }
1180
1182
1183 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1184 if (!theVert) return {};
1185 decltype(theVert->particles_out()) finalStatePart;
1186 auto outgoing = theVert->particles_out();
1187 for (const auto& thePart: outgoing) {
1188 if (!thePart) continue;
1189 finalStatePart.push_back(thePart);
1190 if (isStable(thePart)) continue;
1191 V pVert = findSimulatedEndVertex(thePart);
1192 if (pVert == theVert) break; // to prevent Sherpa loop
1193 if (pVert != nullptr) {
1194 auto vecPart = findFinalStateParticles<V>(pVert);
1195 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1196 }
1197 }
1198 return finalStatePart;
1199 }
1200
1201}
1202#endif

◆ isChLepton() [1/2]

template<>
bool MC::isChLepton ( const int & p)
inline

Definition at line 201 of file HepMCHelpers.h.

201{

◆ isChLepton() [2/2]

template<class T>
bool MC::isChLepton ( const T & p)
inline

APID: the fourth generation leptons are leptons.

Definition at line 200 of file HepMCHelpers.h.

◆ isDecayed()

template<class T>
bool MC::isDecayed ( const T & p)
inline

Identify if the particle decayed.

Definition at line 60 of file HepMCHelpers.h.

◆ isDiquark() [1/3]

template<>
bool MC::isDiquark ( const DecodedPID & p)
inline

Definition at line 229 of file HepMCHelpers.h.

◆ isDiquark() [2/3]

template<>
bool MC::isDiquark ( const int & p)
inline

Definition at line 235 of file HepMCHelpers.h.

◆ isDiquark() [3/3]

template<class T>
bool MC::isDiquark ( const T & p)
inline

PDG rule 4 Diquarks have 4-digit numbers with nq1 >= nq2 and nq3 = 0 APID: states with top quarks are diquarks APID: states with fourth generation quarks are not diquarks.

Definition at line 228 of file HepMCHelpers.h.

◆ isDM() [1/2]

template<>
bool MC::isDM ( const int & p)
inline

Definition at line 660 of file HepMCHelpers.h.

681 {
682inline
683auto particles_in (const HepMC::GenVertex* p) {
684 return std::ranges::subrange (p->particles_in_const_begin(),
685 p->particles_in_const_end());
686}
687}
688#endif
689
690namespace MC
691{
692 template <class VTX>
693 auto particles_in (const VTX* p) { return p->particles_in(); }
694 template <class VTX>
695 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
696
697 namespace Pythia8
698 {
700 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
701
702 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
703
704 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
705 }
706
707#include "AtlasPID.h"
708
710 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
711
713 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
714
716 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
717
719 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
720
722 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
723
725 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
726
728 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
729
731 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
732
734 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
735
737 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
738
742 template <class T> inline bool isStableOrSimDecayed(const T& p) {
743 const auto vertex = p->end_vertex();
744 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
745 }
746
748 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
749
751 template <class T> inline bool isSpecialNonInteracting(const T& p) {
752 const int apid = std::abs(p->pdg_id());
753 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
754 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
755 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
756 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
757 return false;
758 }
759
761
762 template <class T> T findMother(T thePart) {
763 auto partOriVert = thePart->production_vertex();
764 if (!partOriVert) return nullptr;
765
766 long partPDG = thePart->pdg_id();
767 long MotherPDG(0);
768
769 auto MothOriVert = partOriVert;
770 MothOriVert = nullptr;
771 T theMoth(nullptr);
772
773 size_t itr = 0;
774 do {
775 if (itr != 0) partOriVert = MothOriVert;
776 for ( const auto& p : particles_in(partOriVert) ) {
777 theMoth = p;
778 if (!theMoth) continue;
779 MotherPDG = theMoth->pdg_id();
780 MothOriVert = theMoth->production_vertex();
781 if (MotherPDG == partPDG) break;
782 }
783 itr++;
784 if (itr > 100) {
785 break;
786 }
787 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
788 MothOriVert != partOriVert);
789 return theMoth;
790 }
791
793
794 template <class C, class T> T findMatching(C TruthContainer, T p) {
795 T ptrPart = nullptr;
796 if (!p) return ptrPart;
797 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
798 for (T truthParticle : *TruthContainer) {
799 if (HepMC::is_sim_descendant(p,truthParticle)) {
800 ptrPart = truthParticle;
801 break;
802 }
803 }
804 }
805 else {
806 for (T truthParticle : TruthContainer) {
807 if (HepMC::is_sim_descendant(p,truthParticle)) {
808 ptrPart = truthParticle;
809 break;
810 }
811 }
812 }
813 return ptrPart;
814 }
816
817 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
818 auto prodVtx = thePart->production_vertex();
819 if (!prodVtx) return;
820 for (const auto& theMother: prodVtx->particles_in()) {
821 if (!theMother) continue;
822 allancestors.insert(theMother);
823 findParticleAncestors(theMother, allancestors);
824 }
825 }
826
828
829 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
830 auto endVtx = thePart->end_vertex();
831 if (!endVtx) return;
832 for (const auto& theDaughter: endVtx->particles_out()) {
833 if (!theDaughter) continue;
834 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
835 allstabledescendants.insert(theDaughter);
836 }
837 findParticleStableDescendants(theDaughter, allstabledescendants);
838 }
839 }
840
844
845 template <class T> bool isHardScatteringVertex(T pVert) {
846 if (pVert == nullptr) return false;
847 T pV = pVert;
848 int numOfPartIn(0);
849 int pdg(0);
850
851 do {
852 pVert = pV;
853 auto incoming = pVert->particles_in();
854 numOfPartIn = incoming.size();
855 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
856 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
857
858 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
859
860 if (numOfPartIn == 2) {
861 auto incoming = pVert->particles_in();
862 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
863 }
864 return false;
865}
866
870
871 template <class T, class U>
872 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
873 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
874 auto vtx = p->production_vertex();
875 if (!vtx) return false;
876 bool fromHad = false;
877 for ( const auto& parent : particles_in(vtx) ) {
878 if (!parent) continue;
879 // should this really go into parton-level territory?
880 // probably depends where BSM particles are being decayed
881 fromBSM |= isBSM(parent);
882 if (!isPhysical(parent)) return false;
883 fromTau |= isTau(parent);
884 if (isHadron(parent)&&!isBeam(parent)) {
885 if (!hadron) hadron = parent; // assumes linear hadron parentage
886 return true;
887 }
888 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
889 }
890 return fromHad;
891 }
892
895
896 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
897 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
898 decltype(thePart->end_vertex()) pVert(nullptr);
899 if (EndVert != nullptr) {
900 do {
901 bool samePart = false;
902 pVert = nullptr;
903 auto outgoing = EndVert->particles_out();
904 auto incoming = EndVert->particles_in();
905 for (const auto& itrDaug: outgoing) {
906 if (!itrDaug) continue;
907 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
908 // brem on generator level for tau
909 (outgoing.size() == 1 && incoming.size() == 1 &&
911 itrDaug->pdg_id() == thePart->pdg_id()) {
912 samePart = true;
913 pVert = itrDaug->end_vertex();
914 }
915 }
916 if (samePart) EndVert = pVert;
917 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
918 }
919 return EndVert;
920 }
921
923
924 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
925 if (!theVert) return {};
926 decltype(theVert->particles_out()) finalStatePart;
927 auto outgoing = theVert->particles_out();
928 for (const auto& thePart: outgoing) {
929 if (!thePart) continue;
930 finalStatePart.push_back(thePart);
931 if (isStable(thePart)) continue;
932 V pVert = findSimulatedEndVertex(thePart);
933 if (pVert == theVert) break; // to prevent Sherpa loop
934 if (pVert != nullptr) {
935 auto vecPart = findFinalStateParticles<V>(pVert);
936 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
937 }
938 }
939 return finalStatePart;
940 }
941
942}
943#endif

◆ isDM() [2/2]

template<class T>
bool MC::isDM ( const T & p)
inline

PDG rule 11j: The nature of Dark Matter (DM) is not known, and therefore a definitive classificationis too early.

Candidates within specific scenarios are classified therein, such as 1000022 for the lightest neutralino. Generic fundamental states can be given temporary codes in the range 51 - 60, with 51, 52 and 53 reserved for spin 0, 1/2 and 1 ones (this could also be an axion state). Generic mediators of s-channel DM pair creation of annihilation can be given codes 54 and 55 for spin 0 or 1 ones. Separate antiparticles, with negativecodes, may or may not exist. More elaborate new scenarios should be constructed with n= 5 and nr = 9.

Definition at line 659 of file HepMCHelpers.h.

680{
681inline
682auto particles_in (const HepMC::GenVertex* p) {
683 return std::ranges::subrange (p->particles_in_const_begin(),
684 p->particles_in_const_end());
685}
686}
687#endif
688
689namespace MC
690{
691 template <class VTX>
692 auto particles_in (const VTX* p) { return p->particles_in(); }
693 template <class VTX>
694 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
695
696 namespace Pythia8
697 {
699 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
700
701 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
702
703 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
704 }
705
706#include "AtlasPID.h"
707
709 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
710
712 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
713
715 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
716
718 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
719
721 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
722
724 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
725
727 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
728
730 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
731
733 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
734
736 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
737
741 template <class T> inline bool isStableOrSimDecayed(const T& p) {
742 const auto vertex = p->end_vertex();
743 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
744 }
745
747 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
748
750 template <class T> inline bool isSpecialNonInteracting(const T& p) {
751 const int apid = std::abs(p->pdg_id());
752 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
753 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
754 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
755 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
756 return false;
757 }
758
760
761 template <class T> T findMother(T thePart) {
762 auto partOriVert = thePart->production_vertex();
763 if (!partOriVert) return nullptr;
764
765 long partPDG = thePart->pdg_id();
766 long MotherPDG(0);
767
768 auto MothOriVert = partOriVert;
769 MothOriVert = nullptr;
770 T theMoth(nullptr);
771
772 size_t itr = 0;
773 do {
774 if (itr != 0) partOriVert = MothOriVert;
775 for ( const auto& p : particles_in(partOriVert) ) {
776 theMoth = p;
777 if (!theMoth) continue;
778 MotherPDG = theMoth->pdg_id();
779 MothOriVert = theMoth->production_vertex();
780 if (MotherPDG == partPDG) break;
781 }
782 itr++;
783 if (itr > 100) {
784 break;
785 }
786 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
787 MothOriVert != partOriVert);
788 return theMoth;
789 }
790
792
793 template <class C, class T> T findMatching(C TruthContainer, T p) {
794 T ptrPart = nullptr;
795 if (!p) return ptrPart;
796 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
797 for (T truthParticle : *TruthContainer) {
798 if (HepMC::is_sim_descendant(p,truthParticle)) {
799 ptrPart = truthParticle;
800 break;
801 }
802 }
803 }
804 else {
805 for (T truthParticle : TruthContainer) {
806 if (HepMC::is_sim_descendant(p,truthParticle)) {
807 ptrPart = truthParticle;
808 break;
809 }
810 }
811 }
812 return ptrPart;
813 }
815
816 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
817 auto prodVtx = thePart->production_vertex();
818 if (!prodVtx) return;
819 for (const auto& theMother: prodVtx->particles_in()) {
820 if (!theMother) continue;
821 allancestors.insert(theMother);
822 findParticleAncestors(theMother, allancestors);
823 }
824 }
825
827
828 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
829 auto endVtx = thePart->end_vertex();
830 if (!endVtx) return;
831 for (const auto& theDaughter: endVtx->particles_out()) {
832 if (!theDaughter) continue;
833 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
834 allstabledescendants.insert(theDaughter);
835 }
836 findParticleStableDescendants(theDaughter, allstabledescendants);
837 }
838 }
839
843
844 template <class T> bool isHardScatteringVertex(T pVert) {
845 if (pVert == nullptr) return false;
846 T pV = pVert;
847 int numOfPartIn(0);
848 int pdg(0);
849
850 do {
851 pVert = pV;
852 auto incoming = pVert->particles_in();
853 numOfPartIn = incoming.size();
854 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
855 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
856
857 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
858
859 if (numOfPartIn == 2) {
860 auto incoming = pVert->particles_in();
861 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
862 }
863 return false;
864}
865
869
870 template <class T, class U>
871 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
872 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
873 auto vtx = p->production_vertex();
874 if (!vtx) return false;
875 bool fromHad = false;
876 for ( const auto& parent : particles_in(vtx) ) {
877 if (!parent) continue;
878 // should this really go into parton-level territory?
879 // probably depends where BSM particles are being decayed
880 fromBSM |= isBSM(parent);
881 if (!isPhysical(parent)) return false;
882 fromTau |= isTau(parent);
883 if (isHadron(parent)&&!isBeam(parent)) {
884 if (!hadron) hadron = parent; // assumes linear hadron parentage
885 return true;
886 }
887 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
888 }
889 return fromHad;
890 }
891
894
895 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
896 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
897 decltype(thePart->end_vertex()) pVert(nullptr);
898 if (EndVert != nullptr) {
899 do {
900 bool samePart = false;
901 pVert = nullptr;
902 auto outgoing = EndVert->particles_out();
903 auto incoming = EndVert->particles_in();
904 for (const auto& itrDaug: outgoing) {
905 if (!itrDaug) continue;
906 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
907 // brem on generator level for tau
908 (outgoing.size() == 1 && incoming.size() == 1 &&
910 itrDaug->pdg_id() == thePart->pdg_id()) {
911 samePart = true;
912 pVert = itrDaug->end_vertex();
913 }
914 }
915 if (samePart) EndVert = pVert;
916 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
917 }
918 return EndVert;
919 }
920
922
923 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
924 if (!theVert) return {};
925 decltype(theVert->particles_out()) finalStatePart;
926 auto outgoing = theVert->particles_out();
927 for (const auto& thePart: outgoing) {
928 if (!thePart) continue;
929 finalStatePart.push_back(thePart);
930 if (isStable(thePart)) continue;
931 V pVert = findSimulatedEndVertex(thePart);
932 if (pVert == theVert) break; // to prevent Sherpa loop
933 if (pVert != nullptr) {
934 auto vecPart = findFinalStateParticles<V>(pVert);
935 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
936 }
937 }
938 return finalStatePart;
939 }
940
941}
942#endif

◆ isElectron() [1/2]

template<>
bool MC::isElectron ( const int & p)
inline

Definition at line 204 of file HepMCHelpers.h.

◆ isElectron() [2/2]

template<class T>
bool MC::isElectron ( const T & p)
inline

Definition at line 203 of file HepMCHelpers.h.

◆ isEMInteracting() [1/2]

template<>
bool MC::isEMInteracting ( const int & p)
inline

Definition at line 1102 of file HepMCHelpers.h.

1123{
1124inline
1125auto particles_in (const HepMC::GenVertex* p) {
1126 return std::ranges::subrange (p->particles_in_const_begin(),
1127 p->particles_in_const_end());
1128}
1129}
1130#endif
1131
1132namespace MC
1133{
1134 template <class VTX>
1135 auto particles_in (const VTX* p) { return p->particles_in(); }
1136 template <class VTX>
1137 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1138
1139 namespace Pythia8
1140 {
1142 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1143
1144 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1145
1146 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1147 }
1148
1149#include "AtlasPID.h"
1150
1152 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1153
1155 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1156
1158 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1159
1161 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1162
1164 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1165
1167 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1168
1170 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1171
1173 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1174
1176 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1177
1179 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1180
1184 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1185 const auto vertex = p->end_vertex();
1186 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1187 }
1188
1190 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1191
1193 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1194 const int apid = std::abs(p->pdg_id());
1195 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1196 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1197 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1198 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1199 return false;
1200 }
1201
1203
1204 template <class T> T findMother(T thePart) {
1205 auto partOriVert = thePart->production_vertex();
1206 if (!partOriVert) return nullptr;
1207
1208 long partPDG = thePart->pdg_id();
1209 long MotherPDG(0);
1210
1211 auto MothOriVert = partOriVert;
1212 MothOriVert = nullptr;
1213 T theMoth(nullptr);
1214
1215 size_t itr = 0;
1216 do {
1217 if (itr != 0) partOriVert = MothOriVert;
1218 for ( const auto& p : particles_in(partOriVert) ) {
1219 theMoth = p;
1220 if (!theMoth) continue;
1221 MotherPDG = theMoth->pdg_id();
1222 MothOriVert = theMoth->production_vertex();
1223 if (MotherPDG == partPDG) break;
1224 }
1225 itr++;
1226 if (itr > 100) {
1227 break;
1228 }
1229 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1230 MothOriVert != partOriVert);
1231 return theMoth;
1232 }
1233
1235
1236 template <class C, class T> T findMatching(C TruthContainer, T p) {
1237 T ptrPart = nullptr;
1238 if (!p) return ptrPart;
1239 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1240 for (T truthParticle : *TruthContainer) {
1241 if (HepMC::is_sim_descendant(p,truthParticle)) {
1242 ptrPart = truthParticle;
1243 break;
1244 }
1245 }
1246 }
1247 else {
1248 for (T truthParticle : TruthContainer) {
1249 if (HepMC::is_sim_descendant(p,truthParticle)) {
1250 ptrPart = truthParticle;
1251 break;
1252 }
1253 }
1254 }
1255 return ptrPart;
1256 }
1258
1259 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1260 auto prodVtx = thePart->production_vertex();
1261 if (!prodVtx) return;
1262 for (const auto& theMother: prodVtx->particles_in()) {
1263 if (!theMother) continue;
1264 allancestors.insert(theMother);
1265 findParticleAncestors(theMother, allancestors);
1266 }
1267 }
1268
1270
1271 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1272 auto endVtx = thePart->end_vertex();
1273 if (!endVtx) return;
1274 for (const auto& theDaughter: endVtx->particles_out()) {
1275 if (!theDaughter) continue;
1276 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1277 allstabledescendants.insert(theDaughter);
1278 }
1279 findParticleStableDescendants(theDaughter, allstabledescendants);
1280 }
1281 }
1282
1286
1287 template <class T> bool isHardScatteringVertex(T pVert) {
1288 if (pVert == nullptr) return false;
1289 T pV = pVert;
1290 int numOfPartIn(0);
1291 int pdg(0);
1292
1293 do {
1294 pVert = pV;
1295 auto incoming = pVert->particles_in();
1296 numOfPartIn = incoming.size();
1297 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1298 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1299
1300 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1301
1302 if (numOfPartIn == 2) {
1303 auto incoming = pVert->particles_in();
1304 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1305 }
1306 return false;
1307}
1308
1312
1313 template <class T, class U>
1314 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1315 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1316 auto vtx = p->production_vertex();
1317 if (!vtx) return false;
1318 bool fromHad = false;
1319 for ( const auto& parent : particles_in(vtx) ) {
1320 if (!parent) continue;
1321 // should this really go into parton-level territory?
1322 // probably depends where BSM particles are being decayed
1323 fromBSM |= isBSM(parent);
1324 if (!isPhysical(parent)) return false;
1325 fromTau |= isTau(parent);
1326 if (isHadron(parent)&&!isBeam(parent)) {
1327 if (!hadron) hadron = parent; // assumes linear hadron parentage
1328 return true;
1329 }
1330 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1331 }
1332 return fromHad;
1333 }
1334
1337
1338 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1339 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1340 decltype(thePart->end_vertex()) pVert(nullptr);
1341 if (EndVert != nullptr) {
1342 do {
1343 bool samePart = false;
1344 pVert = nullptr;
1345 auto outgoing = EndVert->particles_out();
1346 auto incoming = EndVert->particles_in();
1347 for (const auto& itrDaug: outgoing) {
1348 if (!itrDaug) continue;
1349 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1350 // brem on generator level for tau
1351 (outgoing.size() == 1 && incoming.size() == 1 &&
1353 itrDaug->pdg_id() == thePart->pdg_id()) {
1354 samePart = true;
1355 pVert = itrDaug->end_vertex();
1356 }
1357 }
1358 if (samePart) EndVert = pVert;
1359 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1360 }
1361 return EndVert;
1362 }
1363
1365
1366 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1367 if (!theVert) return {};
1368 decltype(theVert->particles_out()) finalStatePart;
1369 auto outgoing = theVert->particles_out();
1370 for (const auto& thePart: outgoing) {
1371 if (!thePart) continue;
1372 finalStatePart.push_back(thePart);
1373 if (isStable(thePart)) continue;
1374 V pVert = findSimulatedEndVertex(thePart);
1375 if (pVert == theVert) break; // to prevent Sherpa loop
1376 if (pVert != nullptr) {
1377 auto vecPart = findFinalStateParticles<V>(pVert);
1378 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1379 }
1380 }
1381 return finalStatePart;
1382 }
1383
1384}
1385#endif

◆ isEMInteracting() [2/2]

template<class T>
bool MC::isEMInteracting ( const T & p)
inline

Definition at line 1101 of file HepMCHelpers.h.

1122{
1123inline
1124auto particles_in (const HepMC::GenVertex* p) {
1125 return std::ranges::subrange (p->particles_in_const_begin(),
1126 p->particles_in_const_end());
1127}
1128}
1129#endif
1130
1131namespace MC
1132{
1133 template <class VTX>
1134 auto particles_in (const VTX* p) { return p->particles_in(); }
1135 template <class VTX>
1136 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1137
1138 namespace Pythia8
1139 {
1141 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1142
1143 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1144
1145 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1146 }
1147
1148#include "AtlasPID.h"
1149
1151 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1152
1154 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1155
1157 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1158
1160 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1161
1163 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1164
1166 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1167
1169 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1170
1172 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1173
1175 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1176
1178 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1179
1183 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1184 const auto vertex = p->end_vertex();
1185 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1186 }
1187
1189 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1190
1192 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1193 const int apid = std::abs(p->pdg_id());
1194 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1195 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1196 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1197 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1198 return false;
1199 }
1200
1202
1203 template <class T> T findMother(T thePart) {
1204 auto partOriVert = thePart->production_vertex();
1205 if (!partOriVert) return nullptr;
1206
1207 long partPDG = thePart->pdg_id();
1208 long MotherPDG(0);
1209
1210 auto MothOriVert = partOriVert;
1211 MothOriVert = nullptr;
1212 T theMoth(nullptr);
1213
1214 size_t itr = 0;
1215 do {
1216 if (itr != 0) partOriVert = MothOriVert;
1217 for ( const auto& p : particles_in(partOriVert) ) {
1218 theMoth = p;
1219 if (!theMoth) continue;
1220 MotherPDG = theMoth->pdg_id();
1221 MothOriVert = theMoth->production_vertex();
1222 if (MotherPDG == partPDG) break;
1223 }
1224 itr++;
1225 if (itr > 100) {
1226 break;
1227 }
1228 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1229 MothOriVert != partOriVert);
1230 return theMoth;
1231 }
1232
1234
1235 template <class C, class T> T findMatching(C TruthContainer, T p) {
1236 T ptrPart = nullptr;
1237 if (!p) return ptrPart;
1238 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1239 for (T truthParticle : *TruthContainer) {
1240 if (HepMC::is_sim_descendant(p,truthParticle)) {
1241 ptrPart = truthParticle;
1242 break;
1243 }
1244 }
1245 }
1246 else {
1247 for (T truthParticle : TruthContainer) {
1248 if (HepMC::is_sim_descendant(p,truthParticle)) {
1249 ptrPart = truthParticle;
1250 break;
1251 }
1252 }
1253 }
1254 return ptrPart;
1255 }
1257
1258 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1259 auto prodVtx = thePart->production_vertex();
1260 if (!prodVtx) return;
1261 for (const auto& theMother: prodVtx->particles_in()) {
1262 if (!theMother) continue;
1263 allancestors.insert(theMother);
1264 findParticleAncestors(theMother, allancestors);
1265 }
1266 }
1267
1269
1270 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1271 auto endVtx = thePart->end_vertex();
1272 if (!endVtx) return;
1273 for (const auto& theDaughter: endVtx->particles_out()) {
1274 if (!theDaughter) continue;
1275 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1276 allstabledescendants.insert(theDaughter);
1277 }
1278 findParticleStableDescendants(theDaughter, allstabledescendants);
1279 }
1280 }
1281
1285
1286 template <class T> bool isHardScatteringVertex(T pVert) {
1287 if (pVert == nullptr) return false;
1288 T pV = pVert;
1289 int numOfPartIn(0);
1290 int pdg(0);
1291
1292 do {
1293 pVert = pV;
1294 auto incoming = pVert->particles_in();
1295 numOfPartIn = incoming.size();
1296 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1297 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1298
1299 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1300
1301 if (numOfPartIn == 2) {
1302 auto incoming = pVert->particles_in();
1303 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1304 }
1305 return false;
1306}
1307
1311
1312 template <class T, class U>
1313 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1314 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1315 auto vtx = p->production_vertex();
1316 if (!vtx) return false;
1317 bool fromHad = false;
1318 for ( const auto& parent : particles_in(vtx) ) {
1319 if (!parent) continue;
1320 // should this really go into parton-level territory?
1321 // probably depends where BSM particles are being decayed
1322 fromBSM |= isBSM(parent);
1323 if (!isPhysical(parent)) return false;
1324 fromTau |= isTau(parent);
1325 if (isHadron(parent)&&!isBeam(parent)) {
1326 if (!hadron) hadron = parent; // assumes linear hadron parentage
1327 return true;
1328 }
1329 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1330 }
1331 return fromHad;
1332 }
1333
1336
1337 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1338 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1339 decltype(thePart->end_vertex()) pVert(nullptr);
1340 if (EndVert != nullptr) {
1341 do {
1342 bool samePart = false;
1343 pVert = nullptr;
1344 auto outgoing = EndVert->particles_out();
1345 auto incoming = EndVert->particles_in();
1346 for (const auto& itrDaug: outgoing) {
1347 if (!itrDaug) continue;
1348 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1349 // brem on generator level for tau
1350 (outgoing.size() == 1 && incoming.size() == 1 &&
1352 itrDaug->pdg_id() == thePart->pdg_id()) {
1353 samePart = true;
1354 pVert = itrDaug->end_vertex();
1355 }
1356 }
1357 if (samePart) EndVert = pVert;
1358 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1359 }
1360 return EndVert;
1361 }
1362
1364
1365 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1366 if (!theVert) return {};
1367 decltype(theVert->particles_out()) finalStatePart;
1368 auto outgoing = theVert->particles_out();
1369 for (const auto& thePart: outgoing) {
1370 if (!thePart) continue;
1371 finalStatePart.push_back(thePart);
1372 if (isStable(thePart)) continue;
1373 V pVert = findSimulatedEndVertex(thePart);
1374 if (pVert == theVert) break; // to prevent Sherpa loop
1375 if (pVert != nullptr) {
1376 auto vecPart = findFinalStateParticles<V>(pVert);
1377 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1378 }
1379 }
1380 return finalStatePart;
1381 }
1382
1383}
1384#endif

◆ isExcited() [1/3]

template<>
bool MC::isExcited ( const DecodedPID & p)
inline

Definition at line 539 of file HepMCHelpers.h.

560 {
561inline
562auto particles_in (const HepMC::GenVertex* p) {
563 return std::ranges::subrange (p->particles_in_const_begin(),
564 p->particles_in_const_end());
565}
566}
567#endif
568
569namespace MC
570{
571 template <class VTX>
572 auto particles_in (const VTX* p) { return p->particles_in(); }
573 template <class VTX>
574 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
575
576 namespace Pythia8
577 {
579 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
580
581 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
582
583 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
584 }
585
586#include "AtlasPID.h"
587
589 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
590
592 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
593
595 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
596
598 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
599
601 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
602
604 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
605
607 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
608
610 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
611
613 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
614
616 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
617
621 template <class T> inline bool isStableOrSimDecayed(const T& p) {
622 const auto vertex = p->end_vertex();
623 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
624 }
625
627 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
628
630 template <class T> inline bool isSpecialNonInteracting(const T& p) {
631 const int apid = std::abs(p->pdg_id());
632 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
633 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
634 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
635 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
636 return false;
637 }
638
640
641 template <class T> T findMother(T thePart) {
642 auto partOriVert = thePart->production_vertex();
643 if (!partOriVert) return nullptr;
644
645 long partPDG = thePart->pdg_id();
646 long MotherPDG(0);
647
648 auto MothOriVert = partOriVert;
649 MothOriVert = nullptr;
650 T theMoth(nullptr);
651
652 size_t itr = 0;
653 do {
654 if (itr != 0) partOriVert = MothOriVert;
655 for ( const auto& p : particles_in(partOriVert) ) {
656 theMoth = p;
657 if (!theMoth) continue;
658 MotherPDG = theMoth->pdg_id();
659 MothOriVert = theMoth->production_vertex();
660 if (MotherPDG == partPDG) break;
661 }
662 itr++;
663 if (itr > 100) {
664 break;
665 }
666 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
667 MothOriVert != partOriVert);
668 return theMoth;
669 }
670
672
673 template <class C, class T> T findMatching(C TruthContainer, T p) {
674 T ptrPart = nullptr;
675 if (!p) return ptrPart;
676 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
677 for (T truthParticle : *TruthContainer) {
678 if (HepMC::is_sim_descendant(p,truthParticle)) {
679 ptrPart = truthParticle;
680 break;
681 }
682 }
683 }
684 else {
685 for (T truthParticle : TruthContainer) {
686 if (HepMC::is_sim_descendant(p,truthParticle)) {
687 ptrPart = truthParticle;
688 break;
689 }
690 }
691 }
692 return ptrPart;
693 }
695
696 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
697 auto prodVtx = thePart->production_vertex();
698 if (!prodVtx) return;
699 for (const auto& theMother: prodVtx->particles_in()) {
700 if (!theMother) continue;
701 allancestors.insert(theMother);
702 findParticleAncestors(theMother, allancestors);
703 }
704 }
705
707
708 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
709 auto endVtx = thePart->end_vertex();
710 if (!endVtx) return;
711 for (const auto& theDaughter: endVtx->particles_out()) {
712 if (!theDaughter) continue;
713 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
714 allstabledescendants.insert(theDaughter);
715 }
716 findParticleStableDescendants(theDaughter, allstabledescendants);
717 }
718 }
719
723
724 template <class T> bool isHardScatteringVertex(T pVert) {
725 if (pVert == nullptr) return false;
726 T pV = pVert;
727 int numOfPartIn(0);
728 int pdg(0);
729
730 do {
731 pVert = pV;
732 auto incoming = pVert->particles_in();
733 numOfPartIn = incoming.size();
734 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
735 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
736
737 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
738
739 if (numOfPartIn == 2) {
740 auto incoming = pVert->particles_in();
741 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
742 }
743 return false;
744}
745
749
750 template <class T, class U>
751 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
752 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
753 auto vtx = p->production_vertex();
754 if (!vtx) return false;
755 bool fromHad = false;
756 for ( const auto& parent : particles_in(vtx) ) {
757 if (!parent) continue;
758 // should this really go into parton-level territory?
759 // probably depends where BSM particles are being decayed
760 fromBSM |= isBSM(parent);
761 if (!isPhysical(parent)) return false;
762 fromTau |= isTau(parent);
763 if (isHadron(parent)&&!isBeam(parent)) {
764 if (!hadron) hadron = parent; // assumes linear hadron parentage
765 return true;
766 }
767 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
768 }
769 return fromHad;
770 }
771
774
775 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
776 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
777 decltype(thePart->end_vertex()) pVert(nullptr);
778 if (EndVert != nullptr) {
779 do {
780 bool samePart = false;
781 pVert = nullptr;
782 auto outgoing = EndVert->particles_out();
783 auto incoming = EndVert->particles_in();
784 for (const auto& itrDaug: outgoing) {
785 if (!itrDaug) continue;
786 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
787 // brem on generator level for tau
788 (outgoing.size() == 1 && incoming.size() == 1 &&
790 itrDaug->pdg_id() == thePart->pdg_id()) {
791 samePart = true;
792 pVert = itrDaug->end_vertex();
793 }
794 }
795 if (samePart) EndVert = pVert;
796 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
797 }
798 return EndVert;
799 }
800
802
803 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
804 if (!theVert) return {};
805 decltype(theVert->particles_out()) finalStatePart;
806 auto outgoing = theVert->particles_out();
807 for (const auto& thePart: outgoing) {
808 if (!thePart) continue;
809 finalStatePart.push_back(thePart);
810 if (isStable(thePart)) continue;
811 V pVert = findSimulatedEndVertex(thePart);
812 if (pVert == theVert) break; // to prevent Sherpa loop
813 if (pVert != nullptr) {
814 auto vecPart = findFinalStateParticles<V>(pVert);
815 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
816 }
817 }
818 return finalStatePart;
819 }
820
821}
822#endif

◆ isExcited() [2/3]

template<>
bool MC::isExcited ( const int & p)
inline

Definition at line 544 of file HepMCHelpers.h.

565{
566inline
567auto particles_in (const HepMC::GenVertex* p) {
568 return std::ranges::subrange (p->particles_in_const_begin(),
569 p->particles_in_const_end());
570}
571}
572#endif
573
574namespace MC
575{
576 template <class VTX>
577 auto particles_in (const VTX* p) { return p->particles_in(); }
578 template <class VTX>
579 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
580
581 namespace Pythia8
582 {
584 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
585
586 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
587
588 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
589 }
590
591#include "AtlasPID.h"
592
594 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
595
597 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
598
600 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
601
603 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
604
606 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
607
609 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
610
612 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
613
615 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
616
618 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
619
621 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
622
626 template <class T> inline bool isStableOrSimDecayed(const T& p) {
627 const auto vertex = p->end_vertex();
628 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
629 }
630
632 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
633
635 template <class T> inline bool isSpecialNonInteracting(const T& p) {
636 const int apid = std::abs(p->pdg_id());
637 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
638 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
639 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
640 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
641 return false;
642 }
643
645
646 template <class T> T findMother(T thePart) {
647 auto partOriVert = thePart->production_vertex();
648 if (!partOriVert) return nullptr;
649
650 long partPDG = thePart->pdg_id();
651 long MotherPDG(0);
652
653 auto MothOriVert = partOriVert;
654 MothOriVert = nullptr;
655 T theMoth(nullptr);
656
657 size_t itr = 0;
658 do {
659 if (itr != 0) partOriVert = MothOriVert;
660 for ( const auto& p : particles_in(partOriVert) ) {
661 theMoth = p;
662 if (!theMoth) continue;
663 MotherPDG = theMoth->pdg_id();
664 MothOriVert = theMoth->production_vertex();
665 if (MotherPDG == partPDG) break;
666 }
667 itr++;
668 if (itr > 100) {
669 break;
670 }
671 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
672 MothOriVert != partOriVert);
673 return theMoth;
674 }
675
677
678 template <class C, class T> T findMatching(C TruthContainer, T p) {
679 T ptrPart = nullptr;
680 if (!p) return ptrPart;
681 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
682 for (T truthParticle : *TruthContainer) {
683 if (HepMC::is_sim_descendant(p,truthParticle)) {
684 ptrPart = truthParticle;
685 break;
686 }
687 }
688 }
689 else {
690 for (T truthParticle : TruthContainer) {
691 if (HepMC::is_sim_descendant(p,truthParticle)) {
692 ptrPart = truthParticle;
693 break;
694 }
695 }
696 }
697 return ptrPart;
698 }
700
701 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
702 auto prodVtx = thePart->production_vertex();
703 if (!prodVtx) return;
704 for (const auto& theMother: prodVtx->particles_in()) {
705 if (!theMother) continue;
706 allancestors.insert(theMother);
707 findParticleAncestors(theMother, allancestors);
708 }
709 }
710
712
713 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
714 auto endVtx = thePart->end_vertex();
715 if (!endVtx) return;
716 for (const auto& theDaughter: endVtx->particles_out()) {
717 if (!theDaughter) continue;
718 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
719 allstabledescendants.insert(theDaughter);
720 }
721 findParticleStableDescendants(theDaughter, allstabledescendants);
722 }
723 }
724
728
729 template <class T> bool isHardScatteringVertex(T pVert) {
730 if (pVert == nullptr) return false;
731 T pV = pVert;
732 int numOfPartIn(0);
733 int pdg(0);
734
735 do {
736 pVert = pV;
737 auto incoming = pVert->particles_in();
738 numOfPartIn = incoming.size();
739 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
740 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
741
742 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
743
744 if (numOfPartIn == 2) {
745 auto incoming = pVert->particles_in();
746 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
747 }
748 return false;
749}
750
754
755 template <class T, class U>
756 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
757 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
758 auto vtx = p->production_vertex();
759 if (!vtx) return false;
760 bool fromHad = false;
761 for ( const auto& parent : particles_in(vtx) ) {
762 if (!parent) continue;
763 // should this really go into parton-level territory?
764 // probably depends where BSM particles are being decayed
765 fromBSM |= isBSM(parent);
766 if (!isPhysical(parent)) return false;
767 fromTau |= isTau(parent);
768 if (isHadron(parent)&&!isBeam(parent)) {
769 if (!hadron) hadron = parent; // assumes linear hadron parentage
770 return true;
771 }
772 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
773 }
774 return fromHad;
775 }
776
779
780 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
781 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
782 decltype(thePart->end_vertex()) pVert(nullptr);
783 if (EndVert != nullptr) {
784 do {
785 bool samePart = false;
786 pVert = nullptr;
787 auto outgoing = EndVert->particles_out();
788 auto incoming = EndVert->particles_in();
789 for (const auto& itrDaug: outgoing) {
790 if (!itrDaug) continue;
791 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
792 // brem on generator level for tau
793 (outgoing.size() == 1 && incoming.size() == 1 &&
795 itrDaug->pdg_id() == thePart->pdg_id()) {
796 samePart = true;
797 pVert = itrDaug->end_vertex();
798 }
799 }
800 if (samePart) EndVert = pVert;
801 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
802 }
803 return EndVert;
804 }
805
807
808 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
809 if (!theVert) return {};
810 decltype(theVert->particles_out()) finalStatePart;
811 auto outgoing = theVert->particles_out();
812 for (const auto& thePart: outgoing) {
813 if (!thePart) continue;
814 finalStatePart.push_back(thePart);
815 if (isStable(thePart)) continue;
816 V pVert = findSimulatedEndVertex(thePart);
817 if (pVert == theVert) break; // to prevent Sherpa loop
818 if (pVert != nullptr) {
819 auto vecPart = findFinalStateParticles<V>(pVert);
820 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
821 }
822 }
823 return finalStatePart;
824 }
825
826}
827#endif

◆ isExcited() [3/3]

template<class T>
bool MC::isExcited ( const T & p)
inline

PDG rule 11f Excited (composite) quarks and leptons are identified by setting n= 4 and nr= 0.

Definition at line 537 of file HepMCHelpers.h.

558{
559inline
560auto particles_in (const HepMC::GenVertex* p) {
561 return std::ranges::subrange (p->particles_in_const_begin(),
562 p->particles_in_const_end());
563}
564}
565#endif
566
567namespace MC
568{
569 template <class VTX>
570 auto particles_in (const VTX* p) { return p->particles_in(); }
571 template <class VTX>
572 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
573
574 namespace Pythia8
575 {
577 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
578
579 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
580
581 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
582 }
583
584#include "AtlasPID.h"
585
587 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
588
590 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
591
593 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
594
596 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
597
599 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
600
602 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
603
605 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
606
608 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
609
611 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
612
614 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
615
619 template <class T> inline bool isStableOrSimDecayed(const T& p) {
620 const auto vertex = p->end_vertex();
621 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
622 }
623
625 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
626
628 template <class T> inline bool isSpecialNonInteracting(const T& p) {
629 const int apid = std::abs(p->pdg_id());
630 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
631 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
632 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
633 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
634 return false;
635 }
636
638
639 template <class T> T findMother(T thePart) {
640 auto partOriVert = thePart->production_vertex();
641 if (!partOriVert) return nullptr;
642
643 long partPDG = thePart->pdg_id();
644 long MotherPDG(0);
645
646 auto MothOriVert = partOriVert;
647 MothOriVert = nullptr;
648 T theMoth(nullptr);
649
650 size_t itr = 0;
651 do {
652 if (itr != 0) partOriVert = MothOriVert;
653 for ( const auto& p : particles_in(partOriVert) ) {
654 theMoth = p;
655 if (!theMoth) continue;
656 MotherPDG = theMoth->pdg_id();
657 MothOriVert = theMoth->production_vertex();
658 if (MotherPDG == partPDG) break;
659 }
660 itr++;
661 if (itr > 100) {
662 break;
663 }
664 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
665 MothOriVert != partOriVert);
666 return theMoth;
667 }
668
670
671 template <class C, class T> T findMatching(C TruthContainer, T p) {
672 T ptrPart = nullptr;
673 if (!p) return ptrPart;
674 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
675 for (T truthParticle : *TruthContainer) {
676 if (HepMC::is_sim_descendant(p,truthParticle)) {
677 ptrPart = truthParticle;
678 break;
679 }
680 }
681 }
682 else {
683 for (T truthParticle : TruthContainer) {
684 if (HepMC::is_sim_descendant(p,truthParticle)) {
685 ptrPart = truthParticle;
686 break;
687 }
688 }
689 }
690 return ptrPart;
691 }
693
694 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
695 auto prodVtx = thePart->production_vertex();
696 if (!prodVtx) return;
697 for (const auto& theMother: prodVtx->particles_in()) {
698 if (!theMother) continue;
699 allancestors.insert(theMother);
700 findParticleAncestors(theMother, allancestors);
701 }
702 }
703
705
706 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
707 auto endVtx = thePart->end_vertex();
708 if (!endVtx) return;
709 for (const auto& theDaughter: endVtx->particles_out()) {
710 if (!theDaughter) continue;
711 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
712 allstabledescendants.insert(theDaughter);
713 }
714 findParticleStableDescendants(theDaughter, allstabledescendants);
715 }
716 }
717
721
722 template <class T> bool isHardScatteringVertex(T pVert) {
723 if (pVert == nullptr) return false;
724 T pV = pVert;
725 int numOfPartIn(0);
726 int pdg(0);
727
728 do {
729 pVert = pV;
730 auto incoming = pVert->particles_in();
731 numOfPartIn = incoming.size();
732 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
733 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
734
735 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
736
737 if (numOfPartIn == 2) {
738 auto incoming = pVert->particles_in();
739 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
740 }
741 return false;
742}
743
747
748 template <class T, class U>
749 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
750 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
751 auto vtx = p->production_vertex();
752 if (!vtx) return false;
753 bool fromHad = false;
754 for ( const auto& parent : particles_in(vtx) ) {
755 if (!parent) continue;
756 // should this really go into parton-level territory?
757 // probably depends where BSM particles are being decayed
758 fromBSM |= isBSM(parent);
759 if (!isPhysical(parent)) return false;
760 fromTau |= isTau(parent);
761 if (isHadron(parent)&&!isBeam(parent)) {
762 if (!hadron) hadron = parent; // assumes linear hadron parentage
763 return true;
764 }
765 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
766 }
767 return fromHad;
768 }
769
772
773 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
774 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
775 decltype(thePart->end_vertex()) pVert(nullptr);
776 if (EndVert != nullptr) {
777 do {
778 bool samePart = false;
779 pVert = nullptr;
780 auto outgoing = EndVert->particles_out();
781 auto incoming = EndVert->particles_in();
782 for (const auto& itrDaug: outgoing) {
783 if (!itrDaug) continue;
784 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
785 // brem on generator level for tau
786 (outgoing.size() == 1 && incoming.size() == 1 &&
788 itrDaug->pdg_id() == thePart->pdg_id()) {
789 samePart = true;
790 pVert = itrDaug->end_vertex();
791 }
792 }
793 if (samePart) EndVert = pVert;
794 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
795 }
796 return EndVert;
797 }
798
800
801 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
802 if (!theVert) return {};
803 decltype(theVert->particles_out()) finalStatePart;
804 auto outgoing = theVert->particles_out();
805 for (const auto& thePart: outgoing) {
806 if (!thePart) continue;
807 finalStatePart.push_back(thePart);
808 if (isStable(thePart)) continue;
809 V pVert = findSimulatedEndVertex(thePart);
810 if (pVert == theVert) break; // to prevent Sherpa loop
811 if (pVert != nullptr) {
812 auto vecPart = findFinalStateParticles<V>(pVert);
813 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
814 }
815 }
816 return finalStatePart;
817 }
818
819}
820#endif

◆ isFinalState()

template<class T>
bool MC::isFinalState ( const T & p)
inline

Identify if the particle is final state particle.

Definition at line 66 of file HepMCHelpers.h.

66{ return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}

◆ isFourthGeneration() [1/2]

template<>
bool MC::isFourthGeneration ( const int & p)
inline

Definition at line 222 of file HepMCHelpers.h.

◆ isFourthGeneration() [2/2]

template<class T>
bool MC::isFourthGeneration ( const T & p)
inline

Is this a 4th generation fermion?

APID: 4th generation fermions are not standard model particles

Definition at line 221 of file HepMCHelpers.h.

◆ isFromHadron()

template<class T, class U>
bool MC::isFromHadron ( T p,
U hadron,
bool & fromTau,
bool & fromBSM )

Function to classify the particle.

AV: This is MCtruthClassifier legacy. The function should be improved in the future. This can be used for HepMC3::GenVertexPtr, HepMC3::ConstGenVertexPtr or xAOD::TruthVertex*

Definition at line 213 of file HepMCHelpers.h.

213 {
214 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
215 auto vtx = p->production_vertex();
216 if (!vtx) return false;
217 bool fromHad = false;
218 for ( const auto& parent : particles_in(vtx) ) {
219 if (!parent) continue;
220 // should this really go into parton-level territory?
221 // probably depends where BSM particles are being decayed
222 fromBSM |= isBSM(parent);
223 if (!isPhysical(parent)) return false;
224 fromTau |= isTau(parent);
225 if (isHadron(parent)&&!isBeam(parent)) {
226 if (!hadron) hadron = parent; // assumes linear hadron parentage
227 return true;
228 }
229 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
230 }
231 return fromHad;
232 }

◆ isGaugino() [1/3]

template<>
bool MC::isGaugino ( const DecodedPID & p)
inline

Definition at line 506 of file HepMCHelpers.h.

527 {
528inline
529auto particles_in (const HepMC::GenVertex* p) {
530 return std::ranges::subrange (p->particles_in_const_begin(),
531 p->particles_in_const_end());
532}
533}
534#endif
535
536namespace MC
537{
538 template <class VTX>
539 auto particles_in (const VTX* p) { return p->particles_in(); }
540 template <class VTX>
541 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
542
543 namespace Pythia8
544 {
546 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
547
548 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
549
550 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
551 }
552
553#include "AtlasPID.h"
554
556 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
557
559 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
560
562 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
563
565 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
566
568 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
569
571 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
572
574 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
575
577 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
578
580 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
581
583 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
584
588 template <class T> inline bool isStableOrSimDecayed(const T& p) {
589 const auto vertex = p->end_vertex();
590 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
591 }
592
594 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
595
597 template <class T> inline bool isSpecialNonInteracting(const T& p) {
598 const int apid = std::abs(p->pdg_id());
599 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
600 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
601 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
602 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
603 return false;
604 }
605
607
608 template <class T> T findMother(T thePart) {
609 auto partOriVert = thePart->production_vertex();
610 if (!partOriVert) return nullptr;
611
612 long partPDG = thePart->pdg_id();
613 long MotherPDG(0);
614
615 auto MothOriVert = partOriVert;
616 MothOriVert = nullptr;
617 T theMoth(nullptr);
618
619 size_t itr = 0;
620 do {
621 if (itr != 0) partOriVert = MothOriVert;
622 for ( const auto& p : particles_in(partOriVert) ) {
623 theMoth = p;
624 if (!theMoth) continue;
625 MotherPDG = theMoth->pdg_id();
626 MothOriVert = theMoth->production_vertex();
627 if (MotherPDG == partPDG) break;
628 }
629 itr++;
630 if (itr > 100) {
631 break;
632 }
633 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
634 MothOriVert != partOriVert);
635 return theMoth;
636 }
637
639
640 template <class C, class T> T findMatching(C TruthContainer, T p) {
641 T ptrPart = nullptr;
642 if (!p) return ptrPart;
643 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
644 for (T truthParticle : *TruthContainer) {
645 if (HepMC::is_sim_descendant(p,truthParticle)) {
646 ptrPart = truthParticle;
647 break;
648 }
649 }
650 }
651 else {
652 for (T truthParticle : TruthContainer) {
653 if (HepMC::is_sim_descendant(p,truthParticle)) {
654 ptrPart = truthParticle;
655 break;
656 }
657 }
658 }
659 return ptrPart;
660 }
662
663 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
664 auto prodVtx = thePart->production_vertex();
665 if (!prodVtx) return;
666 for (const auto& theMother: prodVtx->particles_in()) {
667 if (!theMother) continue;
668 allancestors.insert(theMother);
669 findParticleAncestors(theMother, allancestors);
670 }
671 }
672
674
675 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
676 auto endVtx = thePart->end_vertex();
677 if (!endVtx) return;
678 for (const auto& theDaughter: endVtx->particles_out()) {
679 if (!theDaughter) continue;
680 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
681 allstabledescendants.insert(theDaughter);
682 }
683 findParticleStableDescendants(theDaughter, allstabledescendants);
684 }
685 }
686
690
691 template <class T> bool isHardScatteringVertex(T pVert) {
692 if (pVert == nullptr) return false;
693 T pV = pVert;
694 int numOfPartIn(0);
695 int pdg(0);
696
697 do {
698 pVert = pV;
699 auto incoming = pVert->particles_in();
700 numOfPartIn = incoming.size();
701 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
702 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
703
704 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
705
706 if (numOfPartIn == 2) {
707 auto incoming = pVert->particles_in();
708 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
709 }
710 return false;
711}
712
716
717 template <class T, class U>
718 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
719 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
720 auto vtx = p->production_vertex();
721 if (!vtx) return false;
722 bool fromHad = false;
723 for ( const auto& parent : particles_in(vtx) ) {
724 if (!parent) continue;
725 // should this really go into parton-level territory?
726 // probably depends where BSM particles are being decayed
727 fromBSM |= isBSM(parent);
728 if (!isPhysical(parent)) return false;
729 fromTau |= isTau(parent);
730 if (isHadron(parent)&&!isBeam(parent)) {
731 if (!hadron) hadron = parent; // assumes linear hadron parentage
732 return true;
733 }
734 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
735 }
736 return fromHad;
737 }
738
741
742 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
743 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
744 decltype(thePart->end_vertex()) pVert(nullptr);
745 if (EndVert != nullptr) {
746 do {
747 bool samePart = false;
748 pVert = nullptr;
749 auto outgoing = EndVert->particles_out();
750 auto incoming = EndVert->particles_in();
751 for (const auto& itrDaug: outgoing) {
752 if (!itrDaug) continue;
753 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
754 // brem on generator level for tau
755 (outgoing.size() == 1 && incoming.size() == 1 &&
757 itrDaug->pdg_id() == thePart->pdg_id()) {
758 samePart = true;
759 pVert = itrDaug->end_vertex();
760 }
761 }
762 if (samePart) EndVert = pVert;
763 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
764 }
765 return EndVert;
766 }
767
769
770 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
771 if (!theVert) return {};
772 decltype(theVert->particles_out()) finalStatePart;
773 auto outgoing = theVert->particles_out();
774 for (const auto& thePart: outgoing) {
775 if (!thePart) continue;
776 finalStatePart.push_back(thePart);
777 if (isStable(thePart)) continue;
778 V pVert = findSimulatedEndVertex(thePart);
779 if (pVert == theVert) break; // to prevent Sherpa loop
780 if (pVert != nullptr) {
781 auto vecPart = findFinalStateParticles<V>(pVert);
782 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
783 }
784 }
785 return finalStatePart;
786 }
787
788}
789#endif

◆ isGaugino() [2/3]

template<>
bool MC::isGaugino ( const int & p)
inline

Definition at line 509 of file HepMCHelpers.h.

530{
531inline
532auto particles_in (const HepMC::GenVertex* p) {
533 return std::ranges::subrange (p->particles_in_const_begin(),
534 p->particles_in_const_end());
535}
536}
537#endif
538
539namespace MC
540{
541 template <class VTX>
542 auto particles_in (const VTX* p) { return p->particles_in(); }
543 template <class VTX>
544 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
545
546 namespace Pythia8
547 {
549 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
550
551 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
552
553 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
554 }
555
556#include "AtlasPID.h"
557
559 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
560
562 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
563
565 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
566
568 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
569
571 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
572
574 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
575
577 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
578
580 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
581
583 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
584
586 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
587
591 template <class T> inline bool isStableOrSimDecayed(const T& p) {
592 const auto vertex = p->end_vertex();
593 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
594 }
595
597 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
598
600 template <class T> inline bool isSpecialNonInteracting(const T& p) {
601 const int apid = std::abs(p->pdg_id());
602 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
603 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
604 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
605 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
606 return false;
607 }
608
610
611 template <class T> T findMother(T thePart) {
612 auto partOriVert = thePart->production_vertex();
613 if (!partOriVert) return nullptr;
614
615 long partPDG = thePart->pdg_id();
616 long MotherPDG(0);
617
618 auto MothOriVert = partOriVert;
619 MothOriVert = nullptr;
620 T theMoth(nullptr);
621
622 size_t itr = 0;
623 do {
624 if (itr != 0) partOriVert = MothOriVert;
625 for ( const auto& p : particles_in(partOriVert) ) {
626 theMoth = p;
627 if (!theMoth) continue;
628 MotherPDG = theMoth->pdg_id();
629 MothOriVert = theMoth->production_vertex();
630 if (MotherPDG == partPDG) break;
631 }
632 itr++;
633 if (itr > 100) {
634 break;
635 }
636 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
637 MothOriVert != partOriVert);
638 return theMoth;
639 }
640
642
643 template <class C, class T> T findMatching(C TruthContainer, T p) {
644 T ptrPart = nullptr;
645 if (!p) return ptrPart;
646 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
647 for (T truthParticle : *TruthContainer) {
648 if (HepMC::is_sim_descendant(p,truthParticle)) {
649 ptrPart = truthParticle;
650 break;
651 }
652 }
653 }
654 else {
655 for (T truthParticle : TruthContainer) {
656 if (HepMC::is_sim_descendant(p,truthParticle)) {
657 ptrPart = truthParticle;
658 break;
659 }
660 }
661 }
662 return ptrPart;
663 }
665
666 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
667 auto prodVtx = thePart->production_vertex();
668 if (!prodVtx) return;
669 for (const auto& theMother: prodVtx->particles_in()) {
670 if (!theMother) continue;
671 allancestors.insert(theMother);
672 findParticleAncestors(theMother, allancestors);
673 }
674 }
675
677
678 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
679 auto endVtx = thePart->end_vertex();
680 if (!endVtx) return;
681 for (const auto& theDaughter: endVtx->particles_out()) {
682 if (!theDaughter) continue;
683 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
684 allstabledescendants.insert(theDaughter);
685 }
686 findParticleStableDescendants(theDaughter, allstabledescendants);
687 }
688 }
689
693
694 template <class T> bool isHardScatteringVertex(T pVert) {
695 if (pVert == nullptr) return false;
696 T pV = pVert;
697 int numOfPartIn(0);
698 int pdg(0);
699
700 do {
701 pVert = pV;
702 auto incoming = pVert->particles_in();
703 numOfPartIn = incoming.size();
704 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
705 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
706
707 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
708
709 if (numOfPartIn == 2) {
710 auto incoming = pVert->particles_in();
711 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
712 }
713 return false;
714}
715
719
720 template <class T, class U>
721 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
722 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
723 auto vtx = p->production_vertex();
724 if (!vtx) return false;
725 bool fromHad = false;
726 for ( const auto& parent : particles_in(vtx) ) {
727 if (!parent) continue;
728 // should this really go into parton-level territory?
729 // probably depends where BSM particles are being decayed
730 fromBSM |= isBSM(parent);
731 if (!isPhysical(parent)) return false;
732 fromTau |= isTau(parent);
733 if (isHadron(parent)&&!isBeam(parent)) {
734 if (!hadron) hadron = parent; // assumes linear hadron parentage
735 return true;
736 }
737 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
738 }
739 return fromHad;
740 }
741
744
745 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
746 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
747 decltype(thePart->end_vertex()) pVert(nullptr);
748 if (EndVert != nullptr) {
749 do {
750 bool samePart = false;
751 pVert = nullptr;
752 auto outgoing = EndVert->particles_out();
753 auto incoming = EndVert->particles_in();
754 for (const auto& itrDaug: outgoing) {
755 if (!itrDaug) continue;
756 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
757 // brem on generator level for tau
758 (outgoing.size() == 1 && incoming.size() == 1 &&
760 itrDaug->pdg_id() == thePart->pdg_id()) {
761 samePart = true;
762 pVert = itrDaug->end_vertex();
763 }
764 }
765 if (samePart) EndVert = pVert;
766 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
767 }
768 return EndVert;
769 }
770
772
773 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
774 if (!theVert) return {};
775 decltype(theVert->particles_out()) finalStatePart;
776 auto outgoing = theVert->particles_out();
777 for (const auto& thePart: outgoing) {
778 if (!thePart) continue;
779 finalStatePart.push_back(thePart);
780 if (isStable(thePart)) continue;
781 V pVert = findSimulatedEndVertex(thePart);
782 if (pVert == theVert) break; // to prevent Sherpa loop
783 if (pVert != nullptr) {
784 auto vecPart = findFinalStateParticles<V>(pVert);
785 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
786 }
787 }
788 return finalStatePart;
789 }
790
791}
792#endif

◆ isGaugino() [3/3]

template<class T>
bool MC::isGaugino ( const T & p)
inline

Definition at line 505 of file HepMCHelpers.h.

526{
527inline
528auto particles_in (const HepMC::GenVertex* p) {
529 return std::ranges::subrange (p->particles_in_const_begin(),
530 p->particles_in_const_end());
531}
532}
533#endif
534
535namespace MC
536{
537 template <class VTX>
538 auto particles_in (const VTX* p) { return p->particles_in(); }
539 template <class VTX>
540 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
541
542 namespace Pythia8
543 {
545 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
546
547 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
548
549 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
550 }
551
552#include "AtlasPID.h"
553
555 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
556
558 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
559
561 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
562
564 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
565
567 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
568
570 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
571
573 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
574
576 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
577
579 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
580
582 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
583
587 template <class T> inline bool isStableOrSimDecayed(const T& p) {
588 const auto vertex = p->end_vertex();
589 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
590 }
591
593 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
594
596 template <class T> inline bool isSpecialNonInteracting(const T& p) {
597 const int apid = std::abs(p->pdg_id());
598 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
599 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
600 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
601 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
602 return false;
603 }
604
606
607 template <class T> T findMother(T thePart) {
608 auto partOriVert = thePart->production_vertex();
609 if (!partOriVert) return nullptr;
610
611 long partPDG = thePart->pdg_id();
612 long MotherPDG(0);
613
614 auto MothOriVert = partOriVert;
615 MothOriVert = nullptr;
616 T theMoth(nullptr);
617
618 size_t itr = 0;
619 do {
620 if (itr != 0) partOriVert = MothOriVert;
621 for ( const auto& p : particles_in(partOriVert) ) {
622 theMoth = p;
623 if (!theMoth) continue;
624 MotherPDG = theMoth->pdg_id();
625 MothOriVert = theMoth->production_vertex();
626 if (MotherPDG == partPDG) break;
627 }
628 itr++;
629 if (itr > 100) {
630 break;
631 }
632 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
633 MothOriVert != partOriVert);
634 return theMoth;
635 }
636
638
639 template <class C, class T> T findMatching(C TruthContainer, T p) {
640 T ptrPart = nullptr;
641 if (!p) return ptrPart;
642 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
643 for (T truthParticle : *TruthContainer) {
644 if (HepMC::is_sim_descendant(p,truthParticle)) {
645 ptrPart = truthParticle;
646 break;
647 }
648 }
649 }
650 else {
651 for (T truthParticle : TruthContainer) {
652 if (HepMC::is_sim_descendant(p,truthParticle)) {
653 ptrPart = truthParticle;
654 break;
655 }
656 }
657 }
658 return ptrPart;
659 }
661
662 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
663 auto prodVtx = thePart->production_vertex();
664 if (!prodVtx) return;
665 for (const auto& theMother: prodVtx->particles_in()) {
666 if (!theMother) continue;
667 allancestors.insert(theMother);
668 findParticleAncestors(theMother, allancestors);
669 }
670 }
671
673
674 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
675 auto endVtx = thePart->end_vertex();
676 if (!endVtx) return;
677 for (const auto& theDaughter: endVtx->particles_out()) {
678 if (!theDaughter) continue;
679 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
680 allstabledescendants.insert(theDaughter);
681 }
682 findParticleStableDescendants(theDaughter, allstabledescendants);
683 }
684 }
685
689
690 template <class T> bool isHardScatteringVertex(T pVert) {
691 if (pVert == nullptr) return false;
692 T pV = pVert;
693 int numOfPartIn(0);
694 int pdg(0);
695
696 do {
697 pVert = pV;
698 auto incoming = pVert->particles_in();
699 numOfPartIn = incoming.size();
700 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
701 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
702
703 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
704
705 if (numOfPartIn == 2) {
706 auto incoming = pVert->particles_in();
707 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
708 }
709 return false;
710}
711
715
716 template <class T, class U>
717 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
718 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
719 auto vtx = p->production_vertex();
720 if (!vtx) return false;
721 bool fromHad = false;
722 for ( const auto& parent : particles_in(vtx) ) {
723 if (!parent) continue;
724 // should this really go into parton-level territory?
725 // probably depends where BSM particles are being decayed
726 fromBSM |= isBSM(parent);
727 if (!isPhysical(parent)) return false;
728 fromTau |= isTau(parent);
729 if (isHadron(parent)&&!isBeam(parent)) {
730 if (!hadron) hadron = parent; // assumes linear hadron parentage
731 return true;
732 }
733 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
734 }
735 return fromHad;
736 }
737
740
741 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
742 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
743 decltype(thePart->end_vertex()) pVert(nullptr);
744 if (EndVert != nullptr) {
745 do {
746 bool samePart = false;
747 pVert = nullptr;
748 auto outgoing = EndVert->particles_out();
749 auto incoming = EndVert->particles_in();
750 for (const auto& itrDaug: outgoing) {
751 if (!itrDaug) continue;
752 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
753 // brem on generator level for tau
754 (outgoing.size() == 1 && incoming.size() == 1 &&
756 itrDaug->pdg_id() == thePart->pdg_id()) {
757 samePart = true;
758 pVert = itrDaug->end_vertex();
759 }
760 }
761 if (samePart) EndVert = pVert;
762 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
763 }
764 return EndVert;
765 }
766
768
769 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
770 if (!theVert) return {};
771 decltype(theVert->particles_out()) finalStatePart;
772 auto outgoing = theVert->particles_out();
773 for (const auto& thePart: outgoing) {
774 if (!thePart) continue;
775 finalStatePart.push_back(thePart);
776 if (isStable(thePart)) continue;
777 V pVert = findSimulatedEndVertex(thePart);
778 if (pVert == theVert) break; // to prevent Sherpa loop
779 if (pVert != nullptr) {
780 auto vecPart = findFinalStateParticles<V>(pVert);
781 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
782 }
783 }
784 return finalStatePart;
785 }
786
787}
788#endif

◆ isGeantino() [1/2]

template<>
bool MC::isGeantino ( const int & p)
inline

Definition at line 439 of file HepMCHelpers.h.

460{
461inline
462auto particles_in (const HepMC::GenVertex* p) {
463 return std::ranges::subrange (p->particles_in_const_begin(),
464 p->particles_in_const_end());
465}
466}
467#endif
468
469namespace MC
470{
471 template <class VTX>
472 auto particles_in (const VTX* p) { return p->particles_in(); }
473 template <class VTX>
474 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
475
476 namespace Pythia8
477 {
479 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
480
481 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
482
483 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
484 }
485
486#include "AtlasPID.h"
487
489 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
490
492 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
493
495 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
496
498 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
499
501 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
502
504 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
505
507 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
508
510 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
511
513 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
514
516 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
517
521 template <class T> inline bool isStableOrSimDecayed(const T& p) {
522 const auto vertex = p->end_vertex();
523 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
524 }
525
527 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
528
530 template <class T> inline bool isSpecialNonInteracting(const T& p) {
531 const int apid = std::abs(p->pdg_id());
532 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
533 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
534 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
535 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
536 return false;
537 }
538
540
541 template <class T> T findMother(T thePart) {
542 auto partOriVert = thePart->production_vertex();
543 if (!partOriVert) return nullptr;
544
545 long partPDG = thePart->pdg_id();
546 long MotherPDG(0);
547
548 auto MothOriVert = partOriVert;
549 MothOriVert = nullptr;
550 T theMoth(nullptr);
551
552 size_t itr = 0;
553 do {
554 if (itr != 0) partOriVert = MothOriVert;
555 for ( const auto& p : particles_in(partOriVert) ) {
556 theMoth = p;
557 if (!theMoth) continue;
558 MotherPDG = theMoth->pdg_id();
559 MothOriVert = theMoth->production_vertex();
560 if (MotherPDG == partPDG) break;
561 }
562 itr++;
563 if (itr > 100) {
564 break;
565 }
566 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
567 MothOriVert != partOriVert);
568 return theMoth;
569 }
570
572
573 template <class C, class T> T findMatching(C TruthContainer, T p) {
574 T ptrPart = nullptr;
575 if (!p) return ptrPart;
576 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
577 for (T truthParticle : *TruthContainer) {
578 if (HepMC::is_sim_descendant(p,truthParticle)) {
579 ptrPart = truthParticle;
580 break;
581 }
582 }
583 }
584 else {
585 for (T truthParticle : TruthContainer) {
586 if (HepMC::is_sim_descendant(p,truthParticle)) {
587 ptrPart = truthParticle;
588 break;
589 }
590 }
591 }
592 return ptrPart;
593 }
595
596 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
597 auto prodVtx = thePart->production_vertex();
598 if (!prodVtx) return;
599 for (const auto& theMother: prodVtx->particles_in()) {
600 if (!theMother) continue;
601 allancestors.insert(theMother);
602 findParticleAncestors(theMother, allancestors);
603 }
604 }
605
607
608 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
609 auto endVtx = thePart->end_vertex();
610 if (!endVtx) return;
611 for (const auto& theDaughter: endVtx->particles_out()) {
612 if (!theDaughter) continue;
613 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
614 allstabledescendants.insert(theDaughter);
615 }
616 findParticleStableDescendants(theDaughter, allstabledescendants);
617 }
618 }
619
623
624 template <class T> bool isHardScatteringVertex(T pVert) {
625 if (pVert == nullptr) return false;
626 T pV = pVert;
627 int numOfPartIn(0);
628 int pdg(0);
629
630 do {
631 pVert = pV;
632 auto incoming = pVert->particles_in();
633 numOfPartIn = incoming.size();
634 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
635 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
636
637 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
638
639 if (numOfPartIn == 2) {
640 auto incoming = pVert->particles_in();
641 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
642 }
643 return false;
644}
645
649
650 template <class T, class U>
651 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
652 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
653 auto vtx = p->production_vertex();
654 if (!vtx) return false;
655 bool fromHad = false;
656 for ( const auto& parent : particles_in(vtx) ) {
657 if (!parent) continue;
658 // should this really go into parton-level territory?
659 // probably depends where BSM particles are being decayed
660 fromBSM |= isBSM(parent);
661 if (!isPhysical(parent)) return false;
662 fromTau |= isTau(parent);
663 if (isHadron(parent)&&!isBeam(parent)) {
664 if (!hadron) hadron = parent; // assumes linear hadron parentage
665 return true;
666 }
667 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
668 }
669 return fromHad;
670 }
671
674
675 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
676 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
677 decltype(thePart->end_vertex()) pVert(nullptr);
678 if (EndVert != nullptr) {
679 do {
680 bool samePart = false;
681 pVert = nullptr;
682 auto outgoing = EndVert->particles_out();
683 auto incoming = EndVert->particles_in();
684 for (const auto& itrDaug: outgoing) {
685 if (!itrDaug) continue;
686 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
687 // brem on generator level for tau
688 (outgoing.size() == 1 && incoming.size() == 1 &&
690 itrDaug->pdg_id() == thePart->pdg_id()) {
691 samePart = true;
692 pVert = itrDaug->end_vertex();
693 }
694 }
695 if (samePart) EndVert = pVert;
696 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
697 }
698 return EndVert;
699 }
700
702
703 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
704 if (!theVert) return {};
705 decltype(theVert->particles_out()) finalStatePart;
706 auto outgoing = theVert->particles_out();
707 for (const auto& thePart: outgoing) {
708 if (!thePart) continue;
709 finalStatePart.push_back(thePart);
710 if (isStable(thePart)) continue;
711 V pVert = findSimulatedEndVertex(thePart);
712 if (pVert == theVert) break; // to prevent Sherpa loop
713 if (pVert != nullptr) {
714 auto vecPart = findFinalStateParticles<V>(pVert);
715 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
716 }
717 }
718 return finalStatePart;
719 }
720
721}
722#endif

◆ isGeantino() [2/2]

template<class T>
bool MC::isGeantino ( const T & p)
inline

Definition at line 438 of file HepMCHelpers.h.

459{
460inline
461auto particles_in (const HepMC::GenVertex* p) {
462 return std::ranges::subrange (p->particles_in_const_begin(),
463 p->particles_in_const_end());
464}
465}
466#endif
467
468namespace MC
469{
470 template <class VTX>
471 auto particles_in (const VTX* p) { return p->particles_in(); }
472 template <class VTX>
473 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
474
475 namespace Pythia8
476 {
478 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
479
480 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
481
482 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
483 }
484
485#include "AtlasPID.h"
486
488 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
489
491 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
492
494 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
495
497 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
498
500 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
501
503 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
504
506 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
507
509 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
510
512 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
513
515 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
516
520 template <class T> inline bool isStableOrSimDecayed(const T& p) {
521 const auto vertex = p->end_vertex();
522 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
523 }
524
526 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
527
529 template <class T> inline bool isSpecialNonInteracting(const T& p) {
530 const int apid = std::abs(p->pdg_id());
531 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
532 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
533 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
534 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
535 return false;
536 }
537
539
540 template <class T> T findMother(T thePart) {
541 auto partOriVert = thePart->production_vertex();
542 if (!partOriVert) return nullptr;
543
544 long partPDG = thePart->pdg_id();
545 long MotherPDG(0);
546
547 auto MothOriVert = partOriVert;
548 MothOriVert = nullptr;
549 T theMoth(nullptr);
550
551 size_t itr = 0;
552 do {
553 if (itr != 0) partOriVert = MothOriVert;
554 for ( const auto& p : particles_in(partOriVert) ) {
555 theMoth = p;
556 if (!theMoth) continue;
557 MotherPDG = theMoth->pdg_id();
558 MothOriVert = theMoth->production_vertex();
559 if (MotherPDG == partPDG) break;
560 }
561 itr++;
562 if (itr > 100) {
563 break;
564 }
565 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
566 MothOriVert != partOriVert);
567 return theMoth;
568 }
569
571
572 template <class C, class T> T findMatching(C TruthContainer, T p) {
573 T ptrPart = nullptr;
574 if (!p) return ptrPart;
575 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
576 for (T truthParticle : *TruthContainer) {
577 if (HepMC::is_sim_descendant(p,truthParticle)) {
578 ptrPart = truthParticle;
579 break;
580 }
581 }
582 }
583 else {
584 for (T truthParticle : TruthContainer) {
585 if (HepMC::is_sim_descendant(p,truthParticle)) {
586 ptrPart = truthParticle;
587 break;
588 }
589 }
590 }
591 return ptrPart;
592 }
594
595 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
596 auto prodVtx = thePart->production_vertex();
597 if (!prodVtx) return;
598 for (const auto& theMother: prodVtx->particles_in()) {
599 if (!theMother) continue;
600 allancestors.insert(theMother);
601 findParticleAncestors(theMother, allancestors);
602 }
603 }
604
606
607 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
608 auto endVtx = thePart->end_vertex();
609 if (!endVtx) return;
610 for (const auto& theDaughter: endVtx->particles_out()) {
611 if (!theDaughter) continue;
612 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
613 allstabledescendants.insert(theDaughter);
614 }
615 findParticleStableDescendants(theDaughter, allstabledescendants);
616 }
617 }
618
622
623 template <class T> bool isHardScatteringVertex(T pVert) {
624 if (pVert == nullptr) return false;
625 T pV = pVert;
626 int numOfPartIn(0);
627 int pdg(0);
628
629 do {
630 pVert = pV;
631 auto incoming = pVert->particles_in();
632 numOfPartIn = incoming.size();
633 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
634 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
635
636 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
637
638 if (numOfPartIn == 2) {
639 auto incoming = pVert->particles_in();
640 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
641 }
642 return false;
643}
644
648
649 template <class T, class U>
650 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
651 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
652 auto vtx = p->production_vertex();
653 if (!vtx) return false;
654 bool fromHad = false;
655 for ( const auto& parent : particles_in(vtx) ) {
656 if (!parent) continue;
657 // should this really go into parton-level territory?
658 // probably depends where BSM particles are being decayed
659 fromBSM |= isBSM(parent);
660 if (!isPhysical(parent)) return false;
661 fromTau |= isTau(parent);
662 if (isHadron(parent)&&!isBeam(parent)) {
663 if (!hadron) hadron = parent; // assumes linear hadron parentage
664 return true;
665 }
666 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
667 }
668 return fromHad;
669 }
670
673
674 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
675 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
676 decltype(thePart->end_vertex()) pVert(nullptr);
677 if (EndVert != nullptr) {
678 do {
679 bool samePart = false;
680 pVert = nullptr;
681 auto outgoing = EndVert->particles_out();
682 auto incoming = EndVert->particles_in();
683 for (const auto& itrDaug: outgoing) {
684 if (!itrDaug) continue;
685 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
686 // brem on generator level for tau
687 (outgoing.size() == 1 && incoming.size() == 1 &&
689 itrDaug->pdg_id() == thePart->pdg_id()) {
690 samePart = true;
691 pVert = itrDaug->end_vertex();
692 }
693 }
694 if (samePart) EndVert = pVert;
695 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
696 }
697 return EndVert;
698 }
699
701
702 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
703 if (!theVert) return {};
704 decltype(theVert->particles_out()) finalStatePart;
705 auto outgoing = theVert->particles_out();
706 for (const auto& thePart: outgoing) {
707 if (!thePart) continue;
708 finalStatePart.push_back(thePart);
709 if (isStable(thePart)) continue;
710 V pVert = findSimulatedEndVertex(thePart);
711 if (pVert == theVert) break; // to prevent Sherpa loop
712 if (pVert != nullptr) {
713 auto vecPart = findFinalStateParticles<V>(pVert);
714 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
715 }
716 }
717 return finalStatePart;
718 }
719
720}
721#endif

◆ isGenericMultichargedParticle() [1/3]

template<>
bool MC::isGenericMultichargedParticle ( const DecodedPID & p)
inline

Definition at line 686 of file HepMCHelpers.h.

707{
708inline
709auto particles_in (const HepMC::GenVertex* p) {
710 return std::ranges::subrange (p->particles_in_const_begin(),
711 p->particles_in_const_end());
712}
713}
714#endif
715
716namespace MC
717{
718 template <class VTX>
719 auto particles_in (const VTX* p) { return p->particles_in(); }
720 template <class VTX>
721 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
722
723 namespace Pythia8
724 {
726 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
727
728 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
729
730 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
731 }
732
733#include "AtlasPID.h"
734
736 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
737
739 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
740
742 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
743
745 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
746
748 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
749
751 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
752
754 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
755
757 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
758
760 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
761
763 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
764
768 template <class T> inline bool isStableOrSimDecayed(const T& p) {
769 const auto vertex = p->end_vertex();
770 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
771 }
772
774 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
775
777 template <class T> inline bool isSpecialNonInteracting(const T& p) {
778 const int apid = std::abs(p->pdg_id());
779 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
780 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
781 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
782 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
783 return false;
784 }
785
787
788 template <class T> T findMother(T thePart) {
789 auto partOriVert = thePart->production_vertex();
790 if (!partOriVert) return nullptr;
791
792 long partPDG = thePart->pdg_id();
793 long MotherPDG(0);
794
795 auto MothOriVert = partOriVert;
796 MothOriVert = nullptr;
797 T theMoth(nullptr);
798
799 size_t itr = 0;
800 do {
801 if (itr != 0) partOriVert = MothOriVert;
802 for ( const auto& p : particles_in(partOriVert) ) {
803 theMoth = p;
804 if (!theMoth) continue;
805 MotherPDG = theMoth->pdg_id();
806 MothOriVert = theMoth->production_vertex();
807 if (MotherPDG == partPDG) break;
808 }
809 itr++;
810 if (itr > 100) {
811 break;
812 }
813 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
814 MothOriVert != partOriVert);
815 return theMoth;
816 }
817
819
820 template <class C, class T> T findMatching(C TruthContainer, T p) {
821 T ptrPart = nullptr;
822 if (!p) return ptrPart;
823 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
824 for (T truthParticle : *TruthContainer) {
825 if (HepMC::is_sim_descendant(p,truthParticle)) {
826 ptrPart = truthParticle;
827 break;
828 }
829 }
830 }
831 else {
832 for (T truthParticle : TruthContainer) {
833 if (HepMC::is_sim_descendant(p,truthParticle)) {
834 ptrPart = truthParticle;
835 break;
836 }
837 }
838 }
839 return ptrPart;
840 }
842
843 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
844 auto prodVtx = thePart->production_vertex();
845 if (!prodVtx) return;
846 for (const auto& theMother: prodVtx->particles_in()) {
847 if (!theMother) continue;
848 allancestors.insert(theMother);
849 findParticleAncestors(theMother, allancestors);
850 }
851 }
852
854
855 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
856 auto endVtx = thePart->end_vertex();
857 if (!endVtx) return;
858 for (const auto& theDaughter: endVtx->particles_out()) {
859 if (!theDaughter) continue;
860 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
861 allstabledescendants.insert(theDaughter);
862 }
863 findParticleStableDescendants(theDaughter, allstabledescendants);
864 }
865 }
866
870
871 template <class T> bool isHardScatteringVertex(T pVert) {
872 if (pVert == nullptr) return false;
873 T pV = pVert;
874 int numOfPartIn(0);
875 int pdg(0);
876
877 do {
878 pVert = pV;
879 auto incoming = pVert->particles_in();
880 numOfPartIn = incoming.size();
881 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
882 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
883
884 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
885
886 if (numOfPartIn == 2) {
887 auto incoming = pVert->particles_in();
888 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
889 }
890 return false;
891}
892
896
897 template <class T, class U>
898 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
899 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
900 auto vtx = p->production_vertex();
901 if (!vtx) return false;
902 bool fromHad = false;
903 for ( const auto& parent : particles_in(vtx) ) {
904 if (!parent) continue;
905 // should this really go into parton-level territory?
906 // probably depends where BSM particles are being decayed
907 fromBSM |= isBSM(parent);
908 if (!isPhysical(parent)) return false;
909 fromTau |= isTau(parent);
910 if (isHadron(parent)&&!isBeam(parent)) {
911 if (!hadron) hadron = parent; // assumes linear hadron parentage
912 return true;
913 }
914 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
915 }
916 return fromHad;
917 }
918
921
922 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
923 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
924 decltype(thePart->end_vertex()) pVert(nullptr);
925 if (EndVert != nullptr) {
926 do {
927 bool samePart = false;
928 pVert = nullptr;
929 auto outgoing = EndVert->particles_out();
930 auto incoming = EndVert->particles_in();
931 for (const auto& itrDaug: outgoing) {
932 if (!itrDaug) continue;
933 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
934 // brem on generator level for tau
935 (outgoing.size() == 1 && incoming.size() == 1 &&
937 itrDaug->pdg_id() == thePart->pdg_id()) {
938 samePart = true;
939 pVert = itrDaug->end_vertex();
940 }
941 }
942 if (samePart) EndVert = pVert;
943 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
944 }
945 return EndVert;
946 }
947
949
950 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
951 if (!theVert) return {};
952 decltype(theVert->particles_out()) finalStatePart;
953 auto outgoing = theVert->particles_out();
954 for (const auto& thePart: outgoing) {
955 if (!thePart) continue;
956 finalStatePart.push_back(thePart);
957 if (isStable(thePart)) continue;
958 V pVert = findSimulatedEndVertex(thePart);
959 if (pVert == theVert) break; // to prevent Sherpa loop
960 if (pVert != nullptr) {
961 auto vecPart = findFinalStateParticles<V>(pVert);
962 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
963 }
964 }
965 return finalStatePart;
966 }
967
968}
969#endif

◆ isGenericMultichargedParticle() [2/3]

template<>
bool MC::isGenericMultichargedParticle ( const int & p)
inline

Definition at line 687 of file HepMCHelpers.h.

708{
709inline
710auto particles_in (const HepMC::GenVertex* p) {
711 return std::ranges::subrange (p->particles_in_const_begin(),
712 p->particles_in_const_end());
713}
714}
715#endif
716
717namespace MC
718{
719 template <class VTX>
720 auto particles_in (const VTX* p) { return p->particles_in(); }
721 template <class VTX>
722 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
723
724 namespace Pythia8
725 {
727 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
728
729 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
730
731 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
732 }
733
734#include "AtlasPID.h"
735
737 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
738
740 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
741
743 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
744
746 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
747
749 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
750
752 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
753
755 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
756
758 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
759
761 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
762
764 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
765
769 template <class T> inline bool isStableOrSimDecayed(const T& p) {
770 const auto vertex = p->end_vertex();
771 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
772 }
773
775 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
776
778 template <class T> inline bool isSpecialNonInteracting(const T& p) {
779 const int apid = std::abs(p->pdg_id());
780 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
781 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
782 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
783 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
784 return false;
785 }
786
788
789 template <class T> T findMother(T thePart) {
790 auto partOriVert = thePart->production_vertex();
791 if (!partOriVert) return nullptr;
792
793 long partPDG = thePart->pdg_id();
794 long MotherPDG(0);
795
796 auto MothOriVert = partOriVert;
797 MothOriVert = nullptr;
798 T theMoth(nullptr);
799
800 size_t itr = 0;
801 do {
802 if (itr != 0) partOriVert = MothOriVert;
803 for ( const auto& p : particles_in(partOriVert) ) {
804 theMoth = p;
805 if (!theMoth) continue;
806 MotherPDG = theMoth->pdg_id();
807 MothOriVert = theMoth->production_vertex();
808 if (MotherPDG == partPDG) break;
809 }
810 itr++;
811 if (itr > 100) {
812 break;
813 }
814 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
815 MothOriVert != partOriVert);
816 return theMoth;
817 }
818
820
821 template <class C, class T> T findMatching(C TruthContainer, T p) {
822 T ptrPart = nullptr;
823 if (!p) return ptrPart;
824 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
825 for (T truthParticle : *TruthContainer) {
826 if (HepMC::is_sim_descendant(p,truthParticle)) {
827 ptrPart = truthParticle;
828 break;
829 }
830 }
831 }
832 else {
833 for (T truthParticle : TruthContainer) {
834 if (HepMC::is_sim_descendant(p,truthParticle)) {
835 ptrPart = truthParticle;
836 break;
837 }
838 }
839 }
840 return ptrPart;
841 }
843
844 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
845 auto prodVtx = thePart->production_vertex();
846 if (!prodVtx) return;
847 for (const auto& theMother: prodVtx->particles_in()) {
848 if (!theMother) continue;
849 allancestors.insert(theMother);
850 findParticleAncestors(theMother, allancestors);
851 }
852 }
853
855
856 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
857 auto endVtx = thePart->end_vertex();
858 if (!endVtx) return;
859 for (const auto& theDaughter: endVtx->particles_out()) {
860 if (!theDaughter) continue;
861 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
862 allstabledescendants.insert(theDaughter);
863 }
864 findParticleStableDescendants(theDaughter, allstabledescendants);
865 }
866 }
867
871
872 template <class T> bool isHardScatteringVertex(T pVert) {
873 if (pVert == nullptr) return false;
874 T pV = pVert;
875 int numOfPartIn(0);
876 int pdg(0);
877
878 do {
879 pVert = pV;
880 auto incoming = pVert->particles_in();
881 numOfPartIn = incoming.size();
882 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
883 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
884
885 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
886
887 if (numOfPartIn == 2) {
888 auto incoming = pVert->particles_in();
889 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
890 }
891 return false;
892}
893
897
898 template <class T, class U>
899 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
900 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
901 auto vtx = p->production_vertex();
902 if (!vtx) return false;
903 bool fromHad = false;
904 for ( const auto& parent : particles_in(vtx) ) {
905 if (!parent) continue;
906 // should this really go into parton-level territory?
907 // probably depends where BSM particles are being decayed
908 fromBSM |= isBSM(parent);
909 if (!isPhysical(parent)) return false;
910 fromTau |= isTau(parent);
911 if (isHadron(parent)&&!isBeam(parent)) {
912 if (!hadron) hadron = parent; // assumes linear hadron parentage
913 return true;
914 }
915 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
916 }
917 return fromHad;
918 }
919
922
923 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
924 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
925 decltype(thePart->end_vertex()) pVert(nullptr);
926 if (EndVert != nullptr) {
927 do {
928 bool samePart = false;
929 pVert = nullptr;
930 auto outgoing = EndVert->particles_out();
931 auto incoming = EndVert->particles_in();
932 for (const auto& itrDaug: outgoing) {
933 if (!itrDaug) continue;
934 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
935 // brem on generator level for tau
936 (outgoing.size() == 1 && incoming.size() == 1 &&
938 itrDaug->pdg_id() == thePart->pdg_id()) {
939 samePart = true;
940 pVert = itrDaug->end_vertex();
941 }
942 }
943 if (samePart) EndVert = pVert;
944 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
945 }
946 return EndVert;
947 }
948
950
951 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
952 if (!theVert) return {};
953 decltype(theVert->particles_out()) finalStatePart;
954 auto outgoing = theVert->particles_out();
955 for (const auto& thePart: outgoing) {
956 if (!thePart) continue;
957 finalStatePart.push_back(thePart);
958 if (isStable(thePart)) continue;
959 V pVert = findSimulatedEndVertex(thePart);
960 if (pVert == theVert) break; // to prevent Sherpa loop
961 if (pVert != nullptr) {
962 auto vecPart = findFinalStateParticles<V>(pVert);
963 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
964 }
965 }
966 return finalStatePart;
967 }
968
969}
970#endif

◆ isGenericMultichargedParticle() [3/3]

template<class T>
bool MC::isGenericMultichargedParticle ( const T & p)
inline

In addition, there is a need to identify ”Q-ball” and similar very exotic (multi-charged) particles which may have large, non-integer charge.

These particles are assigned the ad-hoc numbering +/-100XXXY0, where the charge is XXX.Y. or +/-200XXYY0, where the charge is XX/YY. The case of +/-200XXYY0 is legacy, see https://gitlab.cern.ch/atlas/athena/-/merge_requests/25862 Note that no other quantum numbers besides the charge are considered for these generic multi-charged particles (e.g. isSUSY() is false for them). Such a model was used in previous Run-1 (1301.5272,1504.04188) and Run-2 (1812.03673,2303.13613) ATLAS searches.

Definition at line 685 of file HepMCHelpers.h.

706{
707inline
708auto particles_in (const HepMC::GenVertex* p) {
709 return std::ranges::subrange (p->particles_in_const_begin(),
710 p->particles_in_const_end());
711}
712}
713#endif
714
715namespace MC
716{
717 template <class VTX>
718 auto particles_in (const VTX* p) { return p->particles_in(); }
719 template <class VTX>
720 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
721
722 namespace Pythia8
723 {
725 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
726
727 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
728
729 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
730 }
731
732#include "AtlasPID.h"
733
735 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
736
738 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
739
741 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
742
744 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
745
747 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
748
750 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
751
753 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
754
756 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
757
759 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
760
762 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
763
767 template <class T> inline bool isStableOrSimDecayed(const T& p) {
768 const auto vertex = p->end_vertex();
769 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
770 }
771
773 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
774
776 template <class T> inline bool isSpecialNonInteracting(const T& p) {
777 const int apid = std::abs(p->pdg_id());
778 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
779 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
780 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
781 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
782 return false;
783 }
784
786
787 template <class T> T findMother(T thePart) {
788 auto partOriVert = thePart->production_vertex();
789 if (!partOriVert) return nullptr;
790
791 long partPDG = thePart->pdg_id();
792 long MotherPDG(0);
793
794 auto MothOriVert = partOriVert;
795 MothOriVert = nullptr;
796 T theMoth(nullptr);
797
798 size_t itr = 0;
799 do {
800 if (itr != 0) partOriVert = MothOriVert;
801 for ( const auto& p : particles_in(partOriVert) ) {
802 theMoth = p;
803 if (!theMoth) continue;
804 MotherPDG = theMoth->pdg_id();
805 MothOriVert = theMoth->production_vertex();
806 if (MotherPDG == partPDG) break;
807 }
808 itr++;
809 if (itr > 100) {
810 break;
811 }
812 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
813 MothOriVert != partOriVert);
814 return theMoth;
815 }
816
818
819 template <class C, class T> T findMatching(C TruthContainer, T p) {
820 T ptrPart = nullptr;
821 if (!p) return ptrPart;
822 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
823 for (T truthParticle : *TruthContainer) {
824 if (HepMC::is_sim_descendant(p,truthParticle)) {
825 ptrPart = truthParticle;
826 break;
827 }
828 }
829 }
830 else {
831 for (T truthParticle : TruthContainer) {
832 if (HepMC::is_sim_descendant(p,truthParticle)) {
833 ptrPart = truthParticle;
834 break;
835 }
836 }
837 }
838 return ptrPart;
839 }
841
842 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
843 auto prodVtx = thePart->production_vertex();
844 if (!prodVtx) return;
845 for (const auto& theMother: prodVtx->particles_in()) {
846 if (!theMother) continue;
847 allancestors.insert(theMother);
848 findParticleAncestors(theMother, allancestors);
849 }
850 }
851
853
854 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
855 auto endVtx = thePart->end_vertex();
856 if (!endVtx) return;
857 for (const auto& theDaughter: endVtx->particles_out()) {
858 if (!theDaughter) continue;
859 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
860 allstabledescendants.insert(theDaughter);
861 }
862 findParticleStableDescendants(theDaughter, allstabledescendants);
863 }
864 }
865
869
870 template <class T> bool isHardScatteringVertex(T pVert) {
871 if (pVert == nullptr) return false;
872 T pV = pVert;
873 int numOfPartIn(0);
874 int pdg(0);
875
876 do {
877 pVert = pV;
878 auto incoming = pVert->particles_in();
879 numOfPartIn = incoming.size();
880 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
881 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
882
883 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
884
885 if (numOfPartIn == 2) {
886 auto incoming = pVert->particles_in();
887 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
888 }
889 return false;
890}
891
895
896 template <class T, class U>
897 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
898 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
899 auto vtx = p->production_vertex();
900 if (!vtx) return false;
901 bool fromHad = false;
902 for ( const auto& parent : particles_in(vtx) ) {
903 if (!parent) continue;
904 // should this really go into parton-level territory?
905 // probably depends where BSM particles are being decayed
906 fromBSM |= isBSM(parent);
907 if (!isPhysical(parent)) return false;
908 fromTau |= isTau(parent);
909 if (isHadron(parent)&&!isBeam(parent)) {
910 if (!hadron) hadron = parent; // assumes linear hadron parentage
911 return true;
912 }
913 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
914 }
915 return fromHad;
916 }
917
920
921 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
922 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
923 decltype(thePart->end_vertex()) pVert(nullptr);
924 if (EndVert != nullptr) {
925 do {
926 bool samePart = false;
927 pVert = nullptr;
928 auto outgoing = EndVert->particles_out();
929 auto incoming = EndVert->particles_in();
930 for (const auto& itrDaug: outgoing) {
931 if (!itrDaug) continue;
932 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
933 // brem on generator level for tau
934 (outgoing.size() == 1 && incoming.size() == 1 &&
936 itrDaug->pdg_id() == thePart->pdg_id()) {
937 samePart = true;
938 pVert = itrDaug->end_vertex();
939 }
940 }
941 if (samePart) EndVert = pVert;
942 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
943 }
944 return EndVert;
945 }
946
948
949 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
950 if (!theVert) return {};
951 decltype(theVert->particles_out()) finalStatePart;
952 auto outgoing = theVert->particles_out();
953 for (const auto& thePart: outgoing) {
954 if (!thePart) continue;
955 finalStatePart.push_back(thePart);
956 if (isStable(thePart)) continue;
957 V pVert = findSimulatedEndVertex(thePart);
958 if (pVert == theVert) break; // to prevent Sherpa loop
959 if (pVert != nullptr) {
960 auto vecPart = findFinalStateParticles<V>(pVert);
961 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
962 }
963 }
964 return finalStatePart;
965 }
966
967}
968#endif

◆ isGenSpecific() [1/2]

template<>
bool MC::isGenSpecific ( const int & p)
inline

Definition at line 427 of file HepMCHelpers.h.

448 {
449inline
450auto particles_in (const HepMC::GenVertex* p) {
451 return std::ranges::subrange (p->particles_in_const_begin(),
452 p->particles_in_const_end());
453}
454}
455#endif
456
457namespace MC
458{
459 template <class VTX>
460 auto particles_in (const VTX* p) { return p->particles_in(); }
461 template <class VTX>
462 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
463
464 namespace Pythia8
465 {
467 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
468
469 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
470
471 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
472 }
473
474#include "AtlasPID.h"
475
477 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
478
480 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
481
483 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
484
486 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
487
489 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
490
492 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
493
495 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
496
498 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
499
501 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
502
504 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
505
509 template <class T> inline bool isStableOrSimDecayed(const T& p) {
510 const auto vertex = p->end_vertex();
511 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
512 }
513
515 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
516
518 template <class T> inline bool isSpecialNonInteracting(const T& p) {
519 const int apid = std::abs(p->pdg_id());
520 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
521 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
522 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
523 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
524 return false;
525 }
526
528
529 template <class T> T findMother(T thePart) {
530 auto partOriVert = thePart->production_vertex();
531 if (!partOriVert) return nullptr;
532
533 long partPDG = thePart->pdg_id();
534 long MotherPDG(0);
535
536 auto MothOriVert = partOriVert;
537 MothOriVert = nullptr;
538 T theMoth(nullptr);
539
540 size_t itr = 0;
541 do {
542 if (itr != 0) partOriVert = MothOriVert;
543 for ( const auto& p : particles_in(partOriVert) ) {
544 theMoth = p;
545 if (!theMoth) continue;
546 MotherPDG = theMoth->pdg_id();
547 MothOriVert = theMoth->production_vertex();
548 if (MotherPDG == partPDG) break;
549 }
550 itr++;
551 if (itr > 100) {
552 break;
553 }
554 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
555 MothOriVert != partOriVert);
556 return theMoth;
557 }
558
560
561 template <class C, class T> T findMatching(C TruthContainer, T p) {
562 T ptrPart = nullptr;
563 if (!p) return ptrPart;
564 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
565 for (T truthParticle : *TruthContainer) {
566 if (HepMC::is_sim_descendant(p,truthParticle)) {
567 ptrPart = truthParticle;
568 break;
569 }
570 }
571 }
572 else {
573 for (T truthParticle : TruthContainer) {
574 if (HepMC::is_sim_descendant(p,truthParticle)) {
575 ptrPart = truthParticle;
576 break;
577 }
578 }
579 }
580 return ptrPart;
581 }
583
584 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
585 auto prodVtx = thePart->production_vertex();
586 if (!prodVtx) return;
587 for (const auto& theMother: prodVtx->particles_in()) {
588 if (!theMother) continue;
589 allancestors.insert(theMother);
590 findParticleAncestors(theMother, allancestors);
591 }
592 }
593
595
596 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
597 auto endVtx = thePart->end_vertex();
598 if (!endVtx) return;
599 for (const auto& theDaughter: endVtx->particles_out()) {
600 if (!theDaughter) continue;
601 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
602 allstabledescendants.insert(theDaughter);
603 }
604 findParticleStableDescendants(theDaughter, allstabledescendants);
605 }
606 }
607
611
612 template <class T> bool isHardScatteringVertex(T pVert) {
613 if (pVert == nullptr) return false;
614 T pV = pVert;
615 int numOfPartIn(0);
616 int pdg(0);
617
618 do {
619 pVert = pV;
620 auto incoming = pVert->particles_in();
621 numOfPartIn = incoming.size();
622 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
623 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
624
625 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
626
627 if (numOfPartIn == 2) {
628 auto incoming = pVert->particles_in();
629 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
630 }
631 return false;
632}
633
637
638 template <class T, class U>
639 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
640 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
641 auto vtx = p->production_vertex();
642 if (!vtx) return false;
643 bool fromHad = false;
644 for ( const auto& parent : particles_in(vtx) ) {
645 if (!parent) continue;
646 // should this really go into parton-level territory?
647 // probably depends where BSM particles are being decayed
648 fromBSM |= isBSM(parent);
649 if (!isPhysical(parent)) return false;
650 fromTau |= isTau(parent);
651 if (isHadron(parent)&&!isBeam(parent)) {
652 if (!hadron) hadron = parent; // assumes linear hadron parentage
653 return true;
654 }
655 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
656 }
657 return fromHad;
658 }
659
662
663 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
664 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
665 decltype(thePart->end_vertex()) pVert(nullptr);
666 if (EndVert != nullptr) {
667 do {
668 bool samePart = false;
669 pVert = nullptr;
670 auto outgoing = EndVert->particles_out();
671 auto incoming = EndVert->particles_in();
672 for (const auto& itrDaug: outgoing) {
673 if (!itrDaug) continue;
674 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
675 // brem on generator level for tau
676 (outgoing.size() == 1 && incoming.size() == 1 &&
678 itrDaug->pdg_id() == thePart->pdg_id()) {
679 samePart = true;
680 pVert = itrDaug->end_vertex();
681 }
682 }
683 if (samePart) EndVert = pVert;
684 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
685 }
686 return EndVert;
687 }
688
690
691 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
692 if (!theVert) return {};
693 decltype(theVert->particles_out()) finalStatePart;
694 auto outgoing = theVert->particles_out();
695 for (const auto& thePart: outgoing) {
696 if (!thePart) continue;
697 finalStatePart.push_back(thePart);
698 if (isStable(thePart)) continue;
699 V pVert = findSimulatedEndVertex(thePart);
700 if (pVert == theVert) break; // to prevent Sherpa loop
701 if (pVert != nullptr) {
702 auto vecPart = findFinalStateParticles<V>(pVert);
703 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
704 }
705 }
706 return finalStatePart;
707 }
708
709}
710#endif

◆ isGenSpecific() [2/2]

template<class T>
bool MC::isGenSpecific ( const T & p)
inline

Main Table for MC internal use 81–100,901–930,998-999,1901–1930,2901–2930, and 3901–3930.

Definition at line 426 of file HepMCHelpers.h.

447{
448inline
449auto particles_in (const HepMC::GenVertex* p) {
450 return std::ranges::subrange (p->particles_in_const_begin(),
451 p->particles_in_const_end());
452}
453}
454#endif
455
456namespace MC
457{
458 template <class VTX>
459 auto particles_in (const VTX* p) { return p->particles_in(); }
460 template <class VTX>
461 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
462
463 namespace Pythia8
464 {
466 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
467
468 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
469
470 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
471 }
472
473#include "AtlasPID.h"
474
476 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
477
479 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
480
482 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
483
485 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
486
488 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
489
491 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
492
494 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
495
497 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
498
500 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
501
503 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
504
508 template <class T> inline bool isStableOrSimDecayed(const T& p) {
509 const auto vertex = p->end_vertex();
510 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
511 }
512
514 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
515
517 template <class T> inline bool isSpecialNonInteracting(const T& p) {
518 const int apid = std::abs(p->pdg_id());
519 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
520 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
521 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
522 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
523 return false;
524 }
525
527
528 template <class T> T findMother(T thePart) {
529 auto partOriVert = thePart->production_vertex();
530 if (!partOriVert) return nullptr;
531
532 long partPDG = thePart->pdg_id();
533 long MotherPDG(0);
534
535 auto MothOriVert = partOriVert;
536 MothOriVert = nullptr;
537 T theMoth(nullptr);
538
539 size_t itr = 0;
540 do {
541 if (itr != 0) partOriVert = MothOriVert;
542 for ( const auto& p : particles_in(partOriVert) ) {
543 theMoth = p;
544 if (!theMoth) continue;
545 MotherPDG = theMoth->pdg_id();
546 MothOriVert = theMoth->production_vertex();
547 if (MotherPDG == partPDG) break;
548 }
549 itr++;
550 if (itr > 100) {
551 break;
552 }
553 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
554 MothOriVert != partOriVert);
555 return theMoth;
556 }
557
559
560 template <class C, class T> T findMatching(C TruthContainer, T p) {
561 T ptrPart = nullptr;
562 if (!p) return ptrPart;
563 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
564 for (T truthParticle : *TruthContainer) {
565 if (HepMC::is_sim_descendant(p,truthParticle)) {
566 ptrPart = truthParticle;
567 break;
568 }
569 }
570 }
571 else {
572 for (T truthParticle : TruthContainer) {
573 if (HepMC::is_sim_descendant(p,truthParticle)) {
574 ptrPart = truthParticle;
575 break;
576 }
577 }
578 }
579 return ptrPart;
580 }
582
583 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
584 auto prodVtx = thePart->production_vertex();
585 if (!prodVtx) return;
586 for (const auto& theMother: prodVtx->particles_in()) {
587 if (!theMother) continue;
588 allancestors.insert(theMother);
589 findParticleAncestors(theMother, allancestors);
590 }
591 }
592
594
595 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
596 auto endVtx = thePart->end_vertex();
597 if (!endVtx) return;
598 for (const auto& theDaughter: endVtx->particles_out()) {
599 if (!theDaughter) continue;
600 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
601 allstabledescendants.insert(theDaughter);
602 }
603 findParticleStableDescendants(theDaughter, allstabledescendants);
604 }
605 }
606
610
611 template <class T> bool isHardScatteringVertex(T pVert) {
612 if (pVert == nullptr) return false;
613 T pV = pVert;
614 int numOfPartIn(0);
615 int pdg(0);
616
617 do {
618 pVert = pV;
619 auto incoming = pVert->particles_in();
620 numOfPartIn = incoming.size();
621 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
622 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
623
624 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
625
626 if (numOfPartIn == 2) {
627 auto incoming = pVert->particles_in();
628 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
629 }
630 return false;
631}
632
636
637 template <class T, class U>
638 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
639 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
640 auto vtx = p->production_vertex();
641 if (!vtx) return false;
642 bool fromHad = false;
643 for ( const auto& parent : particles_in(vtx) ) {
644 if (!parent) continue;
645 // should this really go into parton-level territory?
646 // probably depends where BSM particles are being decayed
647 fromBSM |= isBSM(parent);
648 if (!isPhysical(parent)) return false;
649 fromTau |= isTau(parent);
650 if (isHadron(parent)&&!isBeam(parent)) {
651 if (!hadron) hadron = parent; // assumes linear hadron parentage
652 return true;
653 }
654 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
655 }
656 return fromHad;
657 }
658
661
662 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
663 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
664 decltype(thePart->end_vertex()) pVert(nullptr);
665 if (EndVert != nullptr) {
666 do {
667 bool samePart = false;
668 pVert = nullptr;
669 auto outgoing = EndVert->particles_out();
670 auto incoming = EndVert->particles_in();
671 for (const auto& itrDaug: outgoing) {
672 if (!itrDaug) continue;
673 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
674 // brem on generator level for tau
675 (outgoing.size() == 1 && incoming.size() == 1 &&
677 itrDaug->pdg_id() == thePart->pdg_id()) {
678 samePart = true;
679 pVert = itrDaug->end_vertex();
680 }
681 }
682 if (samePart) EndVert = pVert;
683 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
684 }
685 return EndVert;
686 }
687
689
690 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
691 if (!theVert) return {};
692 decltype(theVert->particles_out()) finalStatePart;
693 auto outgoing = theVert->particles_out();
694 for (const auto& thePart: outgoing) {
695 if (!thePart) continue;
696 finalStatePart.push_back(thePart);
697 if (isStable(thePart)) continue;
698 V pVert = findSimulatedEndVertex(thePart);
699 if (pVert == theVert) break; // to prevent Sherpa loop
700 if (pVert != nullptr) {
701 auto vecPart = findFinalStateParticles<V>(pVert);
702 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
703 }
704 }
705 return finalStatePart;
706 }
707
708}
709#endif

◆ isGenStable()

template<class T>
bool MC::isGenStable ( const T & p)
inline

Determine if the particle is stable at the generator (not det-sim) level,.

Definition at line 72 of file HepMCHelpers.h.

◆ isGlueball() [1/3]

template<>
bool MC::isGlueball ( const DecodedPID & p)
inline

Definition at line 443 of file HepMCHelpers.h.

464 {
465inline
466auto particles_in (const HepMC::GenVertex* p) {
467 return std::ranges::subrange (p->particles_in_const_begin(),
468 p->particles_in_const_end());
469}
470}
471#endif
472
473namespace MC
474{
475 template <class VTX>
476 auto particles_in (const VTX* p) { return p->particles_in(); }
477 template <class VTX>
478 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
479
480 namespace Pythia8
481 {
483 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
484
485 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
486
487 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
488 }
489
490#include "AtlasPID.h"
491
493 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
494
496 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
497
499 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
500
502 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
503
505 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
506
508 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
509
511 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
512
514 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
515
517 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
518
520 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
521
525 template <class T> inline bool isStableOrSimDecayed(const T& p) {
526 const auto vertex = p->end_vertex();
527 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
528 }
529
531 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
532
534 template <class T> inline bool isSpecialNonInteracting(const T& p) {
535 const int apid = std::abs(p->pdg_id());
536 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
537 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
538 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
539 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
540 return false;
541 }
542
544
545 template <class T> T findMother(T thePart) {
546 auto partOriVert = thePart->production_vertex();
547 if (!partOriVert) return nullptr;
548
549 long partPDG = thePart->pdg_id();
550 long MotherPDG(0);
551
552 auto MothOriVert = partOriVert;
553 MothOriVert = nullptr;
554 T theMoth(nullptr);
555
556 size_t itr = 0;
557 do {
558 if (itr != 0) partOriVert = MothOriVert;
559 for ( const auto& p : particles_in(partOriVert) ) {
560 theMoth = p;
561 if (!theMoth) continue;
562 MotherPDG = theMoth->pdg_id();
563 MothOriVert = theMoth->production_vertex();
564 if (MotherPDG == partPDG) break;
565 }
566 itr++;
567 if (itr > 100) {
568 break;
569 }
570 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
571 MothOriVert != partOriVert);
572 return theMoth;
573 }
574
576
577 template <class C, class T> T findMatching(C TruthContainer, T p) {
578 T ptrPart = nullptr;
579 if (!p) return ptrPart;
580 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
581 for (T truthParticle : *TruthContainer) {
582 if (HepMC::is_sim_descendant(p,truthParticle)) {
583 ptrPart = truthParticle;
584 break;
585 }
586 }
587 }
588 else {
589 for (T truthParticle : TruthContainer) {
590 if (HepMC::is_sim_descendant(p,truthParticle)) {
591 ptrPart = truthParticle;
592 break;
593 }
594 }
595 }
596 return ptrPart;
597 }
599
600 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
601 auto prodVtx = thePart->production_vertex();
602 if (!prodVtx) return;
603 for (const auto& theMother: prodVtx->particles_in()) {
604 if (!theMother) continue;
605 allancestors.insert(theMother);
606 findParticleAncestors(theMother, allancestors);
607 }
608 }
609
611
612 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
613 auto endVtx = thePart->end_vertex();
614 if (!endVtx) return;
615 for (const auto& theDaughter: endVtx->particles_out()) {
616 if (!theDaughter) continue;
617 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
618 allstabledescendants.insert(theDaughter);
619 }
620 findParticleStableDescendants(theDaughter, allstabledescendants);
621 }
622 }
623
627
628 template <class T> bool isHardScatteringVertex(T pVert) {
629 if (pVert == nullptr) return false;
630 T pV = pVert;
631 int numOfPartIn(0);
632 int pdg(0);
633
634 do {
635 pVert = pV;
636 auto incoming = pVert->particles_in();
637 numOfPartIn = incoming.size();
638 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
639 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
640
641 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
642
643 if (numOfPartIn == 2) {
644 auto incoming = pVert->particles_in();
645 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
646 }
647 return false;
648}
649
653
654 template <class T, class U>
655 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
656 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
657 auto vtx = p->production_vertex();
658 if (!vtx) return false;
659 bool fromHad = false;
660 for ( const auto& parent : particles_in(vtx) ) {
661 if (!parent) continue;
662 // should this really go into parton-level territory?
663 // probably depends where BSM particles are being decayed
664 fromBSM |= isBSM(parent);
665 if (!isPhysical(parent)) return false;
666 fromTau |= isTau(parent);
667 if (isHadron(parent)&&!isBeam(parent)) {
668 if (!hadron) hadron = parent; // assumes linear hadron parentage
669 return true;
670 }
671 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
672 }
673 return fromHad;
674 }
675
678
679 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
680 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
681 decltype(thePart->end_vertex()) pVert(nullptr);
682 if (EndVert != nullptr) {
683 do {
684 bool samePart = false;
685 pVert = nullptr;
686 auto outgoing = EndVert->particles_out();
687 auto incoming = EndVert->particles_in();
688 for (const auto& itrDaug: outgoing) {
689 if (!itrDaug) continue;
690 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
691 // brem on generator level for tau
692 (outgoing.size() == 1 && incoming.size() == 1 &&
694 itrDaug->pdg_id() == thePart->pdg_id()) {
695 samePart = true;
696 pVert = itrDaug->end_vertex();
697 }
698 }
699 if (samePart) EndVert = pVert;
700 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
701 }
702 return EndVert;
703 }
704
706
707 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
708 if (!theVert) return {};
709 decltype(theVert->particles_out()) finalStatePart;
710 auto outgoing = theVert->particles_out();
711 for (const auto& thePart: outgoing) {
712 if (!thePart) continue;
713 finalStatePart.push_back(thePart);
714 if (isStable(thePart)) continue;
715 V pVert = findSimulatedEndVertex(thePart);
716 if (pVert == theVert) break; // to prevent Sherpa loop
717 if (pVert != nullptr) {
718 auto vecPart = findFinalStateParticles<V>(pVert);
719 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
720 }
721 }
722 return finalStatePart;
723 }
724
725}
726#endif

◆ isGlueball() [2/3]

template<>
bool MC::isGlueball ( const int & p)
inline

Definition at line 449 of file HepMCHelpers.h.

470{
471inline
472auto particles_in (const HepMC::GenVertex* p) {
473 return std::ranges::subrange (p->particles_in_const_begin(),
474 p->particles_in_const_end());
475}
476}
477#endif
478
479namespace MC
480{
481 template <class VTX>
482 auto particles_in (const VTX* p) { return p->particles_in(); }
483 template <class VTX>
484 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
485
486 namespace Pythia8
487 {
489 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
490
491 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
492
493 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
494 }
495
496#include "AtlasPID.h"
497
499 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
500
502 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
503
505 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
506
508 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
509
511 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
512
514 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
515
517 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
518
520 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
521
523 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
524
526 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
527
531 template <class T> inline bool isStableOrSimDecayed(const T& p) {
532 const auto vertex = p->end_vertex();
533 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
534 }
535
537 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
538
540 template <class T> inline bool isSpecialNonInteracting(const T& p) {
541 const int apid = std::abs(p->pdg_id());
542 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
543 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
544 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
545 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
546 return false;
547 }
548
550
551 template <class T> T findMother(T thePart) {
552 auto partOriVert = thePart->production_vertex();
553 if (!partOriVert) return nullptr;
554
555 long partPDG = thePart->pdg_id();
556 long MotherPDG(0);
557
558 auto MothOriVert = partOriVert;
559 MothOriVert = nullptr;
560 T theMoth(nullptr);
561
562 size_t itr = 0;
563 do {
564 if (itr != 0) partOriVert = MothOriVert;
565 for ( const auto& p : particles_in(partOriVert) ) {
566 theMoth = p;
567 if (!theMoth) continue;
568 MotherPDG = theMoth->pdg_id();
569 MothOriVert = theMoth->production_vertex();
570 if (MotherPDG == partPDG) break;
571 }
572 itr++;
573 if (itr > 100) {
574 break;
575 }
576 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
577 MothOriVert != partOriVert);
578 return theMoth;
579 }
580
582
583 template <class C, class T> T findMatching(C TruthContainer, T p) {
584 T ptrPart = nullptr;
585 if (!p) return ptrPart;
586 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
587 for (T truthParticle : *TruthContainer) {
588 if (HepMC::is_sim_descendant(p,truthParticle)) {
589 ptrPart = truthParticle;
590 break;
591 }
592 }
593 }
594 else {
595 for (T truthParticle : TruthContainer) {
596 if (HepMC::is_sim_descendant(p,truthParticle)) {
597 ptrPart = truthParticle;
598 break;
599 }
600 }
601 }
602 return ptrPart;
603 }
605
606 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
607 auto prodVtx = thePart->production_vertex();
608 if (!prodVtx) return;
609 for (const auto& theMother: prodVtx->particles_in()) {
610 if (!theMother) continue;
611 allancestors.insert(theMother);
612 findParticleAncestors(theMother, allancestors);
613 }
614 }
615
617
618 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
619 auto endVtx = thePart->end_vertex();
620 if (!endVtx) return;
621 for (const auto& theDaughter: endVtx->particles_out()) {
622 if (!theDaughter) continue;
623 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
624 allstabledescendants.insert(theDaughter);
625 }
626 findParticleStableDescendants(theDaughter, allstabledescendants);
627 }
628 }
629
633
634 template <class T> bool isHardScatteringVertex(T pVert) {
635 if (pVert == nullptr) return false;
636 T pV = pVert;
637 int numOfPartIn(0);
638 int pdg(0);
639
640 do {
641 pVert = pV;
642 auto incoming = pVert->particles_in();
643 numOfPartIn = incoming.size();
644 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
645 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
646
647 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
648
649 if (numOfPartIn == 2) {
650 auto incoming = pVert->particles_in();
651 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
652 }
653 return false;
654}
655
659
660 template <class T, class U>
661 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
662 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
663 auto vtx = p->production_vertex();
664 if (!vtx) return false;
665 bool fromHad = false;
666 for ( const auto& parent : particles_in(vtx) ) {
667 if (!parent) continue;
668 // should this really go into parton-level territory?
669 // probably depends where BSM particles are being decayed
670 fromBSM |= isBSM(parent);
671 if (!isPhysical(parent)) return false;
672 fromTau |= isTau(parent);
673 if (isHadron(parent)&&!isBeam(parent)) {
674 if (!hadron) hadron = parent; // assumes linear hadron parentage
675 return true;
676 }
677 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
678 }
679 return fromHad;
680 }
681
684
685 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
686 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
687 decltype(thePart->end_vertex()) pVert(nullptr);
688 if (EndVert != nullptr) {
689 do {
690 bool samePart = false;
691 pVert = nullptr;
692 auto outgoing = EndVert->particles_out();
693 auto incoming = EndVert->particles_in();
694 for (const auto& itrDaug: outgoing) {
695 if (!itrDaug) continue;
696 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
697 // brem on generator level for tau
698 (outgoing.size() == 1 && incoming.size() == 1 &&
700 itrDaug->pdg_id() == thePart->pdg_id()) {
701 samePart = true;
702 pVert = itrDaug->end_vertex();
703 }
704 }
705 if (samePart) EndVert = pVert;
706 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
707 }
708 return EndVert;
709 }
710
712
713 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
714 if (!theVert) return {};
715 decltype(theVert->particles_out()) finalStatePart;
716 auto outgoing = theVert->particles_out();
717 for (const auto& thePart: outgoing) {
718 if (!thePart) continue;
719 finalStatePart.push_back(thePart);
720 if (isStable(thePart)) continue;
721 V pVert = findSimulatedEndVertex(thePart);
722 if (pVert == theVert) break; // to prevent Sherpa loop
723 if (pVert != nullptr) {
724 auto vecPart = findFinalStateParticles<V>(pVert);
725 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
726 }
727 }
728 return finalStatePart;
729 }
730
731}
732#endif

◆ isGlueball() [3/3]

template<class T>
bool MC::isGlueball ( const T & p)
inline

APID: Definition of Glueballs: SM glueballs 99X (X=1,5), 999Y (Y=3,7)

Definition at line 442 of file HepMCHelpers.h.

463{
464inline
465auto particles_in (const HepMC::GenVertex* p) {
466 return std::ranges::subrange (p->particles_in_const_begin(),
467 p->particles_in_const_end());
468}
469}
470#endif
471
472namespace MC
473{
474 template <class VTX>
475 auto particles_in (const VTX* p) { return p->particles_in(); }
476 template <class VTX>
477 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
478
479 namespace Pythia8
480 {
482 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
483
484 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
485
486 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
487 }
488
489#include "AtlasPID.h"
490
492 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
493
495 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
496
498 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
499
501 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
502
504 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
505
507 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
508
510 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
511
513 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
514
516 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
517
519 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
520
524 template <class T> inline bool isStableOrSimDecayed(const T& p) {
525 const auto vertex = p->end_vertex();
526 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
527 }
528
530 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
531
533 template <class T> inline bool isSpecialNonInteracting(const T& p) {
534 const int apid = std::abs(p->pdg_id());
535 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
536 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
537 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
538 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
539 return false;
540 }
541
543
544 template <class T> T findMother(T thePart) {
545 auto partOriVert = thePart->production_vertex();
546 if (!partOriVert) return nullptr;
547
548 long partPDG = thePart->pdg_id();
549 long MotherPDG(0);
550
551 auto MothOriVert = partOriVert;
552 MothOriVert = nullptr;
553 T theMoth(nullptr);
554
555 size_t itr = 0;
556 do {
557 if (itr != 0) partOriVert = MothOriVert;
558 for ( const auto& p : particles_in(partOriVert) ) {
559 theMoth = p;
560 if (!theMoth) continue;
561 MotherPDG = theMoth->pdg_id();
562 MothOriVert = theMoth->production_vertex();
563 if (MotherPDG == partPDG) break;
564 }
565 itr++;
566 if (itr > 100) {
567 break;
568 }
569 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
570 MothOriVert != partOriVert);
571 return theMoth;
572 }
573
575
576 template <class C, class T> T findMatching(C TruthContainer, T p) {
577 T ptrPart = nullptr;
578 if (!p) return ptrPart;
579 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
580 for (T truthParticle : *TruthContainer) {
581 if (HepMC::is_sim_descendant(p,truthParticle)) {
582 ptrPart = truthParticle;
583 break;
584 }
585 }
586 }
587 else {
588 for (T truthParticle : TruthContainer) {
589 if (HepMC::is_sim_descendant(p,truthParticle)) {
590 ptrPart = truthParticle;
591 break;
592 }
593 }
594 }
595 return ptrPart;
596 }
598
599 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
600 auto prodVtx = thePart->production_vertex();
601 if (!prodVtx) return;
602 for (const auto& theMother: prodVtx->particles_in()) {
603 if (!theMother) continue;
604 allancestors.insert(theMother);
605 findParticleAncestors(theMother, allancestors);
606 }
607 }
608
610
611 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
612 auto endVtx = thePart->end_vertex();
613 if (!endVtx) return;
614 for (const auto& theDaughter: endVtx->particles_out()) {
615 if (!theDaughter) continue;
616 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
617 allstabledescendants.insert(theDaughter);
618 }
619 findParticleStableDescendants(theDaughter, allstabledescendants);
620 }
621 }
622
626
627 template <class T> bool isHardScatteringVertex(T pVert) {
628 if (pVert == nullptr) return false;
629 T pV = pVert;
630 int numOfPartIn(0);
631 int pdg(0);
632
633 do {
634 pVert = pV;
635 auto incoming = pVert->particles_in();
636 numOfPartIn = incoming.size();
637 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
638 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
639
640 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
641
642 if (numOfPartIn == 2) {
643 auto incoming = pVert->particles_in();
644 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
645 }
646 return false;
647}
648
652
653 template <class T, class U>
654 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
655 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
656 auto vtx = p->production_vertex();
657 if (!vtx) return false;
658 bool fromHad = false;
659 for ( const auto& parent : particles_in(vtx) ) {
660 if (!parent) continue;
661 // should this really go into parton-level territory?
662 // probably depends where BSM particles are being decayed
663 fromBSM |= isBSM(parent);
664 if (!isPhysical(parent)) return false;
665 fromTau |= isTau(parent);
666 if (isHadron(parent)&&!isBeam(parent)) {
667 if (!hadron) hadron = parent; // assumes linear hadron parentage
668 return true;
669 }
670 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
671 }
672 return fromHad;
673 }
674
677
678 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
679 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
680 decltype(thePart->end_vertex()) pVert(nullptr);
681 if (EndVert != nullptr) {
682 do {
683 bool samePart = false;
684 pVert = nullptr;
685 auto outgoing = EndVert->particles_out();
686 auto incoming = EndVert->particles_in();
687 for (const auto& itrDaug: outgoing) {
688 if (!itrDaug) continue;
689 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
690 // brem on generator level for tau
691 (outgoing.size() == 1 && incoming.size() == 1 &&
693 itrDaug->pdg_id() == thePart->pdg_id()) {
694 samePart = true;
695 pVert = itrDaug->end_vertex();
696 }
697 }
698 if (samePart) EndVert = pVert;
699 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
700 }
701 return EndVert;
702 }
703
705
706 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
707 if (!theVert) return {};
708 decltype(theVert->particles_out()) finalStatePart;
709 auto outgoing = theVert->particles_out();
710 for (const auto& thePart: outgoing) {
711 if (!thePart) continue;
712 finalStatePart.push_back(thePart);
713 if (isStable(thePart)) continue;
714 V pVert = findSimulatedEndVertex(thePart);
715 if (pVert == theVert) break; // to prevent Sherpa loop
716 if (pVert != nullptr) {
717 auto vecPart = findFinalStateParticles<V>(pVert);
718 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
719 }
720 }
721 return finalStatePart;
722 }
723
724}
725#endif

◆ isGluon() [1/2]

template<>
bool MC::isGluon ( const int & p)
inline

Definition at line 375 of file HepMCHelpers.h.

396{
397inline
398auto particles_in (const HepMC::GenVertex* p) {
399 return std::ranges::subrange (p->particles_in_const_begin(),
400 p->particles_in_const_end());
401}
402}
403#endif
404
405namespace MC
406{
407 template <class VTX>
408 auto particles_in (const VTX* p) { return p->particles_in(); }
409 template <class VTX>
410 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
411
412 namespace Pythia8
413 {
415 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
416
417 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
418
419 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
420 }
421
422#include "AtlasPID.h"
423
425 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
426
428 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
429
431 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
432
434 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
435
437 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
438
440 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
441
443 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
444
446 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
447
449 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
450
452 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
453
457 template <class T> inline bool isStableOrSimDecayed(const T& p) {
458 const auto vertex = p->end_vertex();
459 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
460 }
461
463 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
464
466 template <class T> inline bool isSpecialNonInteracting(const T& p) {
467 const int apid = std::abs(p->pdg_id());
468 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
469 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
470 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
471 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
472 return false;
473 }
474
476
477 template <class T> T findMother(T thePart) {
478 auto partOriVert = thePart->production_vertex();
479 if (!partOriVert) return nullptr;
480
481 long partPDG = thePart->pdg_id();
482 long MotherPDG(0);
483
484 auto MothOriVert = partOriVert;
485 MothOriVert = nullptr;
486 T theMoth(nullptr);
487
488 size_t itr = 0;
489 do {
490 if (itr != 0) partOriVert = MothOriVert;
491 for ( const auto& p : particles_in(partOriVert) ) {
492 theMoth = p;
493 if (!theMoth) continue;
494 MotherPDG = theMoth->pdg_id();
495 MothOriVert = theMoth->production_vertex();
496 if (MotherPDG == partPDG) break;
497 }
498 itr++;
499 if (itr > 100) {
500 break;
501 }
502 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
503 MothOriVert != partOriVert);
504 return theMoth;
505 }
506
508
509 template <class C, class T> T findMatching(C TruthContainer, T p) {
510 T ptrPart = nullptr;
511 if (!p) return ptrPart;
512 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
513 for (T truthParticle : *TruthContainer) {
514 if (HepMC::is_sim_descendant(p,truthParticle)) {
515 ptrPart = truthParticle;
516 break;
517 }
518 }
519 }
520 else {
521 for (T truthParticle : TruthContainer) {
522 if (HepMC::is_sim_descendant(p,truthParticle)) {
523 ptrPart = truthParticle;
524 break;
525 }
526 }
527 }
528 return ptrPart;
529 }
531
532 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
533 auto prodVtx = thePart->production_vertex();
534 if (!prodVtx) return;
535 for (const auto& theMother: prodVtx->particles_in()) {
536 if (!theMother) continue;
537 allancestors.insert(theMother);
538 findParticleAncestors(theMother, allancestors);
539 }
540 }
541
543
544 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
545 auto endVtx = thePart->end_vertex();
546 if (!endVtx) return;
547 for (const auto& theDaughter: endVtx->particles_out()) {
548 if (!theDaughter) continue;
549 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
550 allstabledescendants.insert(theDaughter);
551 }
552 findParticleStableDescendants(theDaughter, allstabledescendants);
553 }
554 }
555
559
560 template <class T> bool isHardScatteringVertex(T pVert) {
561 if (pVert == nullptr) return false;
562 T pV = pVert;
563 int numOfPartIn(0);
564 int pdg(0);
565
566 do {
567 pVert = pV;
568 auto incoming = pVert->particles_in();
569 numOfPartIn = incoming.size();
570 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
571 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
572
573 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
574
575 if (numOfPartIn == 2) {
576 auto incoming = pVert->particles_in();
577 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
578 }
579 return false;
580}
581
585
586 template <class T, class U>
587 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
588 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
589 auto vtx = p->production_vertex();
590 if (!vtx) return false;
591 bool fromHad = false;
592 for ( const auto& parent : particles_in(vtx) ) {
593 if (!parent) continue;
594 // should this really go into parton-level territory?
595 // probably depends where BSM particles are being decayed
596 fromBSM |= isBSM(parent);
597 if (!isPhysical(parent)) return false;
598 fromTau |= isTau(parent);
599 if (isHadron(parent)&&!isBeam(parent)) {
600 if (!hadron) hadron = parent; // assumes linear hadron parentage
601 return true;
602 }
603 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
604 }
605 return fromHad;
606 }
607
610
611 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
612 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
613 decltype(thePart->end_vertex()) pVert(nullptr);
614 if (EndVert != nullptr) {
615 do {
616 bool samePart = false;
617 pVert = nullptr;
618 auto outgoing = EndVert->particles_out();
619 auto incoming = EndVert->particles_in();
620 for (const auto& itrDaug: outgoing) {
621 if (!itrDaug) continue;
622 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
623 // brem on generator level for tau
624 (outgoing.size() == 1 && incoming.size() == 1 &&
626 itrDaug->pdg_id() == thePart->pdg_id()) {
627 samePart = true;
628 pVert = itrDaug->end_vertex();
629 }
630 }
631 if (samePart) EndVert = pVert;
632 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
633 }
634 return EndVert;
635 }
636
638
639 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
640 if (!theVert) return {};
641 decltype(theVert->particles_out()) finalStatePart;
642 auto outgoing = theVert->particles_out();
643 for (const auto& thePart: outgoing) {
644 if (!thePart) continue;
645 finalStatePart.push_back(thePart);
646 if (isStable(thePart)) continue;
647 V pVert = findSimulatedEndVertex(thePart);
648 if (pVert == theVert) break; // to prevent Sherpa loop
649 if (pVert != nullptr) {
650 auto vecPart = findFinalStateParticles<V>(pVert);
651 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
652 }
653 }
654 return finalStatePart;
655 }
656
657}
658#endif

◆ isGluon() [2/2]

template<class T>
bool MC::isGluon ( const T & p)
inline

Definition at line 374 of file HepMCHelpers.h.

395{
396inline
397auto particles_in (const HepMC::GenVertex* p) {
398 return std::ranges::subrange (p->particles_in_const_begin(),
399 p->particles_in_const_end());
400}
401}
402#endif
403
404namespace MC
405{
406 template <class VTX>
407 auto particles_in (const VTX* p) { return p->particles_in(); }
408 template <class VTX>
409 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
410
411 namespace Pythia8
412 {
414 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
415
416 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
417
418 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
419 }
420
421#include "AtlasPID.h"
422
424 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
425
427 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
428
430 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
431
433 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
434
436 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
437
439 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
440
442 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
443
445 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
446
448 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
449
451 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
452
456 template <class T> inline bool isStableOrSimDecayed(const T& p) {
457 const auto vertex = p->end_vertex();
458 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
459 }
460
462 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
463
465 template <class T> inline bool isSpecialNonInteracting(const T& p) {
466 const int apid = std::abs(p->pdg_id());
467 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
468 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
469 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
470 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
471 return false;
472 }
473
475
476 template <class T> T findMother(T thePart) {
477 auto partOriVert = thePart->production_vertex();
478 if (!partOriVert) return nullptr;
479
480 long partPDG = thePart->pdg_id();
481 long MotherPDG(0);
482
483 auto MothOriVert = partOriVert;
484 MothOriVert = nullptr;
485 T theMoth(nullptr);
486
487 size_t itr = 0;
488 do {
489 if (itr != 0) partOriVert = MothOriVert;
490 for ( const auto& p : particles_in(partOriVert) ) {
491 theMoth = p;
492 if (!theMoth) continue;
493 MotherPDG = theMoth->pdg_id();
494 MothOriVert = theMoth->production_vertex();
495 if (MotherPDG == partPDG) break;
496 }
497 itr++;
498 if (itr > 100) {
499 break;
500 }
501 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
502 MothOriVert != partOriVert);
503 return theMoth;
504 }
505
507
508 template <class C, class T> T findMatching(C TruthContainer, T p) {
509 T ptrPart = nullptr;
510 if (!p) return ptrPart;
511 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
512 for (T truthParticle : *TruthContainer) {
513 if (HepMC::is_sim_descendant(p,truthParticle)) {
514 ptrPart = truthParticle;
515 break;
516 }
517 }
518 }
519 else {
520 for (T truthParticle : TruthContainer) {
521 if (HepMC::is_sim_descendant(p,truthParticle)) {
522 ptrPart = truthParticle;
523 break;
524 }
525 }
526 }
527 return ptrPart;
528 }
530
531 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
532 auto prodVtx = thePart->production_vertex();
533 if (!prodVtx) return;
534 for (const auto& theMother: prodVtx->particles_in()) {
535 if (!theMother) continue;
536 allancestors.insert(theMother);
537 findParticleAncestors(theMother, allancestors);
538 }
539 }
540
542
543 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
544 auto endVtx = thePart->end_vertex();
545 if (!endVtx) return;
546 for (const auto& theDaughter: endVtx->particles_out()) {
547 if (!theDaughter) continue;
548 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
549 allstabledescendants.insert(theDaughter);
550 }
551 findParticleStableDescendants(theDaughter, allstabledescendants);
552 }
553 }
554
558
559 template <class T> bool isHardScatteringVertex(T pVert) {
560 if (pVert == nullptr) return false;
561 T pV = pVert;
562 int numOfPartIn(0);
563 int pdg(0);
564
565 do {
566 pVert = pV;
567 auto incoming = pVert->particles_in();
568 numOfPartIn = incoming.size();
569 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
570 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
571
572 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
573
574 if (numOfPartIn == 2) {
575 auto incoming = pVert->particles_in();
576 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
577 }
578 return false;
579}
580
584
585 template <class T, class U>
586 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
587 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
588 auto vtx = p->production_vertex();
589 if (!vtx) return false;
590 bool fromHad = false;
591 for ( const auto& parent : particles_in(vtx) ) {
592 if (!parent) continue;
593 // should this really go into parton-level territory?
594 // probably depends where BSM particles are being decayed
595 fromBSM |= isBSM(parent);
596 if (!isPhysical(parent)) return false;
597 fromTau |= isTau(parent);
598 if (isHadron(parent)&&!isBeam(parent)) {
599 if (!hadron) hadron = parent; // assumes linear hadron parentage
600 return true;
601 }
602 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
603 }
604 return fromHad;
605 }
606
609
610 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
611 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
612 decltype(thePart->end_vertex()) pVert(nullptr);
613 if (EndVert != nullptr) {
614 do {
615 bool samePart = false;
616 pVert = nullptr;
617 auto outgoing = EndVert->particles_out();
618 auto incoming = EndVert->particles_in();
619 for (const auto& itrDaug: outgoing) {
620 if (!itrDaug) continue;
621 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
622 // brem on generator level for tau
623 (outgoing.size() == 1 && incoming.size() == 1 &&
625 itrDaug->pdg_id() == thePart->pdg_id()) {
626 samePart = true;
627 pVert = itrDaug->end_vertex();
628 }
629 }
630 if (samePart) EndVert = pVert;
631 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
632 }
633 return EndVert;
634 }
635
637
638 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
639 if (!theVert) return {};
640 decltype(theVert->particles_out()) finalStatePart;
641 auto outgoing = theVert->particles_out();
642 for (const auto& thePart: outgoing) {
643 if (!thePart) continue;
644 finalStatePart.push_back(thePart);
645 if (isStable(thePart)) continue;
646 V pVert = findSimulatedEndVertex(thePart);
647 if (pVert == theVert) break; // to prevent Sherpa loop
648 if (pVert != nullptr) {
649 auto vecPart = findFinalStateParticles<V>(pVert);
650 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
651 }
652 }
653 return finalStatePart;
654 }
655
656}
657#endif

◆ isGraviton() [1/2]

template<>
bool MC::isGraviton ( const int & p)
inline

Definition at line 399 of file HepMCHelpers.h.

420{
421inline
422auto particles_in (const HepMC::GenVertex* p) {
423 return std::ranges::subrange (p->particles_in_const_begin(),
424 p->particles_in_const_end());
425}
426}
427#endif
428
429namespace MC
430{
431 template <class VTX>
432 auto particles_in (const VTX* p) { return p->particles_in(); }
433 template <class VTX>
434 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
435
436 namespace Pythia8
437 {
439 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
440
441 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
442
443 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
444 }
445
446#include "AtlasPID.h"
447
449 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
450
452 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
453
455 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
456
458 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
459
461 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
462
464 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
465
467 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
468
470 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
471
473 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
474
476 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
477
481 template <class T> inline bool isStableOrSimDecayed(const T& p) {
482 const auto vertex = p->end_vertex();
483 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
484 }
485
487 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
488
490 template <class T> inline bool isSpecialNonInteracting(const T& p) {
491 const int apid = std::abs(p->pdg_id());
492 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
493 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
494 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
495 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
496 return false;
497 }
498
500
501 template <class T> T findMother(T thePart) {
502 auto partOriVert = thePart->production_vertex();
503 if (!partOriVert) return nullptr;
504
505 long partPDG = thePart->pdg_id();
506 long MotherPDG(0);
507
508 auto MothOriVert = partOriVert;
509 MothOriVert = nullptr;
510 T theMoth(nullptr);
511
512 size_t itr = 0;
513 do {
514 if (itr != 0) partOriVert = MothOriVert;
515 for ( const auto& p : particles_in(partOriVert) ) {
516 theMoth = p;
517 if (!theMoth) continue;
518 MotherPDG = theMoth->pdg_id();
519 MothOriVert = theMoth->production_vertex();
520 if (MotherPDG == partPDG) break;
521 }
522 itr++;
523 if (itr > 100) {
524 break;
525 }
526 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
527 MothOriVert != partOriVert);
528 return theMoth;
529 }
530
532
533 template <class C, class T> T findMatching(C TruthContainer, T p) {
534 T ptrPart = nullptr;
535 if (!p) return ptrPart;
536 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
537 for (T truthParticle : *TruthContainer) {
538 if (HepMC::is_sim_descendant(p,truthParticle)) {
539 ptrPart = truthParticle;
540 break;
541 }
542 }
543 }
544 else {
545 for (T truthParticle : TruthContainer) {
546 if (HepMC::is_sim_descendant(p,truthParticle)) {
547 ptrPart = truthParticle;
548 break;
549 }
550 }
551 }
552 return ptrPart;
553 }
555
556 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
557 auto prodVtx = thePart->production_vertex();
558 if (!prodVtx) return;
559 for (const auto& theMother: prodVtx->particles_in()) {
560 if (!theMother) continue;
561 allancestors.insert(theMother);
562 findParticleAncestors(theMother, allancestors);
563 }
564 }
565
567
568 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
569 auto endVtx = thePart->end_vertex();
570 if (!endVtx) return;
571 for (const auto& theDaughter: endVtx->particles_out()) {
572 if (!theDaughter) continue;
573 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
574 allstabledescendants.insert(theDaughter);
575 }
576 findParticleStableDescendants(theDaughter, allstabledescendants);
577 }
578 }
579
583
584 template <class T> bool isHardScatteringVertex(T pVert) {
585 if (pVert == nullptr) return false;
586 T pV = pVert;
587 int numOfPartIn(0);
588 int pdg(0);
589
590 do {
591 pVert = pV;
592 auto incoming = pVert->particles_in();
593 numOfPartIn = incoming.size();
594 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
595 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
596
597 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
598
599 if (numOfPartIn == 2) {
600 auto incoming = pVert->particles_in();
601 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
602 }
603 return false;
604}
605
609
610 template <class T, class U>
611 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
612 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
613 auto vtx = p->production_vertex();
614 if (!vtx) return false;
615 bool fromHad = false;
616 for ( const auto& parent : particles_in(vtx) ) {
617 if (!parent) continue;
618 // should this really go into parton-level territory?
619 // probably depends where BSM particles are being decayed
620 fromBSM |= isBSM(parent);
621 if (!isPhysical(parent)) return false;
622 fromTau |= isTau(parent);
623 if (isHadron(parent)&&!isBeam(parent)) {
624 if (!hadron) hadron = parent; // assumes linear hadron parentage
625 return true;
626 }
627 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
628 }
629 return fromHad;
630 }
631
634
635 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
636 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
637 decltype(thePart->end_vertex()) pVert(nullptr);
638 if (EndVert != nullptr) {
639 do {
640 bool samePart = false;
641 pVert = nullptr;
642 auto outgoing = EndVert->particles_out();
643 auto incoming = EndVert->particles_in();
644 for (const auto& itrDaug: outgoing) {
645 if (!itrDaug) continue;
646 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
647 // brem on generator level for tau
648 (outgoing.size() == 1 && incoming.size() == 1 &&
650 itrDaug->pdg_id() == thePart->pdg_id()) {
651 samePart = true;
652 pVert = itrDaug->end_vertex();
653 }
654 }
655 if (samePart) EndVert = pVert;
656 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
657 }
658 return EndVert;
659 }
660
662
663 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
664 if (!theVert) return {};
665 decltype(theVert->particles_out()) finalStatePart;
666 auto outgoing = theVert->particles_out();
667 for (const auto& thePart: outgoing) {
668 if (!thePart) continue;
669 finalStatePart.push_back(thePart);
670 if (isStable(thePart)) continue;
671 V pVert = findSimulatedEndVertex(thePart);
672 if (pVert == theVert) break; // to prevent Sherpa loop
673 if (pVert != nullptr) {
674 auto vecPart = findFinalStateParticles<V>(pVert);
675 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
676 }
677 }
678 return finalStatePart;
679 }
680
681}
682#endif

◆ isGraviton() [2/2]

template<class T>
bool MC::isGraviton ( const T & p)
inline

Definition at line 398 of file HepMCHelpers.h.

419{
420inline
421auto particles_in (const HepMC::GenVertex* p) {
422 return std::ranges::subrange (p->particles_in_const_begin(),
423 p->particles_in_const_end());
424}
425}
426#endif
427
428namespace MC
429{
430 template <class VTX>
431 auto particles_in (const VTX* p) { return p->particles_in(); }
432 template <class VTX>
433 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
434
435 namespace Pythia8
436 {
438 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
439
440 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
441
442 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
443 }
444
445#include "AtlasPID.h"
446
448 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
449
451 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
452
454 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
455
457 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
458
460 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
461
463 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
464
466 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
467
469 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
470
472 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
473
475 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
476
480 template <class T> inline bool isStableOrSimDecayed(const T& p) {
481 const auto vertex = p->end_vertex();
482 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
483 }
484
486 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
487
489 template <class T> inline bool isSpecialNonInteracting(const T& p) {
490 const int apid = std::abs(p->pdg_id());
491 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
492 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
493 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
494 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
495 return false;
496 }
497
499
500 template <class T> T findMother(T thePart) {
501 auto partOriVert = thePart->production_vertex();
502 if (!partOriVert) return nullptr;
503
504 long partPDG = thePart->pdg_id();
505 long MotherPDG(0);
506
507 auto MothOriVert = partOriVert;
508 MothOriVert = nullptr;
509 T theMoth(nullptr);
510
511 size_t itr = 0;
512 do {
513 if (itr != 0) partOriVert = MothOriVert;
514 for ( const auto& p : particles_in(partOriVert) ) {
515 theMoth = p;
516 if (!theMoth) continue;
517 MotherPDG = theMoth->pdg_id();
518 MothOriVert = theMoth->production_vertex();
519 if (MotherPDG == partPDG) break;
520 }
521 itr++;
522 if (itr > 100) {
523 break;
524 }
525 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
526 MothOriVert != partOriVert);
527 return theMoth;
528 }
529
531
532 template <class C, class T> T findMatching(C TruthContainer, T p) {
533 T ptrPart = nullptr;
534 if (!p) return ptrPart;
535 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
536 for (T truthParticle : *TruthContainer) {
537 if (HepMC::is_sim_descendant(p,truthParticle)) {
538 ptrPart = truthParticle;
539 break;
540 }
541 }
542 }
543 else {
544 for (T truthParticle : TruthContainer) {
545 if (HepMC::is_sim_descendant(p,truthParticle)) {
546 ptrPart = truthParticle;
547 break;
548 }
549 }
550 }
551 return ptrPart;
552 }
554
555 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
556 auto prodVtx = thePart->production_vertex();
557 if (!prodVtx) return;
558 for (const auto& theMother: prodVtx->particles_in()) {
559 if (!theMother) continue;
560 allancestors.insert(theMother);
561 findParticleAncestors(theMother, allancestors);
562 }
563 }
564
566
567 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
568 auto endVtx = thePart->end_vertex();
569 if (!endVtx) return;
570 for (const auto& theDaughter: endVtx->particles_out()) {
571 if (!theDaughter) continue;
572 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
573 allstabledescendants.insert(theDaughter);
574 }
575 findParticleStableDescendants(theDaughter, allstabledescendants);
576 }
577 }
578
582
583 template <class T> bool isHardScatteringVertex(T pVert) {
584 if (pVert == nullptr) return false;
585 T pV = pVert;
586 int numOfPartIn(0);
587 int pdg(0);
588
589 do {
590 pVert = pV;
591 auto incoming = pVert->particles_in();
592 numOfPartIn = incoming.size();
593 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
594 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
595
596 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
597
598 if (numOfPartIn == 2) {
599 auto incoming = pVert->particles_in();
600 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
601 }
602 return false;
603}
604
608
609 template <class T, class U>
610 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
611 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
612 auto vtx = p->production_vertex();
613 if (!vtx) return false;
614 bool fromHad = false;
615 for ( const auto& parent : particles_in(vtx) ) {
616 if (!parent) continue;
617 // should this really go into parton-level territory?
618 // probably depends where BSM particles are being decayed
619 fromBSM |= isBSM(parent);
620 if (!isPhysical(parent)) return false;
621 fromTau |= isTau(parent);
622 if (isHadron(parent)&&!isBeam(parent)) {
623 if (!hadron) hadron = parent; // assumes linear hadron parentage
624 return true;
625 }
626 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
627 }
628 return fromHad;
629 }
630
633
634 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
635 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
636 decltype(thePart->end_vertex()) pVert(nullptr);
637 if (EndVert != nullptr) {
638 do {
639 bool samePart = false;
640 pVert = nullptr;
641 auto outgoing = EndVert->particles_out();
642 auto incoming = EndVert->particles_in();
643 for (const auto& itrDaug: outgoing) {
644 if (!itrDaug) continue;
645 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
646 // brem on generator level for tau
647 (outgoing.size() == 1 && incoming.size() == 1 &&
649 itrDaug->pdg_id() == thePart->pdg_id()) {
650 samePart = true;
651 pVert = itrDaug->end_vertex();
652 }
653 }
654 if (samePart) EndVert = pVert;
655 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
656 }
657 return EndVert;
658 }
659
661
662 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
663 if (!theVert) return {};
664 decltype(theVert->particles_out()) finalStatePart;
665 auto outgoing = theVert->particles_out();
666 for (const auto& thePart: outgoing) {
667 if (!thePart) continue;
668 finalStatePart.push_back(thePart);
669 if (isStable(thePart)) continue;
670 V pVert = findSimulatedEndVertex(thePart);
671 if (pVert == theVert) break; // to prevent Sherpa loop
672 if (pVert != nullptr) {
673 auto vecPart = findFinalStateParticles<V>(pVert);
674 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
675 }
676 }
677 return finalStatePart;
678 }
679
680}
681#endif

◆ isHadron() [1/3]

template<>
bool MC::isHadron ( const DecodedPID & p)
inline

Definition at line 353 of file HepMCHelpers.h.

374{
375inline
376auto particles_in (const HepMC::GenVertex* p) {
377 return std::ranges::subrange (p->particles_in_const_begin(),
378 p->particles_in_const_end());
379}
380}
381#endif
382
383namespace MC
384{
385 template <class VTX>
386 auto particles_in (const VTX* p) { return p->particles_in(); }
387 template <class VTX>
388 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
389
390 namespace Pythia8
391 {
393 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
394
395 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
396
397 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
398 }
399
400#include "AtlasPID.h"
401
403 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
404
406 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
407
409 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
410
412 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
413
415 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
416
418 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
419
421 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
422
424 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
425
427 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
428
430 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
431
435 template <class T> inline bool isStableOrSimDecayed(const T& p) {
436 const auto vertex = p->end_vertex();
437 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
438 }
439
441 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
442
444 template <class T> inline bool isSpecialNonInteracting(const T& p) {
445 const int apid = std::abs(p->pdg_id());
446 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
447 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
448 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
449 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
450 return false;
451 }
452
454
455 template <class T> T findMother(T thePart) {
456 auto partOriVert = thePart->production_vertex();
457 if (!partOriVert) return nullptr;
458
459 long partPDG = thePart->pdg_id();
460 long MotherPDG(0);
461
462 auto MothOriVert = partOriVert;
463 MothOriVert = nullptr;
464 T theMoth(nullptr);
465
466 size_t itr = 0;
467 do {
468 if (itr != 0) partOriVert = MothOriVert;
469 for ( const auto& p : particles_in(partOriVert) ) {
470 theMoth = p;
471 if (!theMoth) continue;
472 MotherPDG = theMoth->pdg_id();
473 MothOriVert = theMoth->production_vertex();
474 if (MotherPDG == partPDG) break;
475 }
476 itr++;
477 if (itr > 100) {
478 break;
479 }
480 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
481 MothOriVert != partOriVert);
482 return theMoth;
483 }
484
486
487 template <class C, class T> T findMatching(C TruthContainer, T p) {
488 T ptrPart = nullptr;
489 if (!p) return ptrPart;
490 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
491 for (T truthParticle : *TruthContainer) {
492 if (HepMC::is_sim_descendant(p,truthParticle)) {
493 ptrPart = truthParticle;
494 break;
495 }
496 }
497 }
498 else {
499 for (T truthParticle : TruthContainer) {
500 if (HepMC::is_sim_descendant(p,truthParticle)) {
501 ptrPart = truthParticle;
502 break;
503 }
504 }
505 }
506 return ptrPart;
507 }
509
510 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
511 auto prodVtx = thePart->production_vertex();
512 if (!prodVtx) return;
513 for (const auto& theMother: prodVtx->particles_in()) {
514 if (!theMother) continue;
515 allancestors.insert(theMother);
516 findParticleAncestors(theMother, allancestors);
517 }
518 }
519
521
522 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
523 auto endVtx = thePart->end_vertex();
524 if (!endVtx) return;
525 for (const auto& theDaughter: endVtx->particles_out()) {
526 if (!theDaughter) continue;
527 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
528 allstabledescendants.insert(theDaughter);
529 }
530 findParticleStableDescendants(theDaughter, allstabledescendants);
531 }
532 }
533
537
538 template <class T> bool isHardScatteringVertex(T pVert) {
539 if (pVert == nullptr) return false;
540 T pV = pVert;
541 int numOfPartIn(0);
542 int pdg(0);
543
544 do {
545 pVert = pV;
546 auto incoming = pVert->particles_in();
547 numOfPartIn = incoming.size();
548 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
549 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
550
551 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
552
553 if (numOfPartIn == 2) {
554 auto incoming = pVert->particles_in();
555 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
556 }
557 return false;
558}
559
563
564 template <class T, class U>
565 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
566 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
567 auto vtx = p->production_vertex();
568 if (!vtx) return false;
569 bool fromHad = false;
570 for ( const auto& parent : particles_in(vtx) ) {
571 if (!parent) continue;
572 // should this really go into parton-level territory?
573 // probably depends where BSM particles are being decayed
574 fromBSM |= isBSM(parent);
575 if (!isPhysical(parent)) return false;
576 fromTau |= isTau(parent);
577 if (isHadron(parent)&&!isBeam(parent)) {
578 if (!hadron) hadron = parent; // assumes linear hadron parentage
579 return true;
580 }
581 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
582 }
583 return fromHad;
584 }
585
588
589 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
590 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
591 decltype(thePart->end_vertex()) pVert(nullptr);
592 if (EndVert != nullptr) {
593 do {
594 bool samePart = false;
595 pVert = nullptr;
596 auto outgoing = EndVert->particles_out();
597 auto incoming = EndVert->particles_in();
598 for (const auto& itrDaug: outgoing) {
599 if (!itrDaug) continue;
600 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
601 // brem on generator level for tau
602 (outgoing.size() == 1 && incoming.size() == 1 &&
604 itrDaug->pdg_id() == thePart->pdg_id()) {
605 samePart = true;
606 pVert = itrDaug->end_vertex();
607 }
608 }
609 if (samePart) EndVert = pVert;
610 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
611 }
612 return EndVert;
613 }
614
616
617 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
618 if (!theVert) return {};
619 decltype(theVert->particles_out()) finalStatePart;
620 auto outgoing = theVert->particles_out();
621 for (const auto& thePart: outgoing) {
622 if (!thePart) continue;
623 finalStatePart.push_back(thePart);
624 if (isStable(thePart)) continue;
625 V pVert = findSimulatedEndVertex(thePart);
626 if (pVert == theVert) break; // to prevent Sherpa loop
627 if (pVert != nullptr) {
628 auto vecPart = findFinalStateParticles<V>(pVert);
629 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
630 }
631 }
632 return finalStatePart;
633 }
634
635}
636#endif

◆ isHadron() [2/3]

template<>
bool MC::isHadron ( const int & p)
inline

Definition at line 354 of file HepMCHelpers.h.

375{
376inline
377auto particles_in (const HepMC::GenVertex* p) {
378 return std::ranges::subrange (p->particles_in_const_begin(),
379 p->particles_in_const_end());
380}
381}
382#endif
383
384namespace MC
385{
386 template <class VTX>
387 auto particles_in (const VTX* p) { return p->particles_in(); }
388 template <class VTX>
389 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
390
391 namespace Pythia8
392 {
394 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
395
396 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
397
398 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
399 }
400
401#include "AtlasPID.h"
402
404 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
405
407 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
408
410 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
411
413 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
414
416 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
417
419 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
420
422 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
423
425 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
426
428 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
429
431 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
432
436 template <class T> inline bool isStableOrSimDecayed(const T& p) {
437 const auto vertex = p->end_vertex();
438 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
439 }
440
442 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
443
445 template <class T> inline bool isSpecialNonInteracting(const T& p) {
446 const int apid = std::abs(p->pdg_id());
447 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
448 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
449 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
450 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
451 return false;
452 }
453
455
456 template <class T> T findMother(T thePart) {
457 auto partOriVert = thePart->production_vertex();
458 if (!partOriVert) return nullptr;
459
460 long partPDG = thePart->pdg_id();
461 long MotherPDG(0);
462
463 auto MothOriVert = partOriVert;
464 MothOriVert = nullptr;
465 T theMoth(nullptr);
466
467 size_t itr = 0;
468 do {
469 if (itr != 0) partOriVert = MothOriVert;
470 for ( const auto& p : particles_in(partOriVert) ) {
471 theMoth = p;
472 if (!theMoth) continue;
473 MotherPDG = theMoth->pdg_id();
474 MothOriVert = theMoth->production_vertex();
475 if (MotherPDG == partPDG) break;
476 }
477 itr++;
478 if (itr > 100) {
479 break;
480 }
481 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
482 MothOriVert != partOriVert);
483 return theMoth;
484 }
485
487
488 template <class C, class T> T findMatching(C TruthContainer, T p) {
489 T ptrPart = nullptr;
490 if (!p) return ptrPart;
491 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
492 for (T truthParticle : *TruthContainer) {
493 if (HepMC::is_sim_descendant(p,truthParticle)) {
494 ptrPart = truthParticle;
495 break;
496 }
497 }
498 }
499 else {
500 for (T truthParticle : TruthContainer) {
501 if (HepMC::is_sim_descendant(p,truthParticle)) {
502 ptrPart = truthParticle;
503 break;
504 }
505 }
506 }
507 return ptrPart;
508 }
510
511 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
512 auto prodVtx = thePart->production_vertex();
513 if (!prodVtx) return;
514 for (const auto& theMother: prodVtx->particles_in()) {
515 if (!theMother) continue;
516 allancestors.insert(theMother);
517 findParticleAncestors(theMother, allancestors);
518 }
519 }
520
522
523 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
524 auto endVtx = thePart->end_vertex();
525 if (!endVtx) return;
526 for (const auto& theDaughter: endVtx->particles_out()) {
527 if (!theDaughter) continue;
528 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
529 allstabledescendants.insert(theDaughter);
530 }
531 findParticleStableDescendants(theDaughter, allstabledescendants);
532 }
533 }
534
538
539 template <class T> bool isHardScatteringVertex(T pVert) {
540 if (pVert == nullptr) return false;
541 T pV = pVert;
542 int numOfPartIn(0);
543 int pdg(0);
544
545 do {
546 pVert = pV;
547 auto incoming = pVert->particles_in();
548 numOfPartIn = incoming.size();
549 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
550 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
551
552 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
553
554 if (numOfPartIn == 2) {
555 auto incoming = pVert->particles_in();
556 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
557 }
558 return false;
559}
560
564
565 template <class T, class U>
566 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
567 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
568 auto vtx = p->production_vertex();
569 if (!vtx) return false;
570 bool fromHad = false;
571 for ( const auto& parent : particles_in(vtx) ) {
572 if (!parent) continue;
573 // should this really go into parton-level territory?
574 // probably depends where BSM particles are being decayed
575 fromBSM |= isBSM(parent);
576 if (!isPhysical(parent)) return false;
577 fromTau |= isTau(parent);
578 if (isHadron(parent)&&!isBeam(parent)) {
579 if (!hadron) hadron = parent; // assumes linear hadron parentage
580 return true;
581 }
582 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
583 }
584 return fromHad;
585 }
586
589
590 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
591 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
592 decltype(thePart->end_vertex()) pVert(nullptr);
593 if (EndVert != nullptr) {
594 do {
595 bool samePart = false;
596 pVert = nullptr;
597 auto outgoing = EndVert->particles_out();
598 auto incoming = EndVert->particles_in();
599 for (const auto& itrDaug: outgoing) {
600 if (!itrDaug) continue;
601 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
602 // brem on generator level for tau
603 (outgoing.size() == 1 && incoming.size() == 1 &&
605 itrDaug->pdg_id() == thePart->pdg_id()) {
606 samePart = true;
607 pVert = itrDaug->end_vertex();
608 }
609 }
610 if (samePart) EndVert = pVert;
611 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
612 }
613 return EndVert;
614 }
615
617
618 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
619 if (!theVert) return {};
620 decltype(theVert->particles_out()) finalStatePart;
621 auto outgoing = theVert->particles_out();
622 for (const auto& thePart: outgoing) {
623 if (!thePart) continue;
624 finalStatePart.push_back(thePart);
625 if (isStable(thePart)) continue;
626 V pVert = findSimulatedEndVertex(thePart);
627 if (pVert == theVert) break; // to prevent Sherpa loop
628 if (pVert != nullptr) {
629 auto vecPart = findFinalStateParticles<V>(pVert);
630 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
631 }
632 }
633 return finalStatePart;
634 }
635
636}
637#endif

◆ isHadron() [3/3]

template<class T>
bool MC::isHadron ( const T & p)
inline

Definition at line 352 of file HepMCHelpers.h.

373{
374inline
375auto particles_in (const HepMC::GenVertex* p) {
376 return std::ranges::subrange (p->particles_in_const_begin(),
377 p->particles_in_const_end());
378}
379}
380#endif
381
382namespace MC
383{
384 template <class VTX>
385 auto particles_in (const VTX* p) { return p->particles_in(); }
386 template <class VTX>
387 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
388
389 namespace Pythia8
390 {
392 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
393
394 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
395
396 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
397 }
398
399#include "AtlasPID.h"
400
402 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
403
405 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
406
408 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
409
411 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
412
414 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
415
417 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
418
420 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
421
423 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
424
426 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
427
429 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
430
434 template <class T> inline bool isStableOrSimDecayed(const T& p) {
435 const auto vertex = p->end_vertex();
436 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
437 }
438
440 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
441
443 template <class T> inline bool isSpecialNonInteracting(const T& p) {
444 const int apid = std::abs(p->pdg_id());
445 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
446 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
447 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
448 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
449 return false;
450 }
451
453
454 template <class T> T findMother(T thePart) {
455 auto partOriVert = thePart->production_vertex();
456 if (!partOriVert) return nullptr;
457
458 long partPDG = thePart->pdg_id();
459 long MotherPDG(0);
460
461 auto MothOriVert = partOriVert;
462 MothOriVert = nullptr;
463 T theMoth(nullptr);
464
465 size_t itr = 0;
466 do {
467 if (itr != 0) partOriVert = MothOriVert;
468 for ( const auto& p : particles_in(partOriVert) ) {
469 theMoth = p;
470 if (!theMoth) continue;
471 MotherPDG = theMoth->pdg_id();
472 MothOriVert = theMoth->production_vertex();
473 if (MotherPDG == partPDG) break;
474 }
475 itr++;
476 if (itr > 100) {
477 break;
478 }
479 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
480 MothOriVert != partOriVert);
481 return theMoth;
482 }
483
485
486 template <class C, class T> T findMatching(C TruthContainer, T p) {
487 T ptrPart = nullptr;
488 if (!p) return ptrPart;
489 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
490 for (T truthParticle : *TruthContainer) {
491 if (HepMC::is_sim_descendant(p,truthParticle)) {
492 ptrPart = truthParticle;
493 break;
494 }
495 }
496 }
497 else {
498 for (T truthParticle : TruthContainer) {
499 if (HepMC::is_sim_descendant(p,truthParticle)) {
500 ptrPart = truthParticle;
501 break;
502 }
503 }
504 }
505 return ptrPart;
506 }
508
509 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
510 auto prodVtx = thePart->production_vertex();
511 if (!prodVtx) return;
512 for (const auto& theMother: prodVtx->particles_in()) {
513 if (!theMother) continue;
514 allancestors.insert(theMother);
515 findParticleAncestors(theMother, allancestors);
516 }
517 }
518
520
521 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
522 auto endVtx = thePart->end_vertex();
523 if (!endVtx) return;
524 for (const auto& theDaughter: endVtx->particles_out()) {
525 if (!theDaughter) continue;
526 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
527 allstabledescendants.insert(theDaughter);
528 }
529 findParticleStableDescendants(theDaughter, allstabledescendants);
530 }
531 }
532
536
537 template <class T> bool isHardScatteringVertex(T pVert) {
538 if (pVert == nullptr) return false;
539 T pV = pVert;
540 int numOfPartIn(0);
541 int pdg(0);
542
543 do {
544 pVert = pV;
545 auto incoming = pVert->particles_in();
546 numOfPartIn = incoming.size();
547 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
548 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
549
550 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
551
552 if (numOfPartIn == 2) {
553 auto incoming = pVert->particles_in();
554 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
555 }
556 return false;
557}
558
562
563 template <class T, class U>
564 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
565 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
566 auto vtx = p->production_vertex();
567 if (!vtx) return false;
568 bool fromHad = false;
569 for ( const auto& parent : particles_in(vtx) ) {
570 if (!parent) continue;
571 // should this really go into parton-level territory?
572 // probably depends where BSM particles are being decayed
573 fromBSM |= isBSM(parent);
574 if (!isPhysical(parent)) return false;
575 fromTau |= isTau(parent);
576 if (isHadron(parent)&&!isBeam(parent)) {
577 if (!hadron) hadron = parent; // assumes linear hadron parentage
578 return true;
579 }
580 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
581 }
582 return fromHad;
583 }
584
587
588 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
589 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
590 decltype(thePart->end_vertex()) pVert(nullptr);
591 if (EndVert != nullptr) {
592 do {
593 bool samePart = false;
594 pVert = nullptr;
595 auto outgoing = EndVert->particles_out();
596 auto incoming = EndVert->particles_in();
597 for (const auto& itrDaug: outgoing) {
598 if (!itrDaug) continue;
599 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
600 // brem on generator level for tau
601 (outgoing.size() == 1 && incoming.size() == 1 &&
603 itrDaug->pdg_id() == thePart->pdg_id()) {
604 samePart = true;
605 pVert = itrDaug->end_vertex();
606 }
607 }
608 if (samePart) EndVert = pVert;
609 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
610 }
611 return EndVert;
612 }
613
615
616 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
617 if (!theVert) return {};
618 decltype(theVert->particles_out()) finalStatePart;
619 auto outgoing = theVert->particles_out();
620 for (const auto& thePart: outgoing) {
621 if (!thePart) continue;
622 finalStatePart.push_back(thePart);
623 if (isStable(thePart)) continue;
624 V pVert = findSimulatedEndVertex(thePart);
625 if (pVert == theVert) break; // to prevent Sherpa loop
626 if (pVert != nullptr) {
627 auto vecPart = findFinalStateParticles<V>(pVert);
628 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
629 }
630 }
631 return finalStatePart;
632 }
633
634}
635#endif

◆ isHardScatteringVertex()

template<class T>
bool MC::isHardScatteringVertex ( T pVert)

Function to classify the vertex as hard scattering vertex.

AV: This is MCtruthClassifier legacy. Note that this function willnot capture some cases of the HardScattering vertices. The function should be improved in the future. This can be used for HepMC3::GenVertexPtr, HepMC3::ConstGenVertexPtr or xAOD::TruthVertex*

Definition at line 186 of file HepMCHelpers.h.

186 {
187 if (pVert == nullptr) return false;
188 T pV = pVert;
189 int numOfPartIn(0);
190 int pdg(0);
191
192 do {
193 pVert = pV;
194 auto incoming = pVert->particles_in();
195 numOfPartIn = incoming.size();
196 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
197 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
198
199 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
200
201 if (numOfPartIn == 2) {
202 auto incoming = pVert->particles_in();
203 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
204 }
205 return false;
206}

◆ isHeavyBaryon()

template<class T>
bool MC::isHeavyBaryon ( const T & p)
inline

Definition at line 933 of file HepMCHelpers.h.

954{
955inline
956auto particles_in (const HepMC::GenVertex* p) {
957 return std::ranges::subrange (p->particles_in_const_begin(),
958 p->particles_in_const_end());
959}
960}
961#endif
962
963namespace MC
964{
965 template <class VTX>
966 auto particles_in (const VTX* p) { return p->particles_in(); }
967 template <class VTX>
968 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
969
970 namespace Pythia8
971 {
973 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
974
975 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
976
977 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
978 }
979
980#include "AtlasPID.h"
981
983 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
984
986 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
987
989 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
990
992 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
993
995 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
996
998 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
999
1001 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1002
1004 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1005
1007 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1008
1010 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1011
1015 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1016 const auto vertex = p->end_vertex();
1017 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1018 }
1019
1021 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1022
1024 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1025 const int apid = std::abs(p->pdg_id());
1026 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1027 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1028 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1029 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1030 return false;
1031 }
1032
1034
1035 template <class T> T findMother(T thePart) {
1036 auto partOriVert = thePart->production_vertex();
1037 if (!partOriVert) return nullptr;
1038
1039 long partPDG = thePart->pdg_id();
1040 long MotherPDG(0);
1041
1042 auto MothOriVert = partOriVert;
1043 MothOriVert = nullptr;
1044 T theMoth(nullptr);
1045
1046 size_t itr = 0;
1047 do {
1048 if (itr != 0) partOriVert = MothOriVert;
1049 for ( const auto& p : particles_in(partOriVert) ) {
1050 theMoth = p;
1051 if (!theMoth) continue;
1052 MotherPDG = theMoth->pdg_id();
1053 MothOriVert = theMoth->production_vertex();
1054 if (MotherPDG == partPDG) break;
1055 }
1056 itr++;
1057 if (itr > 100) {
1058 break;
1059 }
1060 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1061 MothOriVert != partOriVert);
1062 return theMoth;
1063 }
1064
1066
1067 template <class C, class T> T findMatching(C TruthContainer, T p) {
1068 T ptrPart = nullptr;
1069 if (!p) return ptrPart;
1070 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1071 for (T truthParticle : *TruthContainer) {
1072 if (HepMC::is_sim_descendant(p,truthParticle)) {
1073 ptrPart = truthParticle;
1074 break;
1075 }
1076 }
1077 }
1078 else {
1079 for (T truthParticle : TruthContainer) {
1080 if (HepMC::is_sim_descendant(p,truthParticle)) {
1081 ptrPart = truthParticle;
1082 break;
1083 }
1084 }
1085 }
1086 return ptrPart;
1087 }
1089
1090 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1091 auto prodVtx = thePart->production_vertex();
1092 if (!prodVtx) return;
1093 for (const auto& theMother: prodVtx->particles_in()) {
1094 if (!theMother) continue;
1095 allancestors.insert(theMother);
1096 findParticleAncestors(theMother, allancestors);
1097 }
1098 }
1099
1101
1102 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1103 auto endVtx = thePart->end_vertex();
1104 if (!endVtx) return;
1105 for (const auto& theDaughter: endVtx->particles_out()) {
1106 if (!theDaughter) continue;
1107 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1108 allstabledescendants.insert(theDaughter);
1109 }
1110 findParticleStableDescendants(theDaughter, allstabledescendants);
1111 }
1112 }
1113
1117
1118 template <class T> bool isHardScatteringVertex(T pVert) {
1119 if (pVert == nullptr) return false;
1120 T pV = pVert;
1121 int numOfPartIn(0);
1122 int pdg(0);
1123
1124 do {
1125 pVert = pV;
1126 auto incoming = pVert->particles_in();
1127 numOfPartIn = incoming.size();
1128 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1129 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1130
1131 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1132
1133 if (numOfPartIn == 2) {
1134 auto incoming = pVert->particles_in();
1135 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1136 }
1137 return false;
1138}
1139
1143
1144 template <class T, class U>
1145 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1146 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1147 auto vtx = p->production_vertex();
1148 if (!vtx) return false;
1149 bool fromHad = false;
1150 for ( const auto& parent : particles_in(vtx) ) {
1151 if (!parent) continue;
1152 // should this really go into parton-level territory?
1153 // probably depends where BSM particles are being decayed
1154 fromBSM |= isBSM(parent);
1155 if (!isPhysical(parent)) return false;
1156 fromTau |= isTau(parent);
1157 if (isHadron(parent)&&!isBeam(parent)) {
1158 if (!hadron) hadron = parent; // assumes linear hadron parentage
1159 return true;
1160 }
1161 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1162 }
1163 return fromHad;
1164 }
1165
1168
1169 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1170 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1171 decltype(thePart->end_vertex()) pVert(nullptr);
1172 if (EndVert != nullptr) {
1173 do {
1174 bool samePart = false;
1175 pVert = nullptr;
1176 auto outgoing = EndVert->particles_out();
1177 auto incoming = EndVert->particles_in();
1178 for (const auto& itrDaug: outgoing) {
1179 if (!itrDaug) continue;
1180 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1181 // brem on generator level for tau
1182 (outgoing.size() == 1 && incoming.size() == 1 &&
1184 itrDaug->pdg_id() == thePart->pdg_id()) {
1185 samePart = true;
1186 pVert = itrDaug->end_vertex();
1187 }
1188 }
1189 if (samePart) EndVert = pVert;
1190 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1191 }
1192 return EndVert;
1193 }
1194
1196
1197 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1198 if (!theVert) return {};
1199 decltype(theVert->particles_out()) finalStatePart;
1200 auto outgoing = theVert->particles_out();
1201 for (const auto& thePart: outgoing) {
1202 if (!thePart) continue;
1203 finalStatePart.push_back(thePart);
1204 if (isStable(thePart)) continue;
1205 V pVert = findSimulatedEndVertex(thePart);
1206 if (pVert == theVert) break; // to prevent Sherpa loop
1207 if (pVert != nullptr) {
1208 auto vecPart = findFinalStateParticles<V>(pVert);
1209 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1210 }
1211 }
1212 return finalStatePart;
1213 }
1214
1215}
1216#endif

◆ isHeavyBoson() [1/2]

template<>
bool MC::isHeavyBoson ( const int & p)
inline

Definition at line 388 of file HepMCHelpers.h.

409{
410inline
411auto particles_in (const HepMC::GenVertex* p) {
412 return std::ranges::subrange (p->particles_in_const_begin(),
413 p->particles_in_const_end());
414}
415}
416#endif
417
418namespace MC
419{
420 template <class VTX>
421 auto particles_in (const VTX* p) { return p->particles_in(); }
422 template <class VTX>
423 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
424
425 namespace Pythia8
426 {
428 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
429
430 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
431
432 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
433 }
434
435#include "AtlasPID.h"
436
438 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
439
441 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
442
444 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
445
447 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
448
450 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
451
453 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
454
456 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
457
459 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
460
462 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
463
465 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
466
470 template <class T> inline bool isStableOrSimDecayed(const T& p) {
471 const auto vertex = p->end_vertex();
472 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
473 }
474
476 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
477
479 template <class T> inline bool isSpecialNonInteracting(const T& p) {
480 const int apid = std::abs(p->pdg_id());
481 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
482 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
483 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
484 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
485 return false;
486 }
487
489
490 template <class T> T findMother(T thePart) {
491 auto partOriVert = thePart->production_vertex();
492 if (!partOriVert) return nullptr;
493
494 long partPDG = thePart->pdg_id();
495 long MotherPDG(0);
496
497 auto MothOriVert = partOriVert;
498 MothOriVert = nullptr;
499 T theMoth(nullptr);
500
501 size_t itr = 0;
502 do {
503 if (itr != 0) partOriVert = MothOriVert;
504 for ( const auto& p : particles_in(partOriVert) ) {
505 theMoth = p;
506 if (!theMoth) continue;
507 MotherPDG = theMoth->pdg_id();
508 MothOriVert = theMoth->production_vertex();
509 if (MotherPDG == partPDG) break;
510 }
511 itr++;
512 if (itr > 100) {
513 break;
514 }
515 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
516 MothOriVert != partOriVert);
517 return theMoth;
518 }
519
521
522 template <class C, class T> T findMatching(C TruthContainer, T p) {
523 T ptrPart = nullptr;
524 if (!p) return ptrPart;
525 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
526 for (T truthParticle : *TruthContainer) {
527 if (HepMC::is_sim_descendant(p,truthParticle)) {
528 ptrPart = truthParticle;
529 break;
530 }
531 }
532 }
533 else {
534 for (T truthParticle : TruthContainer) {
535 if (HepMC::is_sim_descendant(p,truthParticle)) {
536 ptrPart = truthParticle;
537 break;
538 }
539 }
540 }
541 return ptrPart;
542 }
544
545 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
546 auto prodVtx = thePart->production_vertex();
547 if (!prodVtx) return;
548 for (const auto& theMother: prodVtx->particles_in()) {
549 if (!theMother) continue;
550 allancestors.insert(theMother);
551 findParticleAncestors(theMother, allancestors);
552 }
553 }
554
556
557 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
558 auto endVtx = thePart->end_vertex();
559 if (!endVtx) return;
560 for (const auto& theDaughter: endVtx->particles_out()) {
561 if (!theDaughter) continue;
562 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
563 allstabledescendants.insert(theDaughter);
564 }
565 findParticleStableDescendants(theDaughter, allstabledescendants);
566 }
567 }
568
572
573 template <class T> bool isHardScatteringVertex(T pVert) {
574 if (pVert == nullptr) return false;
575 T pV = pVert;
576 int numOfPartIn(0);
577 int pdg(0);
578
579 do {
580 pVert = pV;
581 auto incoming = pVert->particles_in();
582 numOfPartIn = incoming.size();
583 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
584 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
585
586 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
587
588 if (numOfPartIn == 2) {
589 auto incoming = pVert->particles_in();
590 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
591 }
592 return false;
593}
594
598
599 template <class T, class U>
600 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
601 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
602 auto vtx = p->production_vertex();
603 if (!vtx) return false;
604 bool fromHad = false;
605 for ( const auto& parent : particles_in(vtx) ) {
606 if (!parent) continue;
607 // should this really go into parton-level territory?
608 // probably depends where BSM particles are being decayed
609 fromBSM |= isBSM(parent);
610 if (!isPhysical(parent)) return false;
611 fromTau |= isTau(parent);
612 if (isHadron(parent)&&!isBeam(parent)) {
613 if (!hadron) hadron = parent; // assumes linear hadron parentage
614 return true;
615 }
616 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
617 }
618 return fromHad;
619 }
620
623
624 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
625 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
626 decltype(thePart->end_vertex()) pVert(nullptr);
627 if (EndVert != nullptr) {
628 do {
629 bool samePart = false;
630 pVert = nullptr;
631 auto outgoing = EndVert->particles_out();
632 auto incoming = EndVert->particles_in();
633 for (const auto& itrDaug: outgoing) {
634 if (!itrDaug) continue;
635 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
636 // brem on generator level for tau
637 (outgoing.size() == 1 && incoming.size() == 1 &&
639 itrDaug->pdg_id() == thePart->pdg_id()) {
640 samePart = true;
641 pVert = itrDaug->end_vertex();
642 }
643 }
644 if (samePart) EndVert = pVert;
645 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
646 }
647 return EndVert;
648 }
649
651
652 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
653 if (!theVert) return {};
654 decltype(theVert->particles_out()) finalStatePart;
655 auto outgoing = theVert->particles_out();
656 for (const auto& thePart: outgoing) {
657 if (!thePart) continue;
658 finalStatePart.push_back(thePart);
659 if (isStable(thePart)) continue;
660 V pVert = findSimulatedEndVertex(thePart);
661 if (pVert == theVert) break; // to prevent Sherpa loop
662 if (pVert != nullptr) {
663 auto vecPart = findFinalStateParticles<V>(pVert);
664 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
665 }
666 }
667 return finalStatePart;
668 }
669
670}
671#endif

◆ isHeavyBoson() [2/2]

template<class T>
bool MC::isHeavyBoson ( const T & p)
inline

APID: Additional "Heavy"/"prime" versions of W and Z bosons (Used in MCTruthClassifier)

Definition at line 387 of file HepMCHelpers.h.

408{
409inline
410auto particles_in (const HepMC::GenVertex* p) {
411 return std::ranges::subrange (p->particles_in_const_begin(),
412 p->particles_in_const_end());
413}
414}
415#endif
416
417namespace MC
418{
419 template <class VTX>
420 auto particles_in (const VTX* p) { return p->particles_in(); }
421 template <class VTX>
422 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
423
424 namespace Pythia8
425 {
427 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
428
429 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
430
431 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
432 }
433
434#include "AtlasPID.h"
435
437 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
438
440 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
441
443 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
444
446 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
447
449 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
450
452 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
453
455 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
456
458 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
459
461 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
462
464 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
465
469 template <class T> inline bool isStableOrSimDecayed(const T& p) {
470 const auto vertex = p->end_vertex();
471 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
472 }
473
475 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
476
478 template <class T> inline bool isSpecialNonInteracting(const T& p) {
479 const int apid = std::abs(p->pdg_id());
480 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
481 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
482 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
483 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
484 return false;
485 }
486
488
489 template <class T> T findMother(T thePart) {
490 auto partOriVert = thePart->production_vertex();
491 if (!partOriVert) return nullptr;
492
493 long partPDG = thePart->pdg_id();
494 long MotherPDG(0);
495
496 auto MothOriVert = partOriVert;
497 MothOriVert = nullptr;
498 T theMoth(nullptr);
499
500 size_t itr = 0;
501 do {
502 if (itr != 0) partOriVert = MothOriVert;
503 for ( const auto& p : particles_in(partOriVert) ) {
504 theMoth = p;
505 if (!theMoth) continue;
506 MotherPDG = theMoth->pdg_id();
507 MothOriVert = theMoth->production_vertex();
508 if (MotherPDG == partPDG) break;
509 }
510 itr++;
511 if (itr > 100) {
512 break;
513 }
514 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
515 MothOriVert != partOriVert);
516 return theMoth;
517 }
518
520
521 template <class C, class T> T findMatching(C TruthContainer, T p) {
522 T ptrPart = nullptr;
523 if (!p) return ptrPart;
524 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
525 for (T truthParticle : *TruthContainer) {
526 if (HepMC::is_sim_descendant(p,truthParticle)) {
527 ptrPart = truthParticle;
528 break;
529 }
530 }
531 }
532 else {
533 for (T truthParticle : TruthContainer) {
534 if (HepMC::is_sim_descendant(p,truthParticle)) {
535 ptrPart = truthParticle;
536 break;
537 }
538 }
539 }
540 return ptrPart;
541 }
543
544 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
545 auto prodVtx = thePart->production_vertex();
546 if (!prodVtx) return;
547 for (const auto& theMother: prodVtx->particles_in()) {
548 if (!theMother) continue;
549 allancestors.insert(theMother);
550 findParticleAncestors(theMother, allancestors);
551 }
552 }
553
555
556 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
557 auto endVtx = thePart->end_vertex();
558 if (!endVtx) return;
559 for (const auto& theDaughter: endVtx->particles_out()) {
560 if (!theDaughter) continue;
561 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
562 allstabledescendants.insert(theDaughter);
563 }
564 findParticleStableDescendants(theDaughter, allstabledescendants);
565 }
566 }
567
571
572 template <class T> bool isHardScatteringVertex(T pVert) {
573 if (pVert == nullptr) return false;
574 T pV = pVert;
575 int numOfPartIn(0);
576 int pdg(0);
577
578 do {
579 pVert = pV;
580 auto incoming = pVert->particles_in();
581 numOfPartIn = incoming.size();
582 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
583 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
584
585 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
586
587 if (numOfPartIn == 2) {
588 auto incoming = pVert->particles_in();
589 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
590 }
591 return false;
592}
593
597
598 template <class T, class U>
599 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
600 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
601 auto vtx = p->production_vertex();
602 if (!vtx) return false;
603 bool fromHad = false;
604 for ( const auto& parent : particles_in(vtx) ) {
605 if (!parent) continue;
606 // should this really go into parton-level territory?
607 // probably depends where BSM particles are being decayed
608 fromBSM |= isBSM(parent);
609 if (!isPhysical(parent)) return false;
610 fromTau |= isTau(parent);
611 if (isHadron(parent)&&!isBeam(parent)) {
612 if (!hadron) hadron = parent; // assumes linear hadron parentage
613 return true;
614 }
615 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
616 }
617 return fromHad;
618 }
619
622
623 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
624 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
625 decltype(thePart->end_vertex()) pVert(nullptr);
626 if (EndVert != nullptr) {
627 do {
628 bool samePart = false;
629 pVert = nullptr;
630 auto outgoing = EndVert->particles_out();
631 auto incoming = EndVert->particles_in();
632 for (const auto& itrDaug: outgoing) {
633 if (!itrDaug) continue;
634 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
635 // brem on generator level for tau
636 (outgoing.size() == 1 && incoming.size() == 1 &&
638 itrDaug->pdg_id() == thePart->pdg_id()) {
639 samePart = true;
640 pVert = itrDaug->end_vertex();
641 }
642 }
643 if (samePart) EndVert = pVert;
644 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
645 }
646 return EndVert;
647 }
648
650
651 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
652 if (!theVert) return {};
653 decltype(theVert->particles_out()) finalStatePart;
654 auto outgoing = theVert->particles_out();
655 for (const auto& thePart: outgoing) {
656 if (!thePart) continue;
657 finalStatePart.push_back(thePart);
658 if (isStable(thePart)) continue;
659 V pVert = findSimulatedEndVertex(thePart);
660 if (pVert == theVert) break; // to prevent Sherpa loop
661 if (pVert != nullptr) {
662 auto vecPart = findFinalStateParticles<V>(pVert);
663 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
664 }
665 }
666 return finalStatePart;
667 }
668
669}
670#endif

◆ isHeavyHadron()

template<class T>
bool MC::isHeavyHadron ( const T & p)
inline

Definition at line 910 of file HepMCHelpers.h.

931{
932inline
933auto particles_in (const HepMC::GenVertex* p) {
934 return std::ranges::subrange (p->particles_in_const_begin(),
935 p->particles_in_const_end());
936}
937}
938#endif
939
940namespace MC
941{
942 template <class VTX>
943 auto particles_in (const VTX* p) { return p->particles_in(); }
944 template <class VTX>
945 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
946
947 namespace Pythia8
948 {
950 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
951
952 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
953
954 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
955 }
956
957#include "AtlasPID.h"
958
960 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
961
963 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
964
966 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
967
969 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
970
972 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
973
975 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
976
978 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
979
981 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
982
984 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
985
987 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
988
992 template <class T> inline bool isStableOrSimDecayed(const T& p) {
993 const auto vertex = p->end_vertex();
994 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
995 }
996
998 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
999
1001 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1002 const int apid = std::abs(p->pdg_id());
1003 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1004 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1005 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1006 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1007 return false;
1008 }
1009
1011
1012 template <class T> T findMother(T thePart) {
1013 auto partOriVert = thePart->production_vertex();
1014 if (!partOriVert) return nullptr;
1015
1016 long partPDG = thePart->pdg_id();
1017 long MotherPDG(0);
1018
1019 auto MothOriVert = partOriVert;
1020 MothOriVert = nullptr;
1021 T theMoth(nullptr);
1022
1023 size_t itr = 0;
1024 do {
1025 if (itr != 0) partOriVert = MothOriVert;
1026 for ( const auto& p : particles_in(partOriVert) ) {
1027 theMoth = p;
1028 if (!theMoth) continue;
1029 MotherPDG = theMoth->pdg_id();
1030 MothOriVert = theMoth->production_vertex();
1031 if (MotherPDG == partPDG) break;
1032 }
1033 itr++;
1034 if (itr > 100) {
1035 break;
1036 }
1037 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1038 MothOriVert != partOriVert);
1039 return theMoth;
1040 }
1041
1043
1044 template <class C, class T> T findMatching(C TruthContainer, T p) {
1045 T ptrPart = nullptr;
1046 if (!p) return ptrPart;
1047 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1048 for (T truthParticle : *TruthContainer) {
1049 if (HepMC::is_sim_descendant(p,truthParticle)) {
1050 ptrPart = truthParticle;
1051 break;
1052 }
1053 }
1054 }
1055 else {
1056 for (T truthParticle : TruthContainer) {
1057 if (HepMC::is_sim_descendant(p,truthParticle)) {
1058 ptrPart = truthParticle;
1059 break;
1060 }
1061 }
1062 }
1063 return ptrPart;
1064 }
1066
1067 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1068 auto prodVtx = thePart->production_vertex();
1069 if (!prodVtx) return;
1070 for (const auto& theMother: prodVtx->particles_in()) {
1071 if (!theMother) continue;
1072 allancestors.insert(theMother);
1073 findParticleAncestors(theMother, allancestors);
1074 }
1075 }
1076
1078
1079 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1080 auto endVtx = thePart->end_vertex();
1081 if (!endVtx) return;
1082 for (const auto& theDaughter: endVtx->particles_out()) {
1083 if (!theDaughter) continue;
1084 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1085 allstabledescendants.insert(theDaughter);
1086 }
1087 findParticleStableDescendants(theDaughter, allstabledescendants);
1088 }
1089 }
1090
1094
1095 template <class T> bool isHardScatteringVertex(T pVert) {
1096 if (pVert == nullptr) return false;
1097 T pV = pVert;
1098 int numOfPartIn(0);
1099 int pdg(0);
1100
1101 do {
1102 pVert = pV;
1103 auto incoming = pVert->particles_in();
1104 numOfPartIn = incoming.size();
1105 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1106 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1107
1108 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1109
1110 if (numOfPartIn == 2) {
1111 auto incoming = pVert->particles_in();
1112 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1113 }
1114 return false;
1115}
1116
1120
1121 template <class T, class U>
1122 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1123 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1124 auto vtx = p->production_vertex();
1125 if (!vtx) return false;
1126 bool fromHad = false;
1127 for ( const auto& parent : particles_in(vtx) ) {
1128 if (!parent) continue;
1129 // should this really go into parton-level territory?
1130 // probably depends where BSM particles are being decayed
1131 fromBSM |= isBSM(parent);
1132 if (!isPhysical(parent)) return false;
1133 fromTau |= isTau(parent);
1134 if (isHadron(parent)&&!isBeam(parent)) {
1135 if (!hadron) hadron = parent; // assumes linear hadron parentage
1136 return true;
1137 }
1138 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1139 }
1140 return fromHad;
1141 }
1142
1145
1146 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1147 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1148 decltype(thePart->end_vertex()) pVert(nullptr);
1149 if (EndVert != nullptr) {
1150 do {
1151 bool samePart = false;
1152 pVert = nullptr;
1153 auto outgoing = EndVert->particles_out();
1154 auto incoming = EndVert->particles_in();
1155 for (const auto& itrDaug: outgoing) {
1156 if (!itrDaug) continue;
1157 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1158 // brem on generator level for tau
1159 (outgoing.size() == 1 && incoming.size() == 1 &&
1161 itrDaug->pdg_id() == thePart->pdg_id()) {
1162 samePart = true;
1163 pVert = itrDaug->end_vertex();
1164 }
1165 }
1166 if (samePart) EndVert = pVert;
1167 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1168 }
1169 return EndVert;
1170 }
1171
1173
1174 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1175 if (!theVert) return {};
1176 decltype(theVert->particles_out()) finalStatePart;
1177 auto outgoing = theVert->particles_out();
1178 for (const auto& thePart: outgoing) {
1179 if (!thePart) continue;
1180 finalStatePart.push_back(thePart);
1181 if (isStable(thePart)) continue;
1182 V pVert = findSimulatedEndVertex(thePart);
1183 if (pVert == theVert) break; // to prevent Sherpa loop
1184 if (pVert != nullptr) {
1185 auto vecPart = findFinalStateParticles<V>(pVert);
1186 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1187 }
1188 }
1189 return finalStatePart;
1190 }
1191
1192}
1193#endif

◆ isHeavyMeson()

template<class T>
bool MC::isHeavyMeson ( const T & p)
inline

Definition at line 917 of file HepMCHelpers.h.

938{
939inline
940auto particles_in (const HepMC::GenVertex* p) {
941 return std::ranges::subrange (p->particles_in_const_begin(),
942 p->particles_in_const_end());
943}
944}
945#endif
946
947namespace MC
948{
949 template <class VTX>
950 auto particles_in (const VTX* p) { return p->particles_in(); }
951 template <class VTX>
952 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
953
954 namespace Pythia8
955 {
957 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
958
959 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
960
961 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
962 }
963
964#include "AtlasPID.h"
965
967 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
968
970 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
971
973 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
974
976 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
977
979 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
980
982 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
983
985 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
986
988 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
989
991 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
992
994 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
995
999 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1000 const auto vertex = p->end_vertex();
1001 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1002 }
1003
1005 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1006
1008 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1009 const int apid = std::abs(p->pdg_id());
1010 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1011 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1012 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1013 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1014 return false;
1015 }
1016
1018
1019 template <class T> T findMother(T thePart) {
1020 auto partOriVert = thePart->production_vertex();
1021 if (!partOriVert) return nullptr;
1022
1023 long partPDG = thePart->pdg_id();
1024 long MotherPDG(0);
1025
1026 auto MothOriVert = partOriVert;
1027 MothOriVert = nullptr;
1028 T theMoth(nullptr);
1029
1030 size_t itr = 0;
1031 do {
1032 if (itr != 0) partOriVert = MothOriVert;
1033 for ( const auto& p : particles_in(partOriVert) ) {
1034 theMoth = p;
1035 if (!theMoth) continue;
1036 MotherPDG = theMoth->pdg_id();
1037 MothOriVert = theMoth->production_vertex();
1038 if (MotherPDG == partPDG) break;
1039 }
1040 itr++;
1041 if (itr > 100) {
1042 break;
1043 }
1044 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1045 MothOriVert != partOriVert);
1046 return theMoth;
1047 }
1048
1050
1051 template <class C, class T> T findMatching(C TruthContainer, T p) {
1052 T ptrPart = nullptr;
1053 if (!p) return ptrPart;
1054 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1055 for (T truthParticle : *TruthContainer) {
1056 if (HepMC::is_sim_descendant(p,truthParticle)) {
1057 ptrPart = truthParticle;
1058 break;
1059 }
1060 }
1061 }
1062 else {
1063 for (T truthParticle : TruthContainer) {
1064 if (HepMC::is_sim_descendant(p,truthParticle)) {
1065 ptrPart = truthParticle;
1066 break;
1067 }
1068 }
1069 }
1070 return ptrPart;
1071 }
1073
1074 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1075 auto prodVtx = thePart->production_vertex();
1076 if (!prodVtx) return;
1077 for (const auto& theMother: prodVtx->particles_in()) {
1078 if (!theMother) continue;
1079 allancestors.insert(theMother);
1080 findParticleAncestors(theMother, allancestors);
1081 }
1082 }
1083
1085
1086 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1087 auto endVtx = thePart->end_vertex();
1088 if (!endVtx) return;
1089 for (const auto& theDaughter: endVtx->particles_out()) {
1090 if (!theDaughter) continue;
1091 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1092 allstabledescendants.insert(theDaughter);
1093 }
1094 findParticleStableDescendants(theDaughter, allstabledescendants);
1095 }
1096 }
1097
1101
1102 template <class T> bool isHardScatteringVertex(T pVert) {
1103 if (pVert == nullptr) return false;
1104 T pV = pVert;
1105 int numOfPartIn(0);
1106 int pdg(0);
1107
1108 do {
1109 pVert = pV;
1110 auto incoming = pVert->particles_in();
1111 numOfPartIn = incoming.size();
1112 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1113 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1114
1115 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1116
1117 if (numOfPartIn == 2) {
1118 auto incoming = pVert->particles_in();
1119 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1120 }
1121 return false;
1122}
1123
1127
1128 template <class T, class U>
1129 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1130 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1131 auto vtx = p->production_vertex();
1132 if (!vtx) return false;
1133 bool fromHad = false;
1134 for ( const auto& parent : particles_in(vtx) ) {
1135 if (!parent) continue;
1136 // should this really go into parton-level territory?
1137 // probably depends where BSM particles are being decayed
1138 fromBSM |= isBSM(parent);
1139 if (!isPhysical(parent)) return false;
1140 fromTau |= isTau(parent);
1141 if (isHadron(parent)&&!isBeam(parent)) {
1142 if (!hadron) hadron = parent; // assumes linear hadron parentage
1143 return true;
1144 }
1145 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1146 }
1147 return fromHad;
1148 }
1149
1152
1153 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1154 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1155 decltype(thePart->end_vertex()) pVert(nullptr);
1156 if (EndVert != nullptr) {
1157 do {
1158 bool samePart = false;
1159 pVert = nullptr;
1160 auto outgoing = EndVert->particles_out();
1161 auto incoming = EndVert->particles_in();
1162 for (const auto& itrDaug: outgoing) {
1163 if (!itrDaug) continue;
1164 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1165 // brem on generator level for tau
1166 (outgoing.size() == 1 && incoming.size() == 1 &&
1168 itrDaug->pdg_id() == thePart->pdg_id()) {
1169 samePart = true;
1170 pVert = itrDaug->end_vertex();
1171 }
1172 }
1173 if (samePart) EndVert = pVert;
1174 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1175 }
1176 return EndVert;
1177 }
1178
1180
1181 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1182 if (!theVert) return {};
1183 decltype(theVert->particles_out()) finalStatePart;
1184 auto outgoing = theVert->particles_out();
1185 for (const auto& thePart: outgoing) {
1186 if (!thePart) continue;
1187 finalStatePart.push_back(thePart);
1188 if (isStable(thePart)) continue;
1189 V pVert = findSimulatedEndVertex(thePart);
1190 if (pVert == theVert) break; // to prevent Sherpa loop
1191 if (pVert != nullptr) {
1192 auto vecPart = findFinalStateParticles<V>(pVert);
1193 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1194 }
1195 }
1196 return finalStatePart;
1197 }
1198
1199}
1200#endif

◆ isHiddenValley() [1/3]

template<>
bool MC::isHiddenValley ( const DecodedPID & p)
inline

Definition at line 671 of file HepMCHelpers.h.

692 {
693inline
694auto particles_in (const HepMC::GenVertex* p) {
695 return std::ranges::subrange (p->particles_in_const_begin(),
696 p->particles_in_const_end());
697}
698}
699#endif
700
701namespace MC
702{
703 template <class VTX>
704 auto particles_in (const VTX* p) { return p->particles_in(); }
705 template <class VTX>
706 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
707
708 namespace Pythia8
709 {
711 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
712
713 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
714
715 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
716 }
717
718#include "AtlasPID.h"
719
721 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
722
724 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
725
727 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
728
730 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
731
733 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
734
736 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
737
739 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
740
742 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
743
745 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
746
748 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
749
753 template <class T> inline bool isStableOrSimDecayed(const T& p) {
754 const auto vertex = p->end_vertex();
755 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
756 }
757
759 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
760
762 template <class T> inline bool isSpecialNonInteracting(const T& p) {
763 const int apid = std::abs(p->pdg_id());
764 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
765 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
766 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
767 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
768 return false;
769 }
770
772
773 template <class T> T findMother(T thePart) {
774 auto partOriVert = thePart->production_vertex();
775 if (!partOriVert) return nullptr;
776
777 long partPDG = thePart->pdg_id();
778 long MotherPDG(0);
779
780 auto MothOriVert = partOriVert;
781 MothOriVert = nullptr;
782 T theMoth(nullptr);
783
784 size_t itr = 0;
785 do {
786 if (itr != 0) partOriVert = MothOriVert;
787 for ( const auto& p : particles_in(partOriVert) ) {
788 theMoth = p;
789 if (!theMoth) continue;
790 MotherPDG = theMoth->pdg_id();
791 MothOriVert = theMoth->production_vertex();
792 if (MotherPDG == partPDG) break;
793 }
794 itr++;
795 if (itr > 100) {
796 break;
797 }
798 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
799 MothOriVert != partOriVert);
800 return theMoth;
801 }
802
804
805 template <class C, class T> T findMatching(C TruthContainer, T p) {
806 T ptrPart = nullptr;
807 if (!p) return ptrPart;
808 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
809 for (T truthParticle : *TruthContainer) {
810 if (HepMC::is_sim_descendant(p,truthParticle)) {
811 ptrPart = truthParticle;
812 break;
813 }
814 }
815 }
816 else {
817 for (T truthParticle : TruthContainer) {
818 if (HepMC::is_sim_descendant(p,truthParticle)) {
819 ptrPart = truthParticle;
820 break;
821 }
822 }
823 }
824 return ptrPart;
825 }
827
828 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
829 auto prodVtx = thePart->production_vertex();
830 if (!prodVtx) return;
831 for (const auto& theMother: prodVtx->particles_in()) {
832 if (!theMother) continue;
833 allancestors.insert(theMother);
834 findParticleAncestors(theMother, allancestors);
835 }
836 }
837
839
840 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
841 auto endVtx = thePart->end_vertex();
842 if (!endVtx) return;
843 for (const auto& theDaughter: endVtx->particles_out()) {
844 if (!theDaughter) continue;
845 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
846 allstabledescendants.insert(theDaughter);
847 }
848 findParticleStableDescendants(theDaughter, allstabledescendants);
849 }
850 }
851
855
856 template <class T> bool isHardScatteringVertex(T pVert) {
857 if (pVert == nullptr) return false;
858 T pV = pVert;
859 int numOfPartIn(0);
860 int pdg(0);
861
862 do {
863 pVert = pV;
864 auto incoming = pVert->particles_in();
865 numOfPartIn = incoming.size();
866 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
867 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
868
869 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
870
871 if (numOfPartIn == 2) {
872 auto incoming = pVert->particles_in();
873 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
874 }
875 return false;
876}
877
881
882 template <class T, class U>
883 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
884 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
885 auto vtx = p->production_vertex();
886 if (!vtx) return false;
887 bool fromHad = false;
888 for ( const auto& parent : particles_in(vtx) ) {
889 if (!parent) continue;
890 // should this really go into parton-level territory?
891 // probably depends where BSM particles are being decayed
892 fromBSM |= isBSM(parent);
893 if (!isPhysical(parent)) return false;
894 fromTau |= isTau(parent);
895 if (isHadron(parent)&&!isBeam(parent)) {
896 if (!hadron) hadron = parent; // assumes linear hadron parentage
897 return true;
898 }
899 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
900 }
901 return fromHad;
902 }
903
906
907 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
908 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
909 decltype(thePart->end_vertex()) pVert(nullptr);
910 if (EndVert != nullptr) {
911 do {
912 bool samePart = false;
913 pVert = nullptr;
914 auto outgoing = EndVert->particles_out();
915 auto incoming = EndVert->particles_in();
916 for (const auto& itrDaug: outgoing) {
917 if (!itrDaug) continue;
918 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
919 // brem on generator level for tau
920 (outgoing.size() == 1 && incoming.size() == 1 &&
922 itrDaug->pdg_id() == thePart->pdg_id()) {
923 samePart = true;
924 pVert = itrDaug->end_vertex();
925 }
926 }
927 if (samePart) EndVert = pVert;
928 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
929 }
930 return EndVert;
931 }
932
934
935 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
936 if (!theVert) return {};
937 decltype(theVert->particles_out()) finalStatePart;
938 auto outgoing = theVert->particles_out();
939 for (const auto& thePart: outgoing) {
940 if (!thePart) continue;
941 finalStatePart.push_back(thePart);
942 if (isStable(thePart)) continue;
943 V pVert = findSimulatedEndVertex(thePart);
944 if (pVert == theVert) break; // to prevent Sherpa loop
945 if (pVert != nullptr) {
946 auto vecPart = findFinalStateParticles<V>(pVert);
947 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
948 }
949 }
950 return finalStatePart;
951 }
952
953}
954#endif

◆ isHiddenValley() [2/3]

template<>
bool MC::isHiddenValley ( const int & p)
inline

Definition at line 677 of file HepMCHelpers.h.

698{
699inline
700auto particles_in (const HepMC::GenVertex* p) {
701 return std::ranges::subrange (p->particles_in_const_begin(),
702 p->particles_in_const_end());
703}
704}
705#endif
706
707namespace MC
708{
709 template <class VTX>
710 auto particles_in (const VTX* p) { return p->particles_in(); }
711 template <class VTX>
712 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
713
714 namespace Pythia8
715 {
717 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
718
719 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
720
721 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
722 }
723
724#include "AtlasPID.h"
725
727 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
728
730 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
731
733 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
734
736 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
737
739 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
740
742 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
743
745 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
746
748 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
749
751 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
752
754 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
755
759 template <class T> inline bool isStableOrSimDecayed(const T& p) {
760 const auto vertex = p->end_vertex();
761 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
762 }
763
765 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
766
768 template <class T> inline bool isSpecialNonInteracting(const T& p) {
769 const int apid = std::abs(p->pdg_id());
770 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
771 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
772 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
773 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
774 return false;
775 }
776
778
779 template <class T> T findMother(T thePart) {
780 auto partOriVert = thePart->production_vertex();
781 if (!partOriVert) return nullptr;
782
783 long partPDG = thePart->pdg_id();
784 long MotherPDG(0);
785
786 auto MothOriVert = partOriVert;
787 MothOriVert = nullptr;
788 T theMoth(nullptr);
789
790 size_t itr = 0;
791 do {
792 if (itr != 0) partOriVert = MothOriVert;
793 for ( const auto& p : particles_in(partOriVert) ) {
794 theMoth = p;
795 if (!theMoth) continue;
796 MotherPDG = theMoth->pdg_id();
797 MothOriVert = theMoth->production_vertex();
798 if (MotherPDG == partPDG) break;
799 }
800 itr++;
801 if (itr > 100) {
802 break;
803 }
804 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
805 MothOriVert != partOriVert);
806 return theMoth;
807 }
808
810
811 template <class C, class T> T findMatching(C TruthContainer, T p) {
812 T ptrPart = nullptr;
813 if (!p) return ptrPart;
814 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
815 for (T truthParticle : *TruthContainer) {
816 if (HepMC::is_sim_descendant(p,truthParticle)) {
817 ptrPart = truthParticle;
818 break;
819 }
820 }
821 }
822 else {
823 for (T truthParticle : TruthContainer) {
824 if (HepMC::is_sim_descendant(p,truthParticle)) {
825 ptrPart = truthParticle;
826 break;
827 }
828 }
829 }
830 return ptrPart;
831 }
833
834 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
835 auto prodVtx = thePart->production_vertex();
836 if (!prodVtx) return;
837 for (const auto& theMother: prodVtx->particles_in()) {
838 if (!theMother) continue;
839 allancestors.insert(theMother);
840 findParticleAncestors(theMother, allancestors);
841 }
842 }
843
845
846 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
847 auto endVtx = thePart->end_vertex();
848 if (!endVtx) return;
849 for (const auto& theDaughter: endVtx->particles_out()) {
850 if (!theDaughter) continue;
851 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
852 allstabledescendants.insert(theDaughter);
853 }
854 findParticleStableDescendants(theDaughter, allstabledescendants);
855 }
856 }
857
861
862 template <class T> bool isHardScatteringVertex(T pVert) {
863 if (pVert == nullptr) return false;
864 T pV = pVert;
865 int numOfPartIn(0);
866 int pdg(0);
867
868 do {
869 pVert = pV;
870 auto incoming = pVert->particles_in();
871 numOfPartIn = incoming.size();
872 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
873 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
874
875 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
876
877 if (numOfPartIn == 2) {
878 auto incoming = pVert->particles_in();
879 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
880 }
881 return false;
882}
883
887
888 template <class T, class U>
889 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
890 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
891 auto vtx = p->production_vertex();
892 if (!vtx) return false;
893 bool fromHad = false;
894 for ( const auto& parent : particles_in(vtx) ) {
895 if (!parent) continue;
896 // should this really go into parton-level territory?
897 // probably depends where BSM particles are being decayed
898 fromBSM |= isBSM(parent);
899 if (!isPhysical(parent)) return false;
900 fromTau |= isTau(parent);
901 if (isHadron(parent)&&!isBeam(parent)) {
902 if (!hadron) hadron = parent; // assumes linear hadron parentage
903 return true;
904 }
905 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
906 }
907 return fromHad;
908 }
909
912
913 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
914 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
915 decltype(thePart->end_vertex()) pVert(nullptr);
916 if (EndVert != nullptr) {
917 do {
918 bool samePart = false;
919 pVert = nullptr;
920 auto outgoing = EndVert->particles_out();
921 auto incoming = EndVert->particles_in();
922 for (const auto& itrDaug: outgoing) {
923 if (!itrDaug) continue;
924 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
925 // brem on generator level for tau
926 (outgoing.size() == 1 && incoming.size() == 1 &&
928 itrDaug->pdg_id() == thePart->pdg_id()) {
929 samePart = true;
930 pVert = itrDaug->end_vertex();
931 }
932 }
933 if (samePart) EndVert = pVert;
934 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
935 }
936 return EndVert;
937 }
938
940
941 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
942 if (!theVert) return {};
943 decltype(theVert->particles_out()) finalStatePart;
944 auto outgoing = theVert->particles_out();
945 for (const auto& thePart: outgoing) {
946 if (!thePart) continue;
947 finalStatePart.push_back(thePart);
948 if (isStable(thePart)) continue;
949 V pVert = findSimulatedEndVertex(thePart);
950 if (pVert == theVert) break; // to prevent Sherpa loop
951 if (pVert != nullptr) {
952 auto vecPart = findFinalStateParticles<V>(pVert);
953 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
954 }
955 }
956 return finalStatePart;
957 }
958
959}
960#endif

◆ isHiddenValley() [3/3]

template<class T>
bool MC::isHiddenValley ( const T & p)
inline

PDG rule 11k Hidden Valley particles have n = 4 and n_r = 9, and trailing numbers in agreement with their nearest-analog standard particles, as far as possible.

Thus 4900021 is the gauge boson g_v of a confining gauge field, 490000n_{q_v} and 490001n_{l_v} fundamental constituents charged or not under this, 4900022 is the γ_v of a non-confining field, and 4900n_{q_{v1}}n_{q_{v2}}n_J a Hidden Valley meson.

Definition at line 669 of file HepMCHelpers.h.

690{
691inline
692auto particles_in (const HepMC::GenVertex* p) {
693 return std::ranges::subrange (p->particles_in_const_begin(),
694 p->particles_in_const_end());
695}
696}
697#endif
698
699namespace MC
700{
701 template <class VTX>
702 auto particles_in (const VTX* p) { return p->particles_in(); }
703 template <class VTX>
704 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
705
706 namespace Pythia8
707 {
709 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
710
711 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
712
713 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
714 }
715
716#include "AtlasPID.h"
717
719 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
720
722 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
723
725 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
726
728 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
729
731 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
732
734 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
735
737 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
738
740 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
741
743 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
744
746 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
747
751 template <class T> inline bool isStableOrSimDecayed(const T& p) {
752 const auto vertex = p->end_vertex();
753 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
754 }
755
757 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
758
760 template <class T> inline bool isSpecialNonInteracting(const T& p) {
761 const int apid = std::abs(p->pdg_id());
762 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
763 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
764 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
765 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
766 return false;
767 }
768
770
771 template <class T> T findMother(T thePart) {
772 auto partOriVert = thePart->production_vertex();
773 if (!partOriVert) return nullptr;
774
775 long partPDG = thePart->pdg_id();
776 long MotherPDG(0);
777
778 auto MothOriVert = partOriVert;
779 MothOriVert = nullptr;
780 T theMoth(nullptr);
781
782 size_t itr = 0;
783 do {
784 if (itr != 0) partOriVert = MothOriVert;
785 for ( const auto& p : particles_in(partOriVert) ) {
786 theMoth = p;
787 if (!theMoth) continue;
788 MotherPDG = theMoth->pdg_id();
789 MothOriVert = theMoth->production_vertex();
790 if (MotherPDG == partPDG) break;
791 }
792 itr++;
793 if (itr > 100) {
794 break;
795 }
796 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
797 MothOriVert != partOriVert);
798 return theMoth;
799 }
800
802
803 template <class C, class T> T findMatching(C TruthContainer, T p) {
804 T ptrPart = nullptr;
805 if (!p) return ptrPart;
806 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
807 for (T truthParticle : *TruthContainer) {
808 if (HepMC::is_sim_descendant(p,truthParticle)) {
809 ptrPart = truthParticle;
810 break;
811 }
812 }
813 }
814 else {
815 for (T truthParticle : TruthContainer) {
816 if (HepMC::is_sim_descendant(p,truthParticle)) {
817 ptrPart = truthParticle;
818 break;
819 }
820 }
821 }
822 return ptrPart;
823 }
825
826 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
827 auto prodVtx = thePart->production_vertex();
828 if (!prodVtx) return;
829 for (const auto& theMother: prodVtx->particles_in()) {
830 if (!theMother) continue;
831 allancestors.insert(theMother);
832 findParticleAncestors(theMother, allancestors);
833 }
834 }
835
837
838 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
839 auto endVtx = thePart->end_vertex();
840 if (!endVtx) return;
841 for (const auto& theDaughter: endVtx->particles_out()) {
842 if (!theDaughter) continue;
843 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
844 allstabledescendants.insert(theDaughter);
845 }
846 findParticleStableDescendants(theDaughter, allstabledescendants);
847 }
848 }
849
853
854 template <class T> bool isHardScatteringVertex(T pVert) {
855 if (pVert == nullptr) return false;
856 T pV = pVert;
857 int numOfPartIn(0);
858 int pdg(0);
859
860 do {
861 pVert = pV;
862 auto incoming = pVert->particles_in();
863 numOfPartIn = incoming.size();
864 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
865 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
866
867 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
868
869 if (numOfPartIn == 2) {
870 auto incoming = pVert->particles_in();
871 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
872 }
873 return false;
874}
875
879
880 template <class T, class U>
881 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
882 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
883 auto vtx = p->production_vertex();
884 if (!vtx) return false;
885 bool fromHad = false;
886 for ( const auto& parent : particles_in(vtx) ) {
887 if (!parent) continue;
888 // should this really go into parton-level territory?
889 // probably depends where BSM particles are being decayed
890 fromBSM |= isBSM(parent);
891 if (!isPhysical(parent)) return false;
892 fromTau |= isTau(parent);
893 if (isHadron(parent)&&!isBeam(parent)) {
894 if (!hadron) hadron = parent; // assumes linear hadron parentage
895 return true;
896 }
897 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
898 }
899 return fromHad;
900 }
901
904
905 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
906 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
907 decltype(thePart->end_vertex()) pVert(nullptr);
908 if (EndVert != nullptr) {
909 do {
910 bool samePart = false;
911 pVert = nullptr;
912 auto outgoing = EndVert->particles_out();
913 auto incoming = EndVert->particles_in();
914 for (const auto& itrDaug: outgoing) {
915 if (!itrDaug) continue;
916 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
917 // brem on generator level for tau
918 (outgoing.size() == 1 && incoming.size() == 1 &&
920 itrDaug->pdg_id() == thePart->pdg_id()) {
921 samePart = true;
922 pVert = itrDaug->end_vertex();
923 }
924 }
925 if (samePart) EndVert = pVert;
926 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
927 }
928 return EndVert;
929 }
930
932
933 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
934 if (!theVert) return {};
935 decltype(theVert->particles_out()) finalStatePart;
936 auto outgoing = theVert->particles_out();
937 for (const auto& thePart: outgoing) {
938 if (!thePart) continue;
939 finalStatePart.push_back(thePart);
940 if (isStable(thePart)) continue;
941 V pVert = findSimulatedEndVertex(thePart);
942 if (pVert == theVert) break; // to prevent Sherpa loop
943 if (pVert != nullptr) {
944 auto vecPart = findFinalStateParticles<V>(pVert);
945 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
946 }
947 }
948 return finalStatePart;
949 }
950
951}
952#endif

◆ isHiggs() [1/2]

template<>
bool MC::isHiggs ( const int & p)
inline

Definition at line 392 of file HepMCHelpers.h.

413{
414inline
415auto particles_in (const HepMC::GenVertex* p) {
416 return std::ranges::subrange (p->particles_in_const_begin(),
417 p->particles_in_const_end());
418}
419}
420#endif
421
422namespace MC
423{
424 template <class VTX>
425 auto particles_in (const VTX* p) { return p->particles_in(); }
426 template <class VTX>
427 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
428
429 namespace Pythia8
430 {
432 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
433
434 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
435
436 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
437 }
438
439#include "AtlasPID.h"
440
442 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
443
445 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
446
448 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
449
451 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
452
454 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
455
457 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
458
460 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
461
463 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
464
466 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
467
469 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
470
474 template <class T> inline bool isStableOrSimDecayed(const T& p) {
475 const auto vertex = p->end_vertex();
476 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
477 }
478
480 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
481
483 template <class T> inline bool isSpecialNonInteracting(const T& p) {
484 const int apid = std::abs(p->pdg_id());
485 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
486 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
487 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
488 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
489 return false;
490 }
491
493
494 template <class T> T findMother(T thePart) {
495 auto partOriVert = thePart->production_vertex();
496 if (!partOriVert) return nullptr;
497
498 long partPDG = thePart->pdg_id();
499 long MotherPDG(0);
500
501 auto MothOriVert = partOriVert;
502 MothOriVert = nullptr;
503 T theMoth(nullptr);
504
505 size_t itr = 0;
506 do {
507 if (itr != 0) partOriVert = MothOriVert;
508 for ( const auto& p : particles_in(partOriVert) ) {
509 theMoth = p;
510 if (!theMoth) continue;
511 MotherPDG = theMoth->pdg_id();
512 MothOriVert = theMoth->production_vertex();
513 if (MotherPDG == partPDG) break;
514 }
515 itr++;
516 if (itr > 100) {
517 break;
518 }
519 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
520 MothOriVert != partOriVert);
521 return theMoth;
522 }
523
525
526 template <class C, class T> T findMatching(C TruthContainer, T p) {
527 T ptrPart = nullptr;
528 if (!p) return ptrPart;
529 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
530 for (T truthParticle : *TruthContainer) {
531 if (HepMC::is_sim_descendant(p,truthParticle)) {
532 ptrPart = truthParticle;
533 break;
534 }
535 }
536 }
537 else {
538 for (T truthParticle : TruthContainer) {
539 if (HepMC::is_sim_descendant(p,truthParticle)) {
540 ptrPart = truthParticle;
541 break;
542 }
543 }
544 }
545 return ptrPart;
546 }
548
549 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
550 auto prodVtx = thePart->production_vertex();
551 if (!prodVtx) return;
552 for (const auto& theMother: prodVtx->particles_in()) {
553 if (!theMother) continue;
554 allancestors.insert(theMother);
555 findParticleAncestors(theMother, allancestors);
556 }
557 }
558
560
561 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
562 auto endVtx = thePart->end_vertex();
563 if (!endVtx) return;
564 for (const auto& theDaughter: endVtx->particles_out()) {
565 if (!theDaughter) continue;
566 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
567 allstabledescendants.insert(theDaughter);
568 }
569 findParticleStableDescendants(theDaughter, allstabledescendants);
570 }
571 }
572
576
577 template <class T> bool isHardScatteringVertex(T pVert) {
578 if (pVert == nullptr) return false;
579 T pV = pVert;
580 int numOfPartIn(0);
581 int pdg(0);
582
583 do {
584 pVert = pV;
585 auto incoming = pVert->particles_in();
586 numOfPartIn = incoming.size();
587 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
588 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
589
590 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
591
592 if (numOfPartIn == 2) {
593 auto incoming = pVert->particles_in();
594 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
595 }
596 return false;
597}
598
602
603 template <class T, class U>
604 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
605 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
606 auto vtx = p->production_vertex();
607 if (!vtx) return false;
608 bool fromHad = false;
609 for ( const auto& parent : particles_in(vtx) ) {
610 if (!parent) continue;
611 // should this really go into parton-level territory?
612 // probably depends where BSM particles are being decayed
613 fromBSM |= isBSM(parent);
614 if (!isPhysical(parent)) return false;
615 fromTau |= isTau(parent);
616 if (isHadron(parent)&&!isBeam(parent)) {
617 if (!hadron) hadron = parent; // assumes linear hadron parentage
618 return true;
619 }
620 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
621 }
622 return fromHad;
623 }
624
627
628 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
629 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
630 decltype(thePart->end_vertex()) pVert(nullptr);
631 if (EndVert != nullptr) {
632 do {
633 bool samePart = false;
634 pVert = nullptr;
635 auto outgoing = EndVert->particles_out();
636 auto incoming = EndVert->particles_in();
637 for (const auto& itrDaug: outgoing) {
638 if (!itrDaug) continue;
639 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
640 // brem on generator level for tau
641 (outgoing.size() == 1 && incoming.size() == 1 &&
643 itrDaug->pdg_id() == thePart->pdg_id()) {
644 samePart = true;
645 pVert = itrDaug->end_vertex();
646 }
647 }
648 if (samePart) EndVert = pVert;
649 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
650 }
651 return EndVert;
652 }
653
655
656 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
657 if (!theVert) return {};
658 decltype(theVert->particles_out()) finalStatePart;
659 auto outgoing = theVert->particles_out();
660 for (const auto& thePart: outgoing) {
661 if (!thePart) continue;
662 finalStatePart.push_back(thePart);
663 if (isStable(thePart)) continue;
664 V pVert = findSimulatedEndVertex(thePart);
665 if (pVert == theVert) break; // to prevent Sherpa loop
666 if (pVert != nullptr) {
667 auto vecPart = findFinalStateParticles<V>(pVert);
668 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
669 }
670 }
671 return finalStatePart;
672 }
673
674}
675#endif

◆ isHiggs() [2/2]

template<class T>
bool MC::isHiggs ( const T & p)
inline

APID: HIGGS boson is only one particle.

Definition at line 391 of file HepMCHelpers.h.

412{
413inline
414auto particles_in (const HepMC::GenVertex* p) {
415 return std::ranges::subrange (p->particles_in_const_begin(),
416 p->particles_in_const_end());
417}
418}
419#endif
420
421namespace MC
422{
423 template <class VTX>
424 auto particles_in (const VTX* p) { return p->particles_in(); }
425 template <class VTX>
426 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
427
428 namespace Pythia8
429 {
431 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
432
433 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
434
435 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
436 }
437
438#include "AtlasPID.h"
439
441 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
442
444 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
445
447 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
448
450 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
451
453 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
454
456 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
457
459 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
460
462 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
463
465 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
466
468 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
469
473 template <class T> inline bool isStableOrSimDecayed(const T& p) {
474 const auto vertex = p->end_vertex();
475 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
476 }
477
479 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
480
482 template <class T> inline bool isSpecialNonInteracting(const T& p) {
483 const int apid = std::abs(p->pdg_id());
484 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
485 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
486 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
487 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
488 return false;
489 }
490
492
493 template <class T> T findMother(T thePart) {
494 auto partOriVert = thePart->production_vertex();
495 if (!partOriVert) return nullptr;
496
497 long partPDG = thePart->pdg_id();
498 long MotherPDG(0);
499
500 auto MothOriVert = partOriVert;
501 MothOriVert = nullptr;
502 T theMoth(nullptr);
503
504 size_t itr = 0;
505 do {
506 if (itr != 0) partOriVert = MothOriVert;
507 for ( const auto& p : particles_in(partOriVert) ) {
508 theMoth = p;
509 if (!theMoth) continue;
510 MotherPDG = theMoth->pdg_id();
511 MothOriVert = theMoth->production_vertex();
512 if (MotherPDG == partPDG) break;
513 }
514 itr++;
515 if (itr > 100) {
516 break;
517 }
518 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
519 MothOriVert != partOriVert);
520 return theMoth;
521 }
522
524
525 template <class C, class T> T findMatching(C TruthContainer, T p) {
526 T ptrPart = nullptr;
527 if (!p) return ptrPart;
528 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
529 for (T truthParticle : *TruthContainer) {
530 if (HepMC::is_sim_descendant(p,truthParticle)) {
531 ptrPart = truthParticle;
532 break;
533 }
534 }
535 }
536 else {
537 for (T truthParticle : TruthContainer) {
538 if (HepMC::is_sim_descendant(p,truthParticle)) {
539 ptrPart = truthParticle;
540 break;
541 }
542 }
543 }
544 return ptrPart;
545 }
547
548 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
549 auto prodVtx = thePart->production_vertex();
550 if (!prodVtx) return;
551 for (const auto& theMother: prodVtx->particles_in()) {
552 if (!theMother) continue;
553 allancestors.insert(theMother);
554 findParticleAncestors(theMother, allancestors);
555 }
556 }
557
559
560 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
561 auto endVtx = thePart->end_vertex();
562 if (!endVtx) return;
563 for (const auto& theDaughter: endVtx->particles_out()) {
564 if (!theDaughter) continue;
565 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
566 allstabledescendants.insert(theDaughter);
567 }
568 findParticleStableDescendants(theDaughter, allstabledescendants);
569 }
570 }
571
575
576 template <class T> bool isHardScatteringVertex(T pVert) {
577 if (pVert == nullptr) return false;
578 T pV = pVert;
579 int numOfPartIn(0);
580 int pdg(0);
581
582 do {
583 pVert = pV;
584 auto incoming = pVert->particles_in();
585 numOfPartIn = incoming.size();
586 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
587 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
588
589 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
590
591 if (numOfPartIn == 2) {
592 auto incoming = pVert->particles_in();
593 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
594 }
595 return false;
596}
597
601
602 template <class T, class U>
603 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
604 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
605 auto vtx = p->production_vertex();
606 if (!vtx) return false;
607 bool fromHad = false;
608 for ( const auto& parent : particles_in(vtx) ) {
609 if (!parent) continue;
610 // should this really go into parton-level territory?
611 // probably depends where BSM particles are being decayed
612 fromBSM |= isBSM(parent);
613 if (!isPhysical(parent)) return false;
614 fromTau |= isTau(parent);
615 if (isHadron(parent)&&!isBeam(parent)) {
616 if (!hadron) hadron = parent; // assumes linear hadron parentage
617 return true;
618 }
619 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
620 }
621 return fromHad;
622 }
623
626
627 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
628 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
629 decltype(thePart->end_vertex()) pVert(nullptr);
630 if (EndVert != nullptr) {
631 do {
632 bool samePart = false;
633 pVert = nullptr;
634 auto outgoing = EndVert->particles_out();
635 auto incoming = EndVert->particles_in();
636 for (const auto& itrDaug: outgoing) {
637 if (!itrDaug) continue;
638 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
639 // brem on generator level for tau
640 (outgoing.size() == 1 && incoming.size() == 1 &&
642 itrDaug->pdg_id() == thePart->pdg_id()) {
643 samePart = true;
644 pVert = itrDaug->end_vertex();
645 }
646 }
647 if (samePart) EndVert = pVert;
648 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
649 }
650 return EndVert;
651 }
652
654
655 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
656 if (!theVert) return {};
657 decltype(theVert->particles_out()) finalStatePart;
658 auto outgoing = theVert->particles_out();
659 for (const auto& thePart: outgoing) {
660 if (!thePart) continue;
661 finalStatePart.push_back(thePart);
662 if (isStable(thePart)) continue;
663 V pVert = findSimulatedEndVertex(thePart);
664 if (pVert == theVert) break; // to prevent Sherpa loop
665 if (pVert != nullptr) {
666 auto vecPart = findFinalStateParticles<V>(pVert);
667 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
668 }
669 }
670 return finalStatePart;
671 }
672
673}
674#endif

◆ isInteracting()

template<class T>
bool MC::isInteracting ( const T & p)
inline

Identify if the particle with given PDG ID would not interact with the detector, i.e. not a neutrino or WIMP.

Definition at line 51 of file HepMCHelpers.h.

◆ isKK() [1/3]

template<>
bool MC::isKK ( const DecodedPID & p)
inline

Definition at line 637 of file HepMCHelpers.h.

658{
659inline
660auto particles_in (const HepMC::GenVertex* p) {
661 return std::ranges::subrange (p->particles_in_const_begin(),
662 p->particles_in_const_end());
663}
664}
665#endif
666
667namespace MC
668{
669 template <class VTX>
670 auto particles_in (const VTX* p) { return p->particles_in(); }
671 template <class VTX>
672 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
673
674 namespace Pythia8
675 {
677 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
678
679 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
680
681 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
682 }
683
684#include "AtlasPID.h"
685
687 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
688
690 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
691
693 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
694
696 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
697
699 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
700
702 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
703
705 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
706
708 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
709
711 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
712
714 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
715
719 template <class T> inline bool isStableOrSimDecayed(const T& p) {
720 const auto vertex = p->end_vertex();
721 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
722 }
723
725 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
726
728 template <class T> inline bool isSpecialNonInteracting(const T& p) {
729 const int apid = std::abs(p->pdg_id());
730 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
731 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
732 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
733 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
734 return false;
735 }
736
738
739 template <class T> T findMother(T thePart) {
740 auto partOriVert = thePart->production_vertex();
741 if (!partOriVert) return nullptr;
742
743 long partPDG = thePart->pdg_id();
744 long MotherPDG(0);
745
746 auto MothOriVert = partOriVert;
747 MothOriVert = nullptr;
748 T theMoth(nullptr);
749
750 size_t itr = 0;
751 do {
752 if (itr != 0) partOriVert = MothOriVert;
753 for ( const auto& p : particles_in(partOriVert) ) {
754 theMoth = p;
755 if (!theMoth) continue;
756 MotherPDG = theMoth->pdg_id();
757 MothOriVert = theMoth->production_vertex();
758 if (MotherPDG == partPDG) break;
759 }
760 itr++;
761 if (itr > 100) {
762 break;
763 }
764 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
765 MothOriVert != partOriVert);
766 return theMoth;
767 }
768
770
771 template <class C, class T> T findMatching(C TruthContainer, T p) {
772 T ptrPart = nullptr;
773 if (!p) return ptrPart;
774 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
775 for (T truthParticle : *TruthContainer) {
776 if (HepMC::is_sim_descendant(p,truthParticle)) {
777 ptrPart = truthParticle;
778 break;
779 }
780 }
781 }
782 else {
783 for (T truthParticle : TruthContainer) {
784 if (HepMC::is_sim_descendant(p,truthParticle)) {
785 ptrPart = truthParticle;
786 break;
787 }
788 }
789 }
790 return ptrPart;
791 }
793
794 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
795 auto prodVtx = thePart->production_vertex();
796 if (!prodVtx) return;
797 for (const auto& theMother: prodVtx->particles_in()) {
798 if (!theMother) continue;
799 allancestors.insert(theMother);
800 findParticleAncestors(theMother, allancestors);
801 }
802 }
803
805
806 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
807 auto endVtx = thePart->end_vertex();
808 if (!endVtx) return;
809 for (const auto& theDaughter: endVtx->particles_out()) {
810 if (!theDaughter) continue;
811 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
812 allstabledescendants.insert(theDaughter);
813 }
814 findParticleStableDescendants(theDaughter, allstabledescendants);
815 }
816 }
817
821
822 template <class T> bool isHardScatteringVertex(T pVert) {
823 if (pVert == nullptr) return false;
824 T pV = pVert;
825 int numOfPartIn(0);
826 int pdg(0);
827
828 do {
829 pVert = pV;
830 auto incoming = pVert->particles_in();
831 numOfPartIn = incoming.size();
832 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
833 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
834
835 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
836
837 if (numOfPartIn == 2) {
838 auto incoming = pVert->particles_in();
839 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
840 }
841 return false;
842}
843
847
848 template <class T, class U>
849 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
850 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
851 auto vtx = p->production_vertex();
852 if (!vtx) return false;
853 bool fromHad = false;
854 for ( const auto& parent : particles_in(vtx) ) {
855 if (!parent) continue;
856 // should this really go into parton-level territory?
857 // probably depends where BSM particles are being decayed
858 fromBSM |= isBSM(parent);
859 if (!isPhysical(parent)) return false;
860 fromTau |= isTau(parent);
861 if (isHadron(parent)&&!isBeam(parent)) {
862 if (!hadron) hadron = parent; // assumes linear hadron parentage
863 return true;
864 }
865 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
866 }
867 return fromHad;
868 }
869
872
873 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
874 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
875 decltype(thePart->end_vertex()) pVert(nullptr);
876 if (EndVert != nullptr) {
877 do {
878 bool samePart = false;
879 pVert = nullptr;
880 auto outgoing = EndVert->particles_out();
881 auto incoming = EndVert->particles_in();
882 for (const auto& itrDaug: outgoing) {
883 if (!itrDaug) continue;
884 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
885 // brem on generator level for tau
886 (outgoing.size() == 1 && incoming.size() == 1 &&
888 itrDaug->pdg_id() == thePart->pdg_id()) {
889 samePart = true;
890 pVert = itrDaug->end_vertex();
891 }
892 }
893 if (samePart) EndVert = pVert;
894 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
895 }
896 return EndVert;
897 }
898
900
901 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
902 if (!theVert) return {};
903 decltype(theVert->particles_out()) finalStatePart;
904 auto outgoing = theVert->particles_out();
905 for (const auto& thePart: outgoing) {
906 if (!thePart) continue;
907 finalStatePart.push_back(thePart);
908 if (isStable(thePart)) continue;
909 V pVert = findSimulatedEndVertex(thePart);
910 if (pVert == theVert) break; // to prevent Sherpa loop
911 if (pVert != nullptr) {
912 auto vecPart = findFinalStateParticles<V>(pVert);
913 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
914 }
915 }
916 return finalStatePart;
917 }
918
919}
920#endif

◆ isKK() [2/3]

template<>
bool MC::isKK ( const int & p)
inline

Definition at line 638 of file HepMCHelpers.h.

659{
660inline
661auto particles_in (const HepMC::GenVertex* p) {
662 return std::ranges::subrange (p->particles_in_const_begin(),
663 p->particles_in_const_end());
664}
665}
666#endif
667
668namespace MC
669{
670 template <class VTX>
671 auto particles_in (const VTX* p) { return p->particles_in(); }
672 template <class VTX>
673 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
674
675 namespace Pythia8
676 {
678 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
679
680 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
681
682 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
683 }
684
685#include "AtlasPID.h"
686
688 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
689
691 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
692
694 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
695
697 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
698
700 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
701
703 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
704
706 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
707
709 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
710
712 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
713
715 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
716
720 template <class T> inline bool isStableOrSimDecayed(const T& p) {
721 const auto vertex = p->end_vertex();
722 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
723 }
724
726 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
727
729 template <class T> inline bool isSpecialNonInteracting(const T& p) {
730 const int apid = std::abs(p->pdg_id());
731 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
732 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
733 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
734 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
735 return false;
736 }
737
739
740 template <class T> T findMother(T thePart) {
741 auto partOriVert = thePart->production_vertex();
742 if (!partOriVert) return nullptr;
743
744 long partPDG = thePart->pdg_id();
745 long MotherPDG(0);
746
747 auto MothOriVert = partOriVert;
748 MothOriVert = nullptr;
749 T theMoth(nullptr);
750
751 size_t itr = 0;
752 do {
753 if (itr != 0) partOriVert = MothOriVert;
754 for ( const auto& p : particles_in(partOriVert) ) {
755 theMoth = p;
756 if (!theMoth) continue;
757 MotherPDG = theMoth->pdg_id();
758 MothOriVert = theMoth->production_vertex();
759 if (MotherPDG == partPDG) break;
760 }
761 itr++;
762 if (itr > 100) {
763 break;
764 }
765 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
766 MothOriVert != partOriVert);
767 return theMoth;
768 }
769
771
772 template <class C, class T> T findMatching(C TruthContainer, T p) {
773 T ptrPart = nullptr;
774 if (!p) return ptrPart;
775 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
776 for (T truthParticle : *TruthContainer) {
777 if (HepMC::is_sim_descendant(p,truthParticle)) {
778 ptrPart = truthParticle;
779 break;
780 }
781 }
782 }
783 else {
784 for (T truthParticle : TruthContainer) {
785 if (HepMC::is_sim_descendant(p,truthParticle)) {
786 ptrPart = truthParticle;
787 break;
788 }
789 }
790 }
791 return ptrPart;
792 }
794
795 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
796 auto prodVtx = thePart->production_vertex();
797 if (!prodVtx) return;
798 for (const auto& theMother: prodVtx->particles_in()) {
799 if (!theMother) continue;
800 allancestors.insert(theMother);
801 findParticleAncestors(theMother, allancestors);
802 }
803 }
804
806
807 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
808 auto endVtx = thePart->end_vertex();
809 if (!endVtx) return;
810 for (const auto& theDaughter: endVtx->particles_out()) {
811 if (!theDaughter) continue;
812 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
813 allstabledescendants.insert(theDaughter);
814 }
815 findParticleStableDescendants(theDaughter, allstabledescendants);
816 }
817 }
818
822
823 template <class T> bool isHardScatteringVertex(T pVert) {
824 if (pVert == nullptr) return false;
825 T pV = pVert;
826 int numOfPartIn(0);
827 int pdg(0);
828
829 do {
830 pVert = pV;
831 auto incoming = pVert->particles_in();
832 numOfPartIn = incoming.size();
833 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
834 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
835
836 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
837
838 if (numOfPartIn == 2) {
839 auto incoming = pVert->particles_in();
840 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
841 }
842 return false;
843}
844
848
849 template <class T, class U>
850 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
851 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
852 auto vtx = p->production_vertex();
853 if (!vtx) return false;
854 bool fromHad = false;
855 for ( const auto& parent : particles_in(vtx) ) {
856 if (!parent) continue;
857 // should this really go into parton-level territory?
858 // probably depends where BSM particles are being decayed
859 fromBSM |= isBSM(parent);
860 if (!isPhysical(parent)) return false;
861 fromTau |= isTau(parent);
862 if (isHadron(parent)&&!isBeam(parent)) {
863 if (!hadron) hadron = parent; // assumes linear hadron parentage
864 return true;
865 }
866 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
867 }
868 return fromHad;
869 }
870
873
874 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
875 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
876 decltype(thePart->end_vertex()) pVert(nullptr);
877 if (EndVert != nullptr) {
878 do {
879 bool samePart = false;
880 pVert = nullptr;
881 auto outgoing = EndVert->particles_out();
882 auto incoming = EndVert->particles_in();
883 for (const auto& itrDaug: outgoing) {
884 if (!itrDaug) continue;
885 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
886 // brem on generator level for tau
887 (outgoing.size() == 1 && incoming.size() == 1 &&
889 itrDaug->pdg_id() == thePart->pdg_id()) {
890 samePart = true;
891 pVert = itrDaug->end_vertex();
892 }
893 }
894 if (samePart) EndVert = pVert;
895 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
896 }
897 return EndVert;
898 }
899
901
902 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
903 if (!theVert) return {};
904 decltype(theVert->particles_out()) finalStatePart;
905 auto outgoing = theVert->particles_out();
906 for (const auto& thePart: outgoing) {
907 if (!thePart) continue;
908 finalStatePart.push_back(thePart);
909 if (isStable(thePart)) continue;
910 V pVert = findSimulatedEndVertex(thePart);
911 if (pVert == theVert) break; // to prevent Sherpa loop
912 if (pVert != nullptr) {
913 auto vecPart = findFinalStateParticles<V>(pVert);
914 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
915 }
916 }
917 return finalStatePart;
918 }
919
920}
921#endif

◆ isKK() [3/3]

template<class T>
bool MC::isKK ( const T & p)
inline

PDG rule 11h A black hole in models with extra dimensions has code 5000040.

Kaluza-Klein excitations in models with extra dimensions have n = 5 or n = 6, to distinguish excitations of left-or right-handed fermions or, in case of mixing, the lighter or heavier state (cf. 11d). The non zero nr digit gives the radial excitation number, in scenarios where the level spacing allows these to be distinguished. Should the model also contain supersymmetry, excited SUSY states would be denoted by a nn_r > 0, with n = 1 or 2 as usual. Should some colored states be long-lived enough that hadrons would form around them, the coding strategy of 11g applies, with the initial two nnr digits preserved in the combined code.

Definition at line 636 of file HepMCHelpers.h.

657{
658inline
659auto particles_in (const HepMC::GenVertex* p) {
660 return std::ranges::subrange (p->particles_in_const_begin(),
661 p->particles_in_const_end());
662}
663}
664#endif
665
666namespace MC
667{
668 template <class VTX>
669 auto particles_in (const VTX* p) { return p->particles_in(); }
670 template <class VTX>
671 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
672
673 namespace Pythia8
674 {
676 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
677
678 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
679
680 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
681 }
682
683#include "AtlasPID.h"
684
686 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
687
689 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
690
692 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
693
695 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
696
698 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
699
701 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
702
704 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
705
707 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
708
710 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
711
713 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
714
718 template <class T> inline bool isStableOrSimDecayed(const T& p) {
719 const auto vertex = p->end_vertex();
720 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
721 }
722
724 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
725
727 template <class T> inline bool isSpecialNonInteracting(const T& p) {
728 const int apid = std::abs(p->pdg_id());
729 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
730 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
731 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
732 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
733 return false;
734 }
735
737
738 template <class T> T findMother(T thePart) {
739 auto partOriVert = thePart->production_vertex();
740 if (!partOriVert) return nullptr;
741
742 long partPDG = thePart->pdg_id();
743 long MotherPDG(0);
744
745 auto MothOriVert = partOriVert;
746 MothOriVert = nullptr;
747 T theMoth(nullptr);
748
749 size_t itr = 0;
750 do {
751 if (itr != 0) partOriVert = MothOriVert;
752 for ( const auto& p : particles_in(partOriVert) ) {
753 theMoth = p;
754 if (!theMoth) continue;
755 MotherPDG = theMoth->pdg_id();
756 MothOriVert = theMoth->production_vertex();
757 if (MotherPDG == partPDG) break;
758 }
759 itr++;
760 if (itr > 100) {
761 break;
762 }
763 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
764 MothOriVert != partOriVert);
765 return theMoth;
766 }
767
769
770 template <class C, class T> T findMatching(C TruthContainer, T p) {
771 T ptrPart = nullptr;
772 if (!p) return ptrPart;
773 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
774 for (T truthParticle : *TruthContainer) {
775 if (HepMC::is_sim_descendant(p,truthParticle)) {
776 ptrPart = truthParticle;
777 break;
778 }
779 }
780 }
781 else {
782 for (T truthParticle : TruthContainer) {
783 if (HepMC::is_sim_descendant(p,truthParticle)) {
784 ptrPart = truthParticle;
785 break;
786 }
787 }
788 }
789 return ptrPart;
790 }
792
793 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
794 auto prodVtx = thePart->production_vertex();
795 if (!prodVtx) return;
796 for (const auto& theMother: prodVtx->particles_in()) {
797 if (!theMother) continue;
798 allancestors.insert(theMother);
799 findParticleAncestors(theMother, allancestors);
800 }
801 }
802
804
805 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
806 auto endVtx = thePart->end_vertex();
807 if (!endVtx) return;
808 for (const auto& theDaughter: endVtx->particles_out()) {
809 if (!theDaughter) continue;
810 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
811 allstabledescendants.insert(theDaughter);
812 }
813 findParticleStableDescendants(theDaughter, allstabledescendants);
814 }
815 }
816
820
821 template <class T> bool isHardScatteringVertex(T pVert) {
822 if (pVert == nullptr) return false;
823 T pV = pVert;
824 int numOfPartIn(0);
825 int pdg(0);
826
827 do {
828 pVert = pV;
829 auto incoming = pVert->particles_in();
830 numOfPartIn = incoming.size();
831 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
832 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
833
834 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
835
836 if (numOfPartIn == 2) {
837 auto incoming = pVert->particles_in();
838 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
839 }
840 return false;
841}
842
846
847 template <class T, class U>
848 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
849 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
850 auto vtx = p->production_vertex();
851 if (!vtx) return false;
852 bool fromHad = false;
853 for ( const auto& parent : particles_in(vtx) ) {
854 if (!parent) continue;
855 // should this really go into parton-level territory?
856 // probably depends where BSM particles are being decayed
857 fromBSM |= isBSM(parent);
858 if (!isPhysical(parent)) return false;
859 fromTau |= isTau(parent);
860 if (isHadron(parent)&&!isBeam(parent)) {
861 if (!hadron) hadron = parent; // assumes linear hadron parentage
862 return true;
863 }
864 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
865 }
866 return fromHad;
867 }
868
871
872 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
873 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
874 decltype(thePart->end_vertex()) pVert(nullptr);
875 if (EndVert != nullptr) {
876 do {
877 bool samePart = false;
878 pVert = nullptr;
879 auto outgoing = EndVert->particles_out();
880 auto incoming = EndVert->particles_in();
881 for (const auto& itrDaug: outgoing) {
882 if (!itrDaug) continue;
883 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
884 // brem on generator level for tau
885 (outgoing.size() == 1 && incoming.size() == 1 &&
887 itrDaug->pdg_id() == thePart->pdg_id()) {
888 samePart = true;
889 pVert = itrDaug->end_vertex();
890 }
891 }
892 if (samePart) EndVert = pVert;
893 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
894 }
895 return EndVert;
896 }
897
899
900 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
901 if (!theVert) return {};
902 decltype(theVert->particles_out()) finalStatePart;
903 auto outgoing = theVert->particles_out();
904 for (const auto& thePart: outgoing) {
905 if (!thePart) continue;
906 finalStatePart.push_back(thePart);
907 if (isStable(thePart)) continue;
908 V pVert = findSimulatedEndVertex(thePart);
909 if (pVert == theVert) break; // to prevent Sherpa loop
910 if (pVert != nullptr) {
911 auto vecPart = findFinalStateParticles<V>(pVert);
912 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
913 }
914 }
915 return finalStatePart;
916 }
917
918}
919#endif

◆ isLepton() [1/3]

template<>
bool MC::isLepton ( const DecodedPID & p)
inline

Definition at line 192 of file HepMCHelpers.h.

192{

◆ isLepton() [2/3]

template<>
bool MC::isLepton ( const int & p)
inline

Definition at line 191 of file HepMCHelpers.h.

◆ isLepton() [3/3]

template<class T>
bool MC::isLepton ( const T & p)
inline

APID: the fourth generation leptons are leptons.

Definition at line 190 of file HepMCHelpers.h.

◆ isLeptoQuark() [1/2]

template<>
bool MC::isLeptoQuark ( const int & p)
inline

Definition at line 410 of file HepMCHelpers.h.

431{
432inline
433auto particles_in (const HepMC::GenVertex* p) {
434 return std::ranges::subrange (p->particles_in_const_begin(),
435 p->particles_in_const_end());
436}
437}
438#endif
439
440namespace MC
441{
442 template <class VTX>
443 auto particles_in (const VTX* p) { return p->particles_in(); }
444 template <class VTX>
445 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
446
447 namespace Pythia8
448 {
450 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
451
452 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
453
454 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
455 }
456
457#include "AtlasPID.h"
458
460 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
461
463 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
464
466 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
467
469 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
470
472 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
473
475 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
476
478 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
479
481 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
482
484 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
485
487 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
488
492 template <class T> inline bool isStableOrSimDecayed(const T& p) {
493 const auto vertex = p->end_vertex();
494 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
495 }
496
498 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
499
501 template <class T> inline bool isSpecialNonInteracting(const T& p) {
502 const int apid = std::abs(p->pdg_id());
503 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
504 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
505 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
506 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
507 return false;
508 }
509
511
512 template <class T> T findMother(T thePart) {
513 auto partOriVert = thePart->production_vertex();
514 if (!partOriVert) return nullptr;
515
516 long partPDG = thePart->pdg_id();
517 long MotherPDG(0);
518
519 auto MothOriVert = partOriVert;
520 MothOriVert = nullptr;
521 T theMoth(nullptr);
522
523 size_t itr = 0;
524 do {
525 if (itr != 0) partOriVert = MothOriVert;
526 for ( const auto& p : particles_in(partOriVert) ) {
527 theMoth = p;
528 if (!theMoth) continue;
529 MotherPDG = theMoth->pdg_id();
530 MothOriVert = theMoth->production_vertex();
531 if (MotherPDG == partPDG) break;
532 }
533 itr++;
534 if (itr > 100) {
535 break;
536 }
537 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
538 MothOriVert != partOriVert);
539 return theMoth;
540 }
541
543
544 template <class C, class T> T findMatching(C TruthContainer, T p) {
545 T ptrPart = nullptr;
546 if (!p) return ptrPart;
547 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
548 for (T truthParticle : *TruthContainer) {
549 if (HepMC::is_sim_descendant(p,truthParticle)) {
550 ptrPart = truthParticle;
551 break;
552 }
553 }
554 }
555 else {
556 for (T truthParticle : TruthContainer) {
557 if (HepMC::is_sim_descendant(p,truthParticle)) {
558 ptrPart = truthParticle;
559 break;
560 }
561 }
562 }
563 return ptrPart;
564 }
566
567 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
568 auto prodVtx = thePart->production_vertex();
569 if (!prodVtx) return;
570 for (const auto& theMother: prodVtx->particles_in()) {
571 if (!theMother) continue;
572 allancestors.insert(theMother);
573 findParticleAncestors(theMother, allancestors);
574 }
575 }
576
578
579 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
580 auto endVtx = thePart->end_vertex();
581 if (!endVtx) return;
582 for (const auto& theDaughter: endVtx->particles_out()) {
583 if (!theDaughter) continue;
584 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
585 allstabledescendants.insert(theDaughter);
586 }
587 findParticleStableDescendants(theDaughter, allstabledescendants);
588 }
589 }
590
594
595 template <class T> bool isHardScatteringVertex(T pVert) {
596 if (pVert == nullptr) return false;
597 T pV = pVert;
598 int numOfPartIn(0);
599 int pdg(0);
600
601 do {
602 pVert = pV;
603 auto incoming = pVert->particles_in();
604 numOfPartIn = incoming.size();
605 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
606 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
607
608 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
609
610 if (numOfPartIn == 2) {
611 auto incoming = pVert->particles_in();
612 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
613 }
614 return false;
615}
616
620
621 template <class T, class U>
622 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
623 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
624 auto vtx = p->production_vertex();
625 if (!vtx) return false;
626 bool fromHad = false;
627 for ( const auto& parent : particles_in(vtx) ) {
628 if (!parent) continue;
629 // should this really go into parton-level territory?
630 // probably depends where BSM particles are being decayed
631 fromBSM |= isBSM(parent);
632 if (!isPhysical(parent)) return false;
633 fromTau |= isTau(parent);
634 if (isHadron(parent)&&!isBeam(parent)) {
635 if (!hadron) hadron = parent; // assumes linear hadron parentage
636 return true;
637 }
638 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
639 }
640 return fromHad;
641 }
642
645
646 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
647 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
648 decltype(thePart->end_vertex()) pVert(nullptr);
649 if (EndVert != nullptr) {
650 do {
651 bool samePart = false;
652 pVert = nullptr;
653 auto outgoing = EndVert->particles_out();
654 auto incoming = EndVert->particles_in();
655 for (const auto& itrDaug: outgoing) {
656 if (!itrDaug) continue;
657 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
658 // brem on generator level for tau
659 (outgoing.size() == 1 && incoming.size() == 1 &&
661 itrDaug->pdg_id() == thePart->pdg_id()) {
662 samePart = true;
663 pVert = itrDaug->end_vertex();
664 }
665 }
666 if (samePart) EndVert = pVert;
667 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
668 }
669 return EndVert;
670 }
671
673
674 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
675 if (!theVert) return {};
676 decltype(theVert->particles_out()) finalStatePart;
677 auto outgoing = theVert->particles_out();
678 for (const auto& thePart: outgoing) {
679 if (!thePart) continue;
680 finalStatePart.push_back(thePart);
681 if (isStable(thePart)) continue;
682 V pVert = findSimulatedEndVertex(thePart);
683 if (pVert == theVert) break; // to prevent Sherpa loop
684 if (pVert != nullptr) {
685 auto vecPart = findFinalStateParticles<V>(pVert);
686 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
687 }
688 }
689 return finalStatePart;
690 }
691
692}
693#endif

◆ isLeptoQuark() [2/2]

template<class T>
bool MC::isLeptoQuark ( const T & p)
inline

PDG rule 11c: “One-of-a-kind” exotic particles are assigned numbers in the range 41–80.

The subrange 61-80 can be used for new heavier fermions in generic models, where partners to the SM fermions would have codes offset by 60. If required, however, other assignments could be made.

Definition at line 409 of file HepMCHelpers.h.

430{
431inline
432auto particles_in (const HepMC::GenVertex* p) {
433 return std::ranges::subrange (p->particles_in_const_begin(),
434 p->particles_in_const_end());
435}
436}
437#endif
438
439namespace MC
440{
441 template <class VTX>
442 auto particles_in (const VTX* p) { return p->particles_in(); }
443 template <class VTX>
444 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
445
446 namespace Pythia8
447 {
449 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
450
451 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
452
453 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
454 }
455
456#include "AtlasPID.h"
457
459 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
460
462 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
463
465 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
466
468 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
469
471 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
472
474 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
475
477 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
478
480 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
481
483 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
484
486 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
487
491 template <class T> inline bool isStableOrSimDecayed(const T& p) {
492 const auto vertex = p->end_vertex();
493 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
494 }
495
497 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
498
500 template <class T> inline bool isSpecialNonInteracting(const T& p) {
501 const int apid = std::abs(p->pdg_id());
502 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
503 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
504 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
505 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
506 return false;
507 }
508
510
511 template <class T> T findMother(T thePart) {
512 auto partOriVert = thePart->production_vertex();
513 if (!partOriVert) return nullptr;
514
515 long partPDG = thePart->pdg_id();
516 long MotherPDG(0);
517
518 auto MothOriVert = partOriVert;
519 MothOriVert = nullptr;
520 T theMoth(nullptr);
521
522 size_t itr = 0;
523 do {
524 if (itr != 0) partOriVert = MothOriVert;
525 for ( const auto& p : particles_in(partOriVert) ) {
526 theMoth = p;
527 if (!theMoth) continue;
528 MotherPDG = theMoth->pdg_id();
529 MothOriVert = theMoth->production_vertex();
530 if (MotherPDG == partPDG) break;
531 }
532 itr++;
533 if (itr > 100) {
534 break;
535 }
536 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
537 MothOriVert != partOriVert);
538 return theMoth;
539 }
540
542
543 template <class C, class T> T findMatching(C TruthContainer, T p) {
544 T ptrPart = nullptr;
545 if (!p) return ptrPart;
546 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
547 for (T truthParticle : *TruthContainer) {
548 if (HepMC::is_sim_descendant(p,truthParticle)) {
549 ptrPart = truthParticle;
550 break;
551 }
552 }
553 }
554 else {
555 for (T truthParticle : TruthContainer) {
556 if (HepMC::is_sim_descendant(p,truthParticle)) {
557 ptrPart = truthParticle;
558 break;
559 }
560 }
561 }
562 return ptrPart;
563 }
565
566 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
567 auto prodVtx = thePart->production_vertex();
568 if (!prodVtx) return;
569 for (const auto& theMother: prodVtx->particles_in()) {
570 if (!theMother) continue;
571 allancestors.insert(theMother);
572 findParticleAncestors(theMother, allancestors);
573 }
574 }
575
577
578 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
579 auto endVtx = thePart->end_vertex();
580 if (!endVtx) return;
581 for (const auto& theDaughter: endVtx->particles_out()) {
582 if (!theDaughter) continue;
583 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
584 allstabledescendants.insert(theDaughter);
585 }
586 findParticleStableDescendants(theDaughter, allstabledescendants);
587 }
588 }
589
593
594 template <class T> bool isHardScatteringVertex(T pVert) {
595 if (pVert == nullptr) return false;
596 T pV = pVert;
597 int numOfPartIn(0);
598 int pdg(0);
599
600 do {
601 pVert = pV;
602 auto incoming = pVert->particles_in();
603 numOfPartIn = incoming.size();
604 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
605 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
606
607 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
608
609 if (numOfPartIn == 2) {
610 auto incoming = pVert->particles_in();
611 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
612 }
613 return false;
614}
615
619
620 template <class T, class U>
621 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
622 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
623 auto vtx = p->production_vertex();
624 if (!vtx) return false;
625 bool fromHad = false;
626 for ( const auto& parent : particles_in(vtx) ) {
627 if (!parent) continue;
628 // should this really go into parton-level territory?
629 // probably depends where BSM particles are being decayed
630 fromBSM |= isBSM(parent);
631 if (!isPhysical(parent)) return false;
632 fromTau |= isTau(parent);
633 if (isHadron(parent)&&!isBeam(parent)) {
634 if (!hadron) hadron = parent; // assumes linear hadron parentage
635 return true;
636 }
637 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
638 }
639 return fromHad;
640 }
641
644
645 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
646 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
647 decltype(thePart->end_vertex()) pVert(nullptr);
648 if (EndVert != nullptr) {
649 do {
650 bool samePart = false;
651 pVert = nullptr;
652 auto outgoing = EndVert->particles_out();
653 auto incoming = EndVert->particles_in();
654 for (const auto& itrDaug: outgoing) {
655 if (!itrDaug) continue;
656 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
657 // brem on generator level for tau
658 (outgoing.size() == 1 && incoming.size() == 1 &&
660 itrDaug->pdg_id() == thePart->pdg_id()) {
661 samePart = true;
662 pVert = itrDaug->end_vertex();
663 }
664 }
665 if (samePart) EndVert = pVert;
666 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
667 }
668 return EndVert;
669 }
670
672
673 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
674 if (!theVert) return {};
675 decltype(theVert->particles_out()) finalStatePart;
676 auto outgoing = theVert->particles_out();
677 for (const auto& thePart: outgoing) {
678 if (!thePart) continue;
679 finalStatePart.push_back(thePart);
680 if (isStable(thePart)) continue;
681 V pVert = findSimulatedEndVertex(thePart);
682 if (pVert == theVert) break; // to prevent Sherpa loop
683 if (pVert != nullptr) {
684 auto vecPart = findFinalStateParticles<V>(pVert);
685 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
686 }
687 }
688 return finalStatePart;
689 }
690
691}
692#endif

◆ isLightBaryon()

template<class T>
bool MC::isLightBaryon ( const T & p)
inline

Definition at line 932 of file HepMCHelpers.h.

953{
954inline
955auto particles_in (const HepMC::GenVertex* p) {
956 return std::ranges::subrange (p->particles_in_const_begin(),
957 p->particles_in_const_end());
958}
959}
960#endif
961
962namespace MC
963{
964 template <class VTX>
965 auto particles_in (const VTX* p) { return p->particles_in(); }
966 template <class VTX>
967 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
968
969 namespace Pythia8
970 {
972 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
973
974 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
975
976 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
977 }
978
979#include "AtlasPID.h"
980
982 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
983
985 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
986
988 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
989
991 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
992
994 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
995
997 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
998
1000 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1001
1003 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1004
1006 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1007
1009 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1010
1014 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1015 const auto vertex = p->end_vertex();
1016 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1017 }
1018
1020 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1021
1023 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1024 const int apid = std::abs(p->pdg_id());
1025 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1026 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1027 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1028 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1029 return false;
1030 }
1031
1033
1034 template <class T> T findMother(T thePart) {
1035 auto partOriVert = thePart->production_vertex();
1036 if (!partOriVert) return nullptr;
1037
1038 long partPDG = thePart->pdg_id();
1039 long MotherPDG(0);
1040
1041 auto MothOriVert = partOriVert;
1042 MothOriVert = nullptr;
1043 T theMoth(nullptr);
1044
1045 size_t itr = 0;
1046 do {
1047 if (itr != 0) partOriVert = MothOriVert;
1048 for ( const auto& p : particles_in(partOriVert) ) {
1049 theMoth = p;
1050 if (!theMoth) continue;
1051 MotherPDG = theMoth->pdg_id();
1052 MothOriVert = theMoth->production_vertex();
1053 if (MotherPDG == partPDG) break;
1054 }
1055 itr++;
1056 if (itr > 100) {
1057 break;
1058 }
1059 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1060 MothOriVert != partOriVert);
1061 return theMoth;
1062 }
1063
1065
1066 template <class C, class T> T findMatching(C TruthContainer, T p) {
1067 T ptrPart = nullptr;
1068 if (!p) return ptrPart;
1069 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1070 for (T truthParticle : *TruthContainer) {
1071 if (HepMC::is_sim_descendant(p,truthParticle)) {
1072 ptrPart = truthParticle;
1073 break;
1074 }
1075 }
1076 }
1077 else {
1078 for (T truthParticle : TruthContainer) {
1079 if (HepMC::is_sim_descendant(p,truthParticle)) {
1080 ptrPart = truthParticle;
1081 break;
1082 }
1083 }
1084 }
1085 return ptrPart;
1086 }
1088
1089 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1090 auto prodVtx = thePart->production_vertex();
1091 if (!prodVtx) return;
1092 for (const auto& theMother: prodVtx->particles_in()) {
1093 if (!theMother) continue;
1094 allancestors.insert(theMother);
1095 findParticleAncestors(theMother, allancestors);
1096 }
1097 }
1098
1100
1101 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1102 auto endVtx = thePart->end_vertex();
1103 if (!endVtx) return;
1104 for (const auto& theDaughter: endVtx->particles_out()) {
1105 if (!theDaughter) continue;
1106 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1107 allstabledescendants.insert(theDaughter);
1108 }
1109 findParticleStableDescendants(theDaughter, allstabledescendants);
1110 }
1111 }
1112
1116
1117 template <class T> bool isHardScatteringVertex(T pVert) {
1118 if (pVert == nullptr) return false;
1119 T pV = pVert;
1120 int numOfPartIn(0);
1121 int pdg(0);
1122
1123 do {
1124 pVert = pV;
1125 auto incoming = pVert->particles_in();
1126 numOfPartIn = incoming.size();
1127 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1128 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1129
1130 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1131
1132 if (numOfPartIn == 2) {
1133 auto incoming = pVert->particles_in();
1134 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1135 }
1136 return false;
1137}
1138
1142
1143 template <class T, class U>
1144 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1145 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1146 auto vtx = p->production_vertex();
1147 if (!vtx) return false;
1148 bool fromHad = false;
1149 for ( const auto& parent : particles_in(vtx) ) {
1150 if (!parent) continue;
1151 // should this really go into parton-level territory?
1152 // probably depends where BSM particles are being decayed
1153 fromBSM |= isBSM(parent);
1154 if (!isPhysical(parent)) return false;
1155 fromTau |= isTau(parent);
1156 if (isHadron(parent)&&!isBeam(parent)) {
1157 if (!hadron) hadron = parent; // assumes linear hadron parentage
1158 return true;
1159 }
1160 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1161 }
1162 return fromHad;
1163 }
1164
1167
1168 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1169 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1170 decltype(thePart->end_vertex()) pVert(nullptr);
1171 if (EndVert != nullptr) {
1172 do {
1173 bool samePart = false;
1174 pVert = nullptr;
1175 auto outgoing = EndVert->particles_out();
1176 auto incoming = EndVert->particles_in();
1177 for (const auto& itrDaug: outgoing) {
1178 if (!itrDaug) continue;
1179 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1180 // brem on generator level for tau
1181 (outgoing.size() == 1 && incoming.size() == 1 &&
1183 itrDaug->pdg_id() == thePart->pdg_id()) {
1184 samePart = true;
1185 pVert = itrDaug->end_vertex();
1186 }
1187 }
1188 if (samePart) EndVert = pVert;
1189 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1190 }
1191 return EndVert;
1192 }
1193
1195
1196 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1197 if (!theVert) return {};
1198 decltype(theVert->particles_out()) finalStatePart;
1199 auto outgoing = theVert->particles_out();
1200 for (const auto& thePart: outgoing) {
1201 if (!thePart) continue;
1202 finalStatePart.push_back(thePart);
1203 if (isStable(thePart)) continue;
1204 V pVert = findSimulatedEndVertex(thePart);
1205 if (pVert == theVert) break; // to prevent Sherpa loop
1206 if (pVert != nullptr) {
1207 auto vecPart = findFinalStateParticles<V>(pVert);
1208 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1209 }
1210 }
1211 return finalStatePart;
1212 }
1213
1214}
1215#endif

◆ isLightHadron()

template<class T>
bool MC::isLightHadron ( const T & p)
inline

Definition at line 909 of file HepMCHelpers.h.

930{
931inline
932auto particles_in (const HepMC::GenVertex* p) {
933 return std::ranges::subrange (p->particles_in_const_begin(),
934 p->particles_in_const_end());
935}
936}
937#endif
938
939namespace MC
940{
941 template <class VTX>
942 auto particles_in (const VTX* p) { return p->particles_in(); }
943 template <class VTX>
944 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
945
946 namespace Pythia8
947 {
949 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
950
951 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
952
953 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
954 }
955
956#include "AtlasPID.h"
957
959 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
960
962 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
963
965 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
966
968 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
969
971 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
972
974 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
975
977 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
978
980 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
981
983 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
984
986 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
987
991 template <class T> inline bool isStableOrSimDecayed(const T& p) {
992 const auto vertex = p->end_vertex();
993 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
994 }
995
997 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
998
1000 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1001 const int apid = std::abs(p->pdg_id());
1002 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1003 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1004 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1005 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1006 return false;
1007 }
1008
1010
1011 template <class T> T findMother(T thePart) {
1012 auto partOriVert = thePart->production_vertex();
1013 if (!partOriVert) return nullptr;
1014
1015 long partPDG = thePart->pdg_id();
1016 long MotherPDG(0);
1017
1018 auto MothOriVert = partOriVert;
1019 MothOriVert = nullptr;
1020 T theMoth(nullptr);
1021
1022 size_t itr = 0;
1023 do {
1024 if (itr != 0) partOriVert = MothOriVert;
1025 for ( const auto& p : particles_in(partOriVert) ) {
1026 theMoth = p;
1027 if (!theMoth) continue;
1028 MotherPDG = theMoth->pdg_id();
1029 MothOriVert = theMoth->production_vertex();
1030 if (MotherPDG == partPDG) break;
1031 }
1032 itr++;
1033 if (itr > 100) {
1034 break;
1035 }
1036 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1037 MothOriVert != partOriVert);
1038 return theMoth;
1039 }
1040
1042
1043 template <class C, class T> T findMatching(C TruthContainer, T p) {
1044 T ptrPart = nullptr;
1045 if (!p) return ptrPart;
1046 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1047 for (T truthParticle : *TruthContainer) {
1048 if (HepMC::is_sim_descendant(p,truthParticle)) {
1049 ptrPart = truthParticle;
1050 break;
1051 }
1052 }
1053 }
1054 else {
1055 for (T truthParticle : TruthContainer) {
1056 if (HepMC::is_sim_descendant(p,truthParticle)) {
1057 ptrPart = truthParticle;
1058 break;
1059 }
1060 }
1061 }
1062 return ptrPart;
1063 }
1065
1066 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1067 auto prodVtx = thePart->production_vertex();
1068 if (!prodVtx) return;
1069 for (const auto& theMother: prodVtx->particles_in()) {
1070 if (!theMother) continue;
1071 allancestors.insert(theMother);
1072 findParticleAncestors(theMother, allancestors);
1073 }
1074 }
1075
1077
1078 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1079 auto endVtx = thePart->end_vertex();
1080 if (!endVtx) return;
1081 for (const auto& theDaughter: endVtx->particles_out()) {
1082 if (!theDaughter) continue;
1083 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1084 allstabledescendants.insert(theDaughter);
1085 }
1086 findParticleStableDescendants(theDaughter, allstabledescendants);
1087 }
1088 }
1089
1093
1094 template <class T> bool isHardScatteringVertex(T pVert) {
1095 if (pVert == nullptr) return false;
1096 T pV = pVert;
1097 int numOfPartIn(0);
1098 int pdg(0);
1099
1100 do {
1101 pVert = pV;
1102 auto incoming = pVert->particles_in();
1103 numOfPartIn = incoming.size();
1104 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1105 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1106
1107 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1108
1109 if (numOfPartIn == 2) {
1110 auto incoming = pVert->particles_in();
1111 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1112 }
1113 return false;
1114}
1115
1119
1120 template <class T, class U>
1121 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1122 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1123 auto vtx = p->production_vertex();
1124 if (!vtx) return false;
1125 bool fromHad = false;
1126 for ( const auto& parent : particles_in(vtx) ) {
1127 if (!parent) continue;
1128 // should this really go into parton-level territory?
1129 // probably depends where BSM particles are being decayed
1130 fromBSM |= isBSM(parent);
1131 if (!isPhysical(parent)) return false;
1132 fromTau |= isTau(parent);
1133 if (isHadron(parent)&&!isBeam(parent)) {
1134 if (!hadron) hadron = parent; // assumes linear hadron parentage
1135 return true;
1136 }
1137 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1138 }
1139 return fromHad;
1140 }
1141
1144
1145 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1146 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1147 decltype(thePart->end_vertex()) pVert(nullptr);
1148 if (EndVert != nullptr) {
1149 do {
1150 bool samePart = false;
1151 pVert = nullptr;
1152 auto outgoing = EndVert->particles_out();
1153 auto incoming = EndVert->particles_in();
1154 for (const auto& itrDaug: outgoing) {
1155 if (!itrDaug) continue;
1156 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1157 // brem on generator level for tau
1158 (outgoing.size() == 1 && incoming.size() == 1 &&
1160 itrDaug->pdg_id() == thePart->pdg_id()) {
1161 samePart = true;
1162 pVert = itrDaug->end_vertex();
1163 }
1164 }
1165 if (samePart) EndVert = pVert;
1166 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1167 }
1168 return EndVert;
1169 }
1170
1172
1173 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1174 if (!theVert) return {};
1175 decltype(theVert->particles_out()) finalStatePart;
1176 auto outgoing = theVert->particles_out();
1177 for (const auto& thePart: outgoing) {
1178 if (!thePart) continue;
1179 finalStatePart.push_back(thePart);
1180 if (isStable(thePart)) continue;
1181 V pVert = findSimulatedEndVertex(thePart);
1182 if (pVert == theVert) break; // to prevent Sherpa loop
1183 if (pVert != nullptr) {
1184 auto vecPart = findFinalStateParticles<V>(pVert);
1185 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1186 }
1187 }
1188 return finalStatePart;
1189 }
1190
1191}
1192#endif

◆ isLightMeson()

template<class T>
bool MC::isLightMeson ( const T & p)
inline

Definition at line 916 of file HepMCHelpers.h.

937{
938inline
939auto particles_in (const HepMC::GenVertex* p) {
940 return std::ranges::subrange (p->particles_in_const_begin(),
941 p->particles_in_const_end());
942}
943}
944#endif
945
946namespace MC
947{
948 template <class VTX>
949 auto particles_in (const VTX* p) { return p->particles_in(); }
950 template <class VTX>
951 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
952
953 namespace Pythia8
954 {
956 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
957
958 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
959
960 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
961 }
962
963#include "AtlasPID.h"
964
966 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
967
969 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
970
972 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
973
975 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
976
978 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
979
981 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
982
984 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
985
987 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
988
990 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
991
993 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
994
998 template <class T> inline bool isStableOrSimDecayed(const T& p) {
999 const auto vertex = p->end_vertex();
1000 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1001 }
1002
1004 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1005
1007 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1008 const int apid = std::abs(p->pdg_id());
1009 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1010 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1011 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1012 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1013 return false;
1014 }
1015
1017
1018 template <class T> T findMother(T thePart) {
1019 auto partOriVert = thePart->production_vertex();
1020 if (!partOriVert) return nullptr;
1021
1022 long partPDG = thePart->pdg_id();
1023 long MotherPDG(0);
1024
1025 auto MothOriVert = partOriVert;
1026 MothOriVert = nullptr;
1027 T theMoth(nullptr);
1028
1029 size_t itr = 0;
1030 do {
1031 if (itr != 0) partOriVert = MothOriVert;
1032 for ( const auto& p : particles_in(partOriVert) ) {
1033 theMoth = p;
1034 if (!theMoth) continue;
1035 MotherPDG = theMoth->pdg_id();
1036 MothOriVert = theMoth->production_vertex();
1037 if (MotherPDG == partPDG) break;
1038 }
1039 itr++;
1040 if (itr > 100) {
1041 break;
1042 }
1043 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1044 MothOriVert != partOriVert);
1045 return theMoth;
1046 }
1047
1049
1050 template <class C, class T> T findMatching(C TruthContainer, T p) {
1051 T ptrPart = nullptr;
1052 if (!p) return ptrPart;
1053 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1054 for (T truthParticle : *TruthContainer) {
1055 if (HepMC::is_sim_descendant(p,truthParticle)) {
1056 ptrPart = truthParticle;
1057 break;
1058 }
1059 }
1060 }
1061 else {
1062 for (T truthParticle : TruthContainer) {
1063 if (HepMC::is_sim_descendant(p,truthParticle)) {
1064 ptrPart = truthParticle;
1065 break;
1066 }
1067 }
1068 }
1069 return ptrPart;
1070 }
1072
1073 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1074 auto prodVtx = thePart->production_vertex();
1075 if (!prodVtx) return;
1076 for (const auto& theMother: prodVtx->particles_in()) {
1077 if (!theMother) continue;
1078 allancestors.insert(theMother);
1079 findParticleAncestors(theMother, allancestors);
1080 }
1081 }
1082
1084
1085 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1086 auto endVtx = thePart->end_vertex();
1087 if (!endVtx) return;
1088 for (const auto& theDaughter: endVtx->particles_out()) {
1089 if (!theDaughter) continue;
1090 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1091 allstabledescendants.insert(theDaughter);
1092 }
1093 findParticleStableDescendants(theDaughter, allstabledescendants);
1094 }
1095 }
1096
1100
1101 template <class T> bool isHardScatteringVertex(T pVert) {
1102 if (pVert == nullptr) return false;
1103 T pV = pVert;
1104 int numOfPartIn(0);
1105 int pdg(0);
1106
1107 do {
1108 pVert = pV;
1109 auto incoming = pVert->particles_in();
1110 numOfPartIn = incoming.size();
1111 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1112 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1113
1114 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1115
1116 if (numOfPartIn == 2) {
1117 auto incoming = pVert->particles_in();
1118 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1119 }
1120 return false;
1121}
1122
1126
1127 template <class T, class U>
1128 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1129 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1130 auto vtx = p->production_vertex();
1131 if (!vtx) return false;
1132 bool fromHad = false;
1133 for ( const auto& parent : particles_in(vtx) ) {
1134 if (!parent) continue;
1135 // should this really go into parton-level territory?
1136 // probably depends where BSM particles are being decayed
1137 fromBSM |= isBSM(parent);
1138 if (!isPhysical(parent)) return false;
1139 fromTau |= isTau(parent);
1140 if (isHadron(parent)&&!isBeam(parent)) {
1141 if (!hadron) hadron = parent; // assumes linear hadron parentage
1142 return true;
1143 }
1144 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1145 }
1146 return fromHad;
1147 }
1148
1151
1152 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1153 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1154 decltype(thePart->end_vertex()) pVert(nullptr);
1155 if (EndVert != nullptr) {
1156 do {
1157 bool samePart = false;
1158 pVert = nullptr;
1159 auto outgoing = EndVert->particles_out();
1160 auto incoming = EndVert->particles_in();
1161 for (const auto& itrDaug: outgoing) {
1162 if (!itrDaug) continue;
1163 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1164 // brem on generator level for tau
1165 (outgoing.size() == 1 && incoming.size() == 1 &&
1167 itrDaug->pdg_id() == thePart->pdg_id()) {
1168 samePart = true;
1169 pVert = itrDaug->end_vertex();
1170 }
1171 }
1172 if (samePart) EndVert = pVert;
1173 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1174 }
1175 return EndVert;
1176 }
1177
1179
1180 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1181 if (!theVert) return {};
1182 decltype(theVert->particles_out()) finalStatePart;
1183 auto outgoing = theVert->particles_out();
1184 for (const auto& thePart: outgoing) {
1185 if (!thePart) continue;
1186 finalStatePart.push_back(thePart);
1187 if (isStable(thePart)) continue;
1188 V pVert = findSimulatedEndVertex(thePart);
1189 if (pVert == theVert) break; // to prevent Sherpa loop
1190 if (pVert != nullptr) {
1191 auto vecPart = findFinalStateParticles<V>(pVert);
1192 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1193 }
1194 }
1195 return finalStatePart;
1196 }
1197
1198}
1199#endif

◆ isMeson() [1/3]

template<>
bool MC::isMeson ( const DecodedPID & p)
inline

Definition at line 246 of file HepMCHelpers.h.

246 : outgoing) {
247 if (!itrDaug) continue;
248 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
249 // brem on generator level for tau
250 (outgoing.size() == 1 && incoming.size() == 1 &&
252 itrDaug->pdg_id() == thePart->pdg_id()) {
253 samePart = true;
254 pVert = itrDaug->end_vertex();
255 }
256 }
257 if (samePart) EndVert = pVert;
258 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
259 }
260 return EndVert;
261 }
262
264
265 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
266 if (!theVert) return {};

◆ isMeson() [2/3]

template<>
bool MC::isMeson ( const int & p)
inline

Definition at line 267 of file HepMCHelpers.h.

◆ isMeson() [3/3]

template<class T>
bool MC::isMeson ( const T & p)
inline

Table 43.1 PDG rule 5a: The numbers specifying the meson’s quark content conform to the convention nq1= 0 and nq2 >= nq3.

The special case K0L is the sole exception to this rule. PDG rule 5C: The special numbers 310 and 130 are given to the K0S and K0L respectively. APID: The special code K0 is used when a generator uses K0S/K0L APID: states with fourth generation quarks are not mesons

Definition at line 245 of file HepMCHelpers.h.

◆ isMonopole() [1/3]

template<>
bool MC::isMonopole ( const DecodedPID & p)
inline

Definition at line 647 of file HepMCHelpers.h.

668{
669inline
670auto particles_in (const HepMC::GenVertex* p) {
671 return std::ranges::subrange (p->particles_in_const_begin(),
672 p->particles_in_const_end());
673}
674}
675#endif
676
677namespace MC
678{
679 template <class VTX>
680 auto particles_in (const VTX* p) { return p->particles_in(); }
681 template <class VTX>
682 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
683
684 namespace Pythia8
685 {
687 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
688
689 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
690
691 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
692 }
693
694#include "AtlasPID.h"
695
697 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
698
700 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
701
703 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
704
706 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
707
709 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
710
712 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
713
715 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
716
718 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
719
721 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
722
724 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
725
729 template <class T> inline bool isStableOrSimDecayed(const T& p) {
730 const auto vertex = p->end_vertex();
731 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
732 }
733
735 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
736
738 template <class T> inline bool isSpecialNonInteracting(const T& p) {
739 const int apid = std::abs(p->pdg_id());
740 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
741 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
742 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
743 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
744 return false;
745 }
746
748
749 template <class T> T findMother(T thePart) {
750 auto partOriVert = thePart->production_vertex();
751 if (!partOriVert) return nullptr;
752
753 long partPDG = thePart->pdg_id();
754 long MotherPDG(0);
755
756 auto MothOriVert = partOriVert;
757 MothOriVert = nullptr;
758 T theMoth(nullptr);
759
760 size_t itr = 0;
761 do {
762 if (itr != 0) partOriVert = MothOriVert;
763 for ( const auto& p : particles_in(partOriVert) ) {
764 theMoth = p;
765 if (!theMoth) continue;
766 MotherPDG = theMoth->pdg_id();
767 MothOriVert = theMoth->production_vertex();
768 if (MotherPDG == partPDG) break;
769 }
770 itr++;
771 if (itr > 100) {
772 break;
773 }
774 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
775 MothOriVert != partOriVert);
776 return theMoth;
777 }
778
780
781 template <class C, class T> T findMatching(C TruthContainer, T p) {
782 T ptrPart = nullptr;
783 if (!p) return ptrPart;
784 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
785 for (T truthParticle : *TruthContainer) {
786 if (HepMC::is_sim_descendant(p,truthParticle)) {
787 ptrPart = truthParticle;
788 break;
789 }
790 }
791 }
792 else {
793 for (T truthParticle : TruthContainer) {
794 if (HepMC::is_sim_descendant(p,truthParticle)) {
795 ptrPart = truthParticle;
796 break;
797 }
798 }
799 }
800 return ptrPart;
801 }
803
804 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
805 auto prodVtx = thePart->production_vertex();
806 if (!prodVtx) return;
807 for (const auto& theMother: prodVtx->particles_in()) {
808 if (!theMother) continue;
809 allancestors.insert(theMother);
810 findParticleAncestors(theMother, allancestors);
811 }
812 }
813
815
816 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
817 auto endVtx = thePart->end_vertex();
818 if (!endVtx) return;
819 for (const auto& theDaughter: endVtx->particles_out()) {
820 if (!theDaughter) continue;
821 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
822 allstabledescendants.insert(theDaughter);
823 }
824 findParticleStableDescendants(theDaughter, allstabledescendants);
825 }
826 }
827
831
832 template <class T> bool isHardScatteringVertex(T pVert) {
833 if (pVert == nullptr) return false;
834 T pV = pVert;
835 int numOfPartIn(0);
836 int pdg(0);
837
838 do {
839 pVert = pV;
840 auto incoming = pVert->particles_in();
841 numOfPartIn = incoming.size();
842 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
843 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
844
845 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
846
847 if (numOfPartIn == 2) {
848 auto incoming = pVert->particles_in();
849 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
850 }
851 return false;
852}
853
857
858 template <class T, class U>
859 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
860 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
861 auto vtx = p->production_vertex();
862 if (!vtx) return false;
863 bool fromHad = false;
864 for ( const auto& parent : particles_in(vtx) ) {
865 if (!parent) continue;
866 // should this really go into parton-level territory?
867 // probably depends where BSM particles are being decayed
868 fromBSM |= isBSM(parent);
869 if (!isPhysical(parent)) return false;
870 fromTau |= isTau(parent);
871 if (isHadron(parent)&&!isBeam(parent)) {
872 if (!hadron) hadron = parent; // assumes linear hadron parentage
873 return true;
874 }
875 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
876 }
877 return fromHad;
878 }
879
882
883 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
884 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
885 decltype(thePart->end_vertex()) pVert(nullptr);
886 if (EndVert != nullptr) {
887 do {
888 bool samePart = false;
889 pVert = nullptr;
890 auto outgoing = EndVert->particles_out();
891 auto incoming = EndVert->particles_in();
892 for (const auto& itrDaug: outgoing) {
893 if (!itrDaug) continue;
894 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
895 // brem on generator level for tau
896 (outgoing.size() == 1 && incoming.size() == 1 &&
898 itrDaug->pdg_id() == thePart->pdg_id()) {
899 samePart = true;
900 pVert = itrDaug->end_vertex();
901 }
902 }
903 if (samePart) EndVert = pVert;
904 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
905 }
906 return EndVert;
907 }
908
910
911 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
912 if (!theVert) return {};
913 decltype(theVert->particles_out()) finalStatePart;
914 auto outgoing = theVert->particles_out();
915 for (const auto& thePart: outgoing) {
916 if (!thePart) continue;
917 finalStatePart.push_back(thePart);
918 if (isStable(thePart)) continue;
919 V pVert = findSimulatedEndVertex(thePart);
920 if (pVert == theVert) break; // to prevent Sherpa loop
921 if (pVert != nullptr) {
922 auto vecPart = findFinalStateParticles<V>(pVert);
923 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
924 }
925 }
926 return finalStatePart;
927 }
928
929}
930#endif

◆ isMonopole() [2/3]

template<>
bool MC::isMonopole ( const int & p)
inline

Definition at line 648 of file HepMCHelpers.h.

669{
670inline
671auto particles_in (const HepMC::GenVertex* p) {
672 return std::ranges::subrange (p->particles_in_const_begin(),
673 p->particles_in_const_end());
674}
675}
676#endif
677
678namespace MC
679{
680 template <class VTX>
681 auto particles_in (const VTX* p) { return p->particles_in(); }
682 template <class VTX>
683 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
684
685 namespace Pythia8
686 {
688 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
689
690 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
691
692 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
693 }
694
695#include "AtlasPID.h"
696
698 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
699
701 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
702
704 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
705
707 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
708
710 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
711
713 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
714
716 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
717
719 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
720
722 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
723
725 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
726
730 template <class T> inline bool isStableOrSimDecayed(const T& p) {
731 const auto vertex = p->end_vertex();
732 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
733 }
734
736 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
737
739 template <class T> inline bool isSpecialNonInteracting(const T& p) {
740 const int apid = std::abs(p->pdg_id());
741 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
742 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
743 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
744 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
745 return false;
746 }
747
749
750 template <class T> T findMother(T thePart) {
751 auto partOriVert = thePart->production_vertex();
752 if (!partOriVert) return nullptr;
753
754 long partPDG = thePart->pdg_id();
755 long MotherPDG(0);
756
757 auto MothOriVert = partOriVert;
758 MothOriVert = nullptr;
759 T theMoth(nullptr);
760
761 size_t itr = 0;
762 do {
763 if (itr != 0) partOriVert = MothOriVert;
764 for ( const auto& p : particles_in(partOriVert) ) {
765 theMoth = p;
766 if (!theMoth) continue;
767 MotherPDG = theMoth->pdg_id();
768 MothOriVert = theMoth->production_vertex();
769 if (MotherPDG == partPDG) break;
770 }
771 itr++;
772 if (itr > 100) {
773 break;
774 }
775 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
776 MothOriVert != partOriVert);
777 return theMoth;
778 }
779
781
782 template <class C, class T> T findMatching(C TruthContainer, T p) {
783 T ptrPart = nullptr;
784 if (!p) return ptrPart;
785 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
786 for (T truthParticle : *TruthContainer) {
787 if (HepMC::is_sim_descendant(p,truthParticle)) {
788 ptrPart = truthParticle;
789 break;
790 }
791 }
792 }
793 else {
794 for (T truthParticle : TruthContainer) {
795 if (HepMC::is_sim_descendant(p,truthParticle)) {
796 ptrPart = truthParticle;
797 break;
798 }
799 }
800 }
801 return ptrPart;
802 }
804
805 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
806 auto prodVtx = thePart->production_vertex();
807 if (!prodVtx) return;
808 for (const auto& theMother: prodVtx->particles_in()) {
809 if (!theMother) continue;
810 allancestors.insert(theMother);
811 findParticleAncestors(theMother, allancestors);
812 }
813 }
814
816
817 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
818 auto endVtx = thePart->end_vertex();
819 if (!endVtx) return;
820 for (const auto& theDaughter: endVtx->particles_out()) {
821 if (!theDaughter) continue;
822 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
823 allstabledescendants.insert(theDaughter);
824 }
825 findParticleStableDescendants(theDaughter, allstabledescendants);
826 }
827 }
828
832
833 template <class T> bool isHardScatteringVertex(T pVert) {
834 if (pVert == nullptr) return false;
835 T pV = pVert;
836 int numOfPartIn(0);
837 int pdg(0);
838
839 do {
840 pVert = pV;
841 auto incoming = pVert->particles_in();
842 numOfPartIn = incoming.size();
843 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
844 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
845
846 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
847
848 if (numOfPartIn == 2) {
849 auto incoming = pVert->particles_in();
850 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
851 }
852 return false;
853}
854
858
859 template <class T, class U>
860 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
861 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
862 auto vtx = p->production_vertex();
863 if (!vtx) return false;
864 bool fromHad = false;
865 for ( const auto& parent : particles_in(vtx) ) {
866 if (!parent) continue;
867 // should this really go into parton-level territory?
868 // probably depends where BSM particles are being decayed
869 fromBSM |= isBSM(parent);
870 if (!isPhysical(parent)) return false;
871 fromTau |= isTau(parent);
872 if (isHadron(parent)&&!isBeam(parent)) {
873 if (!hadron) hadron = parent; // assumes linear hadron parentage
874 return true;
875 }
876 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
877 }
878 return fromHad;
879 }
880
883
884 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
885 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
886 decltype(thePart->end_vertex()) pVert(nullptr);
887 if (EndVert != nullptr) {
888 do {
889 bool samePart = false;
890 pVert = nullptr;
891 auto outgoing = EndVert->particles_out();
892 auto incoming = EndVert->particles_in();
893 for (const auto& itrDaug: outgoing) {
894 if (!itrDaug) continue;
895 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
896 // brem on generator level for tau
897 (outgoing.size() == 1 && incoming.size() == 1 &&
899 itrDaug->pdg_id() == thePart->pdg_id()) {
900 samePart = true;
901 pVert = itrDaug->end_vertex();
902 }
903 }
904 if (samePart) EndVert = pVert;
905 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
906 }
907 return EndVert;
908 }
909
911
912 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
913 if (!theVert) return {};
914 decltype(theVert->particles_out()) finalStatePart;
915 auto outgoing = theVert->particles_out();
916 for (const auto& thePart: outgoing) {
917 if (!thePart) continue;
918 finalStatePart.push_back(thePart);
919 if (isStable(thePart)) continue;
920 V pVert = findSimulatedEndVertex(thePart);
921 if (pVert == theVert) break; // to prevent Sherpa loop
922 if (pVert != nullptr) {
923 auto vecPart = findFinalStateParticles<V>(pVert);
924 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
925 }
926 }
927 return finalStatePart;
928 }
929
930}
931#endif

◆ isMonopole() [3/3]

template<class T>
bool MC::isMonopole ( const T & p)
inline

PDG rule 11i Magnetic monopoles and dyons are assumed to have one unit of Dirac monopole charge and a variable integer number nq1nq2 nq3 units of electric charge.

Codes 411nq1nq2 nq3 0 are then used when the magnetic and electrical charge sign agree and 412nq1nq2 nq3 0 when they disagree, with the overall sign of the particle set by the magnetic charge. For now no spin information is provided.

Definition at line 646 of file HepMCHelpers.h.

667{
668inline
669auto particles_in (const HepMC::GenVertex* p) {
670 return std::ranges::subrange (p->particles_in_const_begin(),
671 p->particles_in_const_end());
672}
673}
674#endif
675
676namespace MC
677{
678 template <class VTX>
679 auto particles_in (const VTX* p) { return p->particles_in(); }
680 template <class VTX>
681 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
682
683 namespace Pythia8
684 {
686 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
687
688 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
689
690 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
691 }
692
693#include "AtlasPID.h"
694
696 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
697
699 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
700
702 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
703
705 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
706
708 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
709
711 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
712
714 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
715
717 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
718
720 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
721
723 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
724
728 template <class T> inline bool isStableOrSimDecayed(const T& p) {
729 const auto vertex = p->end_vertex();
730 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
731 }
732
734 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
735
737 template <class T> inline bool isSpecialNonInteracting(const T& p) {
738 const int apid = std::abs(p->pdg_id());
739 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
740 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
741 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
742 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
743 return false;
744 }
745
747
748 template <class T> T findMother(T thePart) {
749 auto partOriVert = thePart->production_vertex();
750 if (!partOriVert) return nullptr;
751
752 long partPDG = thePart->pdg_id();
753 long MotherPDG(0);
754
755 auto MothOriVert = partOriVert;
756 MothOriVert = nullptr;
757 T theMoth(nullptr);
758
759 size_t itr = 0;
760 do {
761 if (itr != 0) partOriVert = MothOriVert;
762 for ( const auto& p : particles_in(partOriVert) ) {
763 theMoth = p;
764 if (!theMoth) continue;
765 MotherPDG = theMoth->pdg_id();
766 MothOriVert = theMoth->production_vertex();
767 if (MotherPDG == partPDG) break;
768 }
769 itr++;
770 if (itr > 100) {
771 break;
772 }
773 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
774 MothOriVert != partOriVert);
775 return theMoth;
776 }
777
779
780 template <class C, class T> T findMatching(C TruthContainer, T p) {
781 T ptrPart = nullptr;
782 if (!p) return ptrPart;
783 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
784 for (T truthParticle : *TruthContainer) {
785 if (HepMC::is_sim_descendant(p,truthParticle)) {
786 ptrPart = truthParticle;
787 break;
788 }
789 }
790 }
791 else {
792 for (T truthParticle : TruthContainer) {
793 if (HepMC::is_sim_descendant(p,truthParticle)) {
794 ptrPart = truthParticle;
795 break;
796 }
797 }
798 }
799 return ptrPart;
800 }
802
803 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
804 auto prodVtx = thePart->production_vertex();
805 if (!prodVtx) return;
806 for (const auto& theMother: prodVtx->particles_in()) {
807 if (!theMother) continue;
808 allancestors.insert(theMother);
809 findParticleAncestors(theMother, allancestors);
810 }
811 }
812
814
815 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
816 auto endVtx = thePart->end_vertex();
817 if (!endVtx) return;
818 for (const auto& theDaughter: endVtx->particles_out()) {
819 if (!theDaughter) continue;
820 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
821 allstabledescendants.insert(theDaughter);
822 }
823 findParticleStableDescendants(theDaughter, allstabledescendants);
824 }
825 }
826
830
831 template <class T> bool isHardScatteringVertex(T pVert) {
832 if (pVert == nullptr) return false;
833 T pV = pVert;
834 int numOfPartIn(0);
835 int pdg(0);
836
837 do {
838 pVert = pV;
839 auto incoming = pVert->particles_in();
840 numOfPartIn = incoming.size();
841 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
842 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
843
844 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
845
846 if (numOfPartIn == 2) {
847 auto incoming = pVert->particles_in();
848 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
849 }
850 return false;
851}
852
856
857 template <class T, class U>
858 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
859 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
860 auto vtx = p->production_vertex();
861 if (!vtx) return false;
862 bool fromHad = false;
863 for ( const auto& parent : particles_in(vtx) ) {
864 if (!parent) continue;
865 // should this really go into parton-level territory?
866 // probably depends where BSM particles are being decayed
867 fromBSM |= isBSM(parent);
868 if (!isPhysical(parent)) return false;
869 fromTau |= isTau(parent);
870 if (isHadron(parent)&&!isBeam(parent)) {
871 if (!hadron) hadron = parent; // assumes linear hadron parentage
872 return true;
873 }
874 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
875 }
876 return fromHad;
877 }
878
881
882 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
883 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
884 decltype(thePart->end_vertex()) pVert(nullptr);
885 if (EndVert != nullptr) {
886 do {
887 bool samePart = false;
888 pVert = nullptr;
889 auto outgoing = EndVert->particles_out();
890 auto incoming = EndVert->particles_in();
891 for (const auto& itrDaug: outgoing) {
892 if (!itrDaug) continue;
893 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
894 // brem on generator level for tau
895 (outgoing.size() == 1 && incoming.size() == 1 &&
897 itrDaug->pdg_id() == thePart->pdg_id()) {
898 samePart = true;
899 pVert = itrDaug->end_vertex();
900 }
901 }
902 if (samePart) EndVert = pVert;
903 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
904 }
905 return EndVert;
906 }
907
909
910 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
911 if (!theVert) return {};
912 decltype(theVert->particles_out()) finalStatePart;
913 auto outgoing = theVert->particles_out();
914 for (const auto& thePart: outgoing) {
915 if (!thePart) continue;
916 finalStatePart.push_back(thePart);
917 if (isStable(thePart)) continue;
918 V pVert = findSimulatedEndVertex(thePart);
919 if (pVert == theVert) break; // to prevent Sherpa loop
920 if (pVert != nullptr) {
921 auto vecPart = findFinalStateParticles<V>(pVert);
922 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
923 }
924 }
925 return finalStatePart;
926 }
927
928}
929#endif

◆ isMSSMHiggs() [1/2]

template<>
bool MC::isMSSMHiggs ( const int & p)
inline

Definition at line 396 of file HepMCHelpers.h.

417{
418inline
419auto particles_in (const HepMC::GenVertex* p) {
420 return std::ranges::subrange (p->particles_in_const_begin(),
421 p->particles_in_const_end());
422}
423}
424#endif
425
426namespace MC
427{
428 template <class VTX>
429 auto particles_in (const VTX* p) { return p->particles_in(); }
430 template <class VTX>
431 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
432
433 namespace Pythia8
434 {
436 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
437
438 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
439
440 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
441 }
442
443#include "AtlasPID.h"
444
446 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
447
449 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
450
452 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
453
455 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
456
458 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
459
461 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
462
464 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
465
467 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
468
470 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
471
473 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
474
478 template <class T> inline bool isStableOrSimDecayed(const T& p) {
479 const auto vertex = p->end_vertex();
480 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
481 }
482
484 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
485
487 template <class T> inline bool isSpecialNonInteracting(const T& p) {
488 const int apid = std::abs(p->pdg_id());
489 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
490 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
491 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
492 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
493 return false;
494 }
495
497
498 template <class T> T findMother(T thePart) {
499 auto partOriVert = thePart->production_vertex();
500 if (!partOriVert) return nullptr;
501
502 long partPDG = thePart->pdg_id();
503 long MotherPDG(0);
504
505 auto MothOriVert = partOriVert;
506 MothOriVert = nullptr;
507 T theMoth(nullptr);
508
509 size_t itr = 0;
510 do {
511 if (itr != 0) partOriVert = MothOriVert;
512 for ( const auto& p : particles_in(partOriVert) ) {
513 theMoth = p;
514 if (!theMoth) continue;
515 MotherPDG = theMoth->pdg_id();
516 MothOriVert = theMoth->production_vertex();
517 if (MotherPDG == partPDG) break;
518 }
519 itr++;
520 if (itr > 100) {
521 break;
522 }
523 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
524 MothOriVert != partOriVert);
525 return theMoth;
526 }
527
529
530 template <class C, class T> T findMatching(C TruthContainer, T p) {
531 T ptrPart = nullptr;
532 if (!p) return ptrPart;
533 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
534 for (T truthParticle : *TruthContainer) {
535 if (HepMC::is_sim_descendant(p,truthParticle)) {
536 ptrPart = truthParticle;
537 break;
538 }
539 }
540 }
541 else {
542 for (T truthParticle : TruthContainer) {
543 if (HepMC::is_sim_descendant(p,truthParticle)) {
544 ptrPart = truthParticle;
545 break;
546 }
547 }
548 }
549 return ptrPart;
550 }
552
553 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
554 auto prodVtx = thePart->production_vertex();
555 if (!prodVtx) return;
556 for (const auto& theMother: prodVtx->particles_in()) {
557 if (!theMother) continue;
558 allancestors.insert(theMother);
559 findParticleAncestors(theMother, allancestors);
560 }
561 }
562
564
565 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
566 auto endVtx = thePart->end_vertex();
567 if (!endVtx) return;
568 for (const auto& theDaughter: endVtx->particles_out()) {
569 if (!theDaughter) continue;
570 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
571 allstabledescendants.insert(theDaughter);
572 }
573 findParticleStableDescendants(theDaughter, allstabledescendants);
574 }
575 }
576
580
581 template <class T> bool isHardScatteringVertex(T pVert) {
582 if (pVert == nullptr) return false;
583 T pV = pVert;
584 int numOfPartIn(0);
585 int pdg(0);
586
587 do {
588 pVert = pV;
589 auto incoming = pVert->particles_in();
590 numOfPartIn = incoming.size();
591 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
592 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
593
594 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
595
596 if (numOfPartIn == 2) {
597 auto incoming = pVert->particles_in();
598 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
599 }
600 return false;
601}
602
606
607 template <class T, class U>
608 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
609 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
610 auto vtx = p->production_vertex();
611 if (!vtx) return false;
612 bool fromHad = false;
613 for ( const auto& parent : particles_in(vtx) ) {
614 if (!parent) continue;
615 // should this really go into parton-level territory?
616 // probably depends where BSM particles are being decayed
617 fromBSM |= isBSM(parent);
618 if (!isPhysical(parent)) return false;
619 fromTau |= isTau(parent);
620 if (isHadron(parent)&&!isBeam(parent)) {
621 if (!hadron) hadron = parent; // assumes linear hadron parentage
622 return true;
623 }
624 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
625 }
626 return fromHad;
627 }
628
631
632 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
633 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
634 decltype(thePart->end_vertex()) pVert(nullptr);
635 if (EndVert != nullptr) {
636 do {
637 bool samePart = false;
638 pVert = nullptr;
639 auto outgoing = EndVert->particles_out();
640 auto incoming = EndVert->particles_in();
641 for (const auto& itrDaug: outgoing) {
642 if (!itrDaug) continue;
643 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
644 // brem on generator level for tau
645 (outgoing.size() == 1 && incoming.size() == 1 &&
647 itrDaug->pdg_id() == thePart->pdg_id()) {
648 samePart = true;
649 pVert = itrDaug->end_vertex();
650 }
651 }
652 if (samePart) EndVert = pVert;
653 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
654 }
655 return EndVert;
656 }
657
659
660 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
661 if (!theVert) return {};
662 decltype(theVert->particles_out()) finalStatePart;
663 auto outgoing = theVert->particles_out();
664 for (const auto& thePart: outgoing) {
665 if (!thePart) continue;
666 finalStatePart.push_back(thePart);
667 if (isStable(thePart)) continue;
668 V pVert = findSimulatedEndVertex(thePart);
669 if (pVert == theVert) break; // to prevent Sherpa loop
670 if (pVert != nullptr) {
671 auto vecPart = findFinalStateParticles<V>(pVert);
672 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
673 }
674 }
675 return finalStatePart;
676 }
677
678}
679#endif

◆ isMSSMHiggs() [2/2]

template<class T>
bool MC::isMSSMHiggs ( const T & p)
inline

APID: Additional Higgs bosons for MSSM (Used in MCTruthClassifier)

Definition at line 395 of file HepMCHelpers.h.

416{
417inline
418auto particles_in (const HepMC::GenVertex* p) {
419 return std::ranges::subrange (p->particles_in_const_begin(),
420 p->particles_in_const_end());
421}
422}
423#endif
424
425namespace MC
426{
427 template <class VTX>
428 auto particles_in (const VTX* p) { return p->particles_in(); }
429 template <class VTX>
430 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
431
432 namespace Pythia8
433 {
435 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
436
437 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
438
439 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
440 }
441
442#include "AtlasPID.h"
443
445 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
446
448 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
449
451 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
452
454 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
455
457 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
458
460 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
461
463 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
464
466 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
467
469 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
470
472 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
473
477 template <class T> inline bool isStableOrSimDecayed(const T& p) {
478 const auto vertex = p->end_vertex();
479 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
480 }
481
483 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
484
486 template <class T> inline bool isSpecialNonInteracting(const T& p) {
487 const int apid = std::abs(p->pdg_id());
488 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
489 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
490 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
491 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
492 return false;
493 }
494
496
497 template <class T> T findMother(T thePart) {
498 auto partOriVert = thePart->production_vertex();
499 if (!partOriVert) return nullptr;
500
501 long partPDG = thePart->pdg_id();
502 long MotherPDG(0);
503
504 auto MothOriVert = partOriVert;
505 MothOriVert = nullptr;
506 T theMoth(nullptr);
507
508 size_t itr = 0;
509 do {
510 if (itr != 0) partOriVert = MothOriVert;
511 for ( const auto& p : particles_in(partOriVert) ) {
512 theMoth = p;
513 if (!theMoth) continue;
514 MotherPDG = theMoth->pdg_id();
515 MothOriVert = theMoth->production_vertex();
516 if (MotherPDG == partPDG) break;
517 }
518 itr++;
519 if (itr > 100) {
520 break;
521 }
522 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
523 MothOriVert != partOriVert);
524 return theMoth;
525 }
526
528
529 template <class C, class T> T findMatching(C TruthContainer, T p) {
530 T ptrPart = nullptr;
531 if (!p) return ptrPart;
532 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
533 for (T truthParticle : *TruthContainer) {
534 if (HepMC::is_sim_descendant(p,truthParticle)) {
535 ptrPart = truthParticle;
536 break;
537 }
538 }
539 }
540 else {
541 for (T truthParticle : TruthContainer) {
542 if (HepMC::is_sim_descendant(p,truthParticle)) {
543 ptrPart = truthParticle;
544 break;
545 }
546 }
547 }
548 return ptrPart;
549 }
551
552 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
553 auto prodVtx = thePart->production_vertex();
554 if (!prodVtx) return;
555 for (const auto& theMother: prodVtx->particles_in()) {
556 if (!theMother) continue;
557 allancestors.insert(theMother);
558 findParticleAncestors(theMother, allancestors);
559 }
560 }
561
563
564 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
565 auto endVtx = thePart->end_vertex();
566 if (!endVtx) return;
567 for (const auto& theDaughter: endVtx->particles_out()) {
568 if (!theDaughter) continue;
569 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
570 allstabledescendants.insert(theDaughter);
571 }
572 findParticleStableDescendants(theDaughter, allstabledescendants);
573 }
574 }
575
579
580 template <class T> bool isHardScatteringVertex(T pVert) {
581 if (pVert == nullptr) return false;
582 T pV = pVert;
583 int numOfPartIn(0);
584 int pdg(0);
585
586 do {
587 pVert = pV;
588 auto incoming = pVert->particles_in();
589 numOfPartIn = incoming.size();
590 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
591 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
592
593 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
594
595 if (numOfPartIn == 2) {
596 auto incoming = pVert->particles_in();
597 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
598 }
599 return false;
600}
601
605
606 template <class T, class U>
607 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
608 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
609 auto vtx = p->production_vertex();
610 if (!vtx) return false;
611 bool fromHad = false;
612 for ( const auto& parent : particles_in(vtx) ) {
613 if (!parent) continue;
614 // should this really go into parton-level territory?
615 // probably depends where BSM particles are being decayed
616 fromBSM |= isBSM(parent);
617 if (!isPhysical(parent)) return false;
618 fromTau |= isTau(parent);
619 if (isHadron(parent)&&!isBeam(parent)) {
620 if (!hadron) hadron = parent; // assumes linear hadron parentage
621 return true;
622 }
623 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
624 }
625 return fromHad;
626 }
627
630
631 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
632 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
633 decltype(thePart->end_vertex()) pVert(nullptr);
634 if (EndVert != nullptr) {
635 do {
636 bool samePart = false;
637 pVert = nullptr;
638 auto outgoing = EndVert->particles_out();
639 auto incoming = EndVert->particles_in();
640 for (const auto& itrDaug: outgoing) {
641 if (!itrDaug) continue;
642 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
643 // brem on generator level for tau
644 (outgoing.size() == 1 && incoming.size() == 1 &&
646 itrDaug->pdg_id() == thePart->pdg_id()) {
647 samePart = true;
648 pVert = itrDaug->end_vertex();
649 }
650 }
651 if (samePart) EndVert = pVert;
652 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
653 }
654 return EndVert;
655 }
656
658
659 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
660 if (!theVert) return {};
661 decltype(theVert->particles_out()) finalStatePart;
662 auto outgoing = theVert->particles_out();
663 for (const auto& thePart: outgoing) {
664 if (!thePart) continue;
665 finalStatePart.push_back(thePart);
666 if (isStable(thePart)) continue;
667 V pVert = findSimulatedEndVertex(thePart);
668 if (pVert == theVert) break; // to prevent Sherpa loop
669 if (pVert != nullptr) {
670 auto vecPart = findFinalStateParticles<V>(pVert);
671 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
672 }
673 }
674 return finalStatePart;
675 }
676
677}
678#endif

◆ isMuon() [1/2]

template<>
bool MC::isMuon ( const int & p)
inline

Definition at line 207 of file HepMCHelpers.h.

◆ isMuon() [2/2]

template<class T>
bool MC::isMuon ( const T & p)
inline

Definition at line 206 of file HepMCHelpers.h.

◆ isNeutral() [1/3]

template<>
bool MC::isNeutral ( const DecodedPID & p)
inline

Definition at line 1087 of file HepMCHelpers.h.

1108{
1109inline
1110auto particles_in (const HepMC::GenVertex* p) {
1111 return std::ranges::subrange (p->particles_in_const_begin(),
1112 p->particles_in_const_end());
1113}
1114}
1115#endif
1116
1117namespace MC
1118{
1119 template <class VTX>
1120 auto particles_in (const VTX* p) { return p->particles_in(); }
1121 template <class VTX>
1122 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1123
1124 namespace Pythia8
1125 {
1127 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1128
1129 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1130
1131 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1132 }
1133
1134#include "AtlasPID.h"
1135
1137 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1138
1140 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1141
1143 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1144
1146 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1147
1149 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1150
1152 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1153
1155 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1156
1158 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1159
1161 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1162
1164 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1165
1169 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1170 const auto vertex = p->end_vertex();
1171 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1172 }
1173
1175 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1176
1178 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1179 const int apid = std::abs(p->pdg_id());
1180 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1181 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1182 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1183 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1184 return false;
1185 }
1186
1188
1189 template <class T> T findMother(T thePart) {
1190 auto partOriVert = thePart->production_vertex();
1191 if (!partOriVert) return nullptr;
1192
1193 long partPDG = thePart->pdg_id();
1194 long MotherPDG(0);
1195
1196 auto MothOriVert = partOriVert;
1197 MothOriVert = nullptr;
1198 T theMoth(nullptr);
1199
1200 size_t itr = 0;
1201 do {
1202 if (itr != 0) partOriVert = MothOriVert;
1203 for ( const auto& p : particles_in(partOriVert) ) {
1204 theMoth = p;
1205 if (!theMoth) continue;
1206 MotherPDG = theMoth->pdg_id();
1207 MothOriVert = theMoth->production_vertex();
1208 if (MotherPDG == partPDG) break;
1209 }
1210 itr++;
1211 if (itr > 100) {
1212 break;
1213 }
1214 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1215 MothOriVert != partOriVert);
1216 return theMoth;
1217 }
1218
1220
1221 template <class C, class T> T findMatching(C TruthContainer, T p) {
1222 T ptrPart = nullptr;
1223 if (!p) return ptrPart;
1224 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1225 for (T truthParticle : *TruthContainer) {
1226 if (HepMC::is_sim_descendant(p,truthParticle)) {
1227 ptrPart = truthParticle;
1228 break;
1229 }
1230 }
1231 }
1232 else {
1233 for (T truthParticle : TruthContainer) {
1234 if (HepMC::is_sim_descendant(p,truthParticle)) {
1235 ptrPart = truthParticle;
1236 break;
1237 }
1238 }
1239 }
1240 return ptrPart;
1241 }
1243
1244 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1245 auto prodVtx = thePart->production_vertex();
1246 if (!prodVtx) return;
1247 for (const auto& theMother: prodVtx->particles_in()) {
1248 if (!theMother) continue;
1249 allancestors.insert(theMother);
1250 findParticleAncestors(theMother, allancestors);
1251 }
1252 }
1253
1255
1256 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1257 auto endVtx = thePart->end_vertex();
1258 if (!endVtx) return;
1259 for (const auto& theDaughter: endVtx->particles_out()) {
1260 if (!theDaughter) continue;
1261 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1262 allstabledescendants.insert(theDaughter);
1263 }
1264 findParticleStableDescendants(theDaughter, allstabledescendants);
1265 }
1266 }
1267
1271
1272 template <class T> bool isHardScatteringVertex(T pVert) {
1273 if (pVert == nullptr) return false;
1274 T pV = pVert;
1275 int numOfPartIn(0);
1276 int pdg(0);
1277
1278 do {
1279 pVert = pV;
1280 auto incoming = pVert->particles_in();
1281 numOfPartIn = incoming.size();
1282 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1283 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1284
1285 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1286
1287 if (numOfPartIn == 2) {
1288 auto incoming = pVert->particles_in();
1289 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1290 }
1291 return false;
1292}
1293
1297
1298 template <class T, class U>
1299 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1300 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1301 auto vtx = p->production_vertex();
1302 if (!vtx) return false;
1303 bool fromHad = false;
1304 for ( const auto& parent : particles_in(vtx) ) {
1305 if (!parent) continue;
1306 // should this really go into parton-level territory?
1307 // probably depends where BSM particles are being decayed
1308 fromBSM |= isBSM(parent);
1309 if (!isPhysical(parent)) return false;
1310 fromTau |= isTau(parent);
1311 if (isHadron(parent)&&!isBeam(parent)) {
1312 if (!hadron) hadron = parent; // assumes linear hadron parentage
1313 return true;
1314 }
1315 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1316 }
1317 return fromHad;
1318 }
1319
1322
1323 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1324 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1325 decltype(thePart->end_vertex()) pVert(nullptr);
1326 if (EndVert != nullptr) {
1327 do {
1328 bool samePart = false;
1329 pVert = nullptr;
1330 auto outgoing = EndVert->particles_out();
1331 auto incoming = EndVert->particles_in();
1332 for (const auto& itrDaug: outgoing) {
1333 if (!itrDaug) continue;
1334 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1335 // brem on generator level for tau
1336 (outgoing.size() == 1 && incoming.size() == 1 &&
1338 itrDaug->pdg_id() == thePart->pdg_id()) {
1339 samePart = true;
1340 pVert = itrDaug->end_vertex();
1341 }
1342 }
1343 if (samePart) EndVert = pVert;
1344 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1345 }
1346 return EndVert;
1347 }
1348
1350
1351 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1352 if (!theVert) return {};
1353 decltype(theVert->particles_out()) finalStatePart;
1354 auto outgoing = theVert->particles_out();
1355 for (const auto& thePart: outgoing) {
1356 if (!thePart) continue;
1357 finalStatePart.push_back(thePart);
1358 if (isStable(thePart)) continue;
1359 V pVert = findSimulatedEndVertex(thePart);
1360 if (pVert == theVert) break; // to prevent Sherpa loop
1361 if (pVert != nullptr) {
1362 auto vecPart = findFinalStateParticles<V>(pVert);
1363 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1364 }
1365 }
1366 return finalStatePart;
1367 }
1368
1369}
1370#endif

◆ isNeutral() [2/3]

template<>
bool MC::isNeutral ( const int & p)
inline

Definition at line 1088 of file HepMCHelpers.h.

1109{
1110inline
1111auto particles_in (const HepMC::GenVertex* p) {
1112 return std::ranges::subrange (p->particles_in_const_begin(),
1113 p->particles_in_const_end());
1114}
1115}
1116#endif
1117
1118namespace MC
1119{
1120 template <class VTX>
1121 auto particles_in (const VTX* p) { return p->particles_in(); }
1122 template <class VTX>
1123 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1124
1125 namespace Pythia8
1126 {
1128 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1129
1130 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1131
1132 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1133 }
1134
1135#include "AtlasPID.h"
1136
1138 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1139
1141 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1142
1144 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1145
1147 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1148
1150 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1151
1153 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1154
1156 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1157
1159 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1160
1162 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1163
1165 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1166
1170 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1171 const auto vertex = p->end_vertex();
1172 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1173 }
1174
1176 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1177
1179 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1180 const int apid = std::abs(p->pdg_id());
1181 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1182 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1183 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1184 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1185 return false;
1186 }
1187
1189
1190 template <class T> T findMother(T thePart) {
1191 auto partOriVert = thePart->production_vertex();
1192 if (!partOriVert) return nullptr;
1193
1194 long partPDG = thePart->pdg_id();
1195 long MotherPDG(0);
1196
1197 auto MothOriVert = partOriVert;
1198 MothOriVert = nullptr;
1199 T theMoth(nullptr);
1200
1201 size_t itr = 0;
1202 do {
1203 if (itr != 0) partOriVert = MothOriVert;
1204 for ( const auto& p : particles_in(partOriVert) ) {
1205 theMoth = p;
1206 if (!theMoth) continue;
1207 MotherPDG = theMoth->pdg_id();
1208 MothOriVert = theMoth->production_vertex();
1209 if (MotherPDG == partPDG) break;
1210 }
1211 itr++;
1212 if (itr > 100) {
1213 break;
1214 }
1215 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1216 MothOriVert != partOriVert);
1217 return theMoth;
1218 }
1219
1221
1222 template <class C, class T> T findMatching(C TruthContainer, T p) {
1223 T ptrPart = nullptr;
1224 if (!p) return ptrPart;
1225 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1226 for (T truthParticle : *TruthContainer) {
1227 if (HepMC::is_sim_descendant(p,truthParticle)) {
1228 ptrPart = truthParticle;
1229 break;
1230 }
1231 }
1232 }
1233 else {
1234 for (T truthParticle : TruthContainer) {
1235 if (HepMC::is_sim_descendant(p,truthParticle)) {
1236 ptrPart = truthParticle;
1237 break;
1238 }
1239 }
1240 }
1241 return ptrPart;
1242 }
1244
1245 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1246 auto prodVtx = thePart->production_vertex();
1247 if (!prodVtx) return;
1248 for (const auto& theMother: prodVtx->particles_in()) {
1249 if (!theMother) continue;
1250 allancestors.insert(theMother);
1251 findParticleAncestors(theMother, allancestors);
1252 }
1253 }
1254
1256
1257 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1258 auto endVtx = thePart->end_vertex();
1259 if (!endVtx) return;
1260 for (const auto& theDaughter: endVtx->particles_out()) {
1261 if (!theDaughter) continue;
1262 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1263 allstabledescendants.insert(theDaughter);
1264 }
1265 findParticleStableDescendants(theDaughter, allstabledescendants);
1266 }
1267 }
1268
1272
1273 template <class T> bool isHardScatteringVertex(T pVert) {
1274 if (pVert == nullptr) return false;
1275 T pV = pVert;
1276 int numOfPartIn(0);
1277 int pdg(0);
1278
1279 do {
1280 pVert = pV;
1281 auto incoming = pVert->particles_in();
1282 numOfPartIn = incoming.size();
1283 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1284 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1285
1286 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1287
1288 if (numOfPartIn == 2) {
1289 auto incoming = pVert->particles_in();
1290 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1291 }
1292 return false;
1293}
1294
1298
1299 template <class T, class U>
1300 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1301 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1302 auto vtx = p->production_vertex();
1303 if (!vtx) return false;
1304 bool fromHad = false;
1305 for ( const auto& parent : particles_in(vtx) ) {
1306 if (!parent) continue;
1307 // should this really go into parton-level territory?
1308 // probably depends where BSM particles are being decayed
1309 fromBSM |= isBSM(parent);
1310 if (!isPhysical(parent)) return false;
1311 fromTau |= isTau(parent);
1312 if (isHadron(parent)&&!isBeam(parent)) {
1313 if (!hadron) hadron = parent; // assumes linear hadron parentage
1314 return true;
1315 }
1316 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1317 }
1318 return fromHad;
1319 }
1320
1323
1324 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1325 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1326 decltype(thePart->end_vertex()) pVert(nullptr);
1327 if (EndVert != nullptr) {
1328 do {
1329 bool samePart = false;
1330 pVert = nullptr;
1331 auto outgoing = EndVert->particles_out();
1332 auto incoming = EndVert->particles_in();
1333 for (const auto& itrDaug: outgoing) {
1334 if (!itrDaug) continue;
1335 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1336 // brem on generator level for tau
1337 (outgoing.size() == 1 && incoming.size() == 1 &&
1339 itrDaug->pdg_id() == thePart->pdg_id()) {
1340 samePart = true;
1341 pVert = itrDaug->end_vertex();
1342 }
1343 }
1344 if (samePart) EndVert = pVert;
1345 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1346 }
1347 return EndVert;
1348 }
1349
1351
1352 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1353 if (!theVert) return {};
1354 decltype(theVert->particles_out()) finalStatePart;
1355 auto outgoing = theVert->particles_out();
1356 for (const auto& thePart: outgoing) {
1357 if (!thePart) continue;
1358 finalStatePart.push_back(thePart);
1359 if (isStable(thePart)) continue;
1360 V pVert = findSimulatedEndVertex(thePart);
1361 if (pVert == theVert) break; // to prevent Sherpa loop
1362 if (pVert != nullptr) {
1363 auto vecPart = findFinalStateParticles<V>(pVert);
1364 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1365 }
1366 }
1367 return finalStatePart;
1368 }
1369
1370}
1371#endif

◆ isNeutral() [3/3]

template<class T>
bool MC::isNeutral ( const T & p)
inline

Definition at line 1086 of file HepMCHelpers.h.

1107{
1108inline
1109auto particles_in (const HepMC::GenVertex* p) {
1110 return std::ranges::subrange (p->particles_in_const_begin(),
1111 p->particles_in_const_end());
1112}
1113}
1114#endif
1115
1116namespace MC
1117{
1118 template <class VTX>
1119 auto particles_in (const VTX* p) { return p->particles_in(); }
1120 template <class VTX>
1121 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1122
1123 namespace Pythia8
1124 {
1126 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1127
1128 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1129
1130 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1131 }
1132
1133#include "AtlasPID.h"
1134
1136 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1137
1139 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1140
1142 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1143
1145 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1146
1148 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1149
1151 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1152
1154 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1155
1157 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1158
1160 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1161
1163 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1164
1168 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1169 const auto vertex = p->end_vertex();
1170 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1171 }
1172
1174 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1175
1177 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1178 const int apid = std::abs(p->pdg_id());
1179 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1180 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1181 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1182 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1183 return false;
1184 }
1185
1187
1188 template <class T> T findMother(T thePart) {
1189 auto partOriVert = thePart->production_vertex();
1190 if (!partOriVert) return nullptr;
1191
1192 long partPDG = thePart->pdg_id();
1193 long MotherPDG(0);
1194
1195 auto MothOriVert = partOriVert;
1196 MothOriVert = nullptr;
1197 T theMoth(nullptr);
1198
1199 size_t itr = 0;
1200 do {
1201 if (itr != 0) partOriVert = MothOriVert;
1202 for ( const auto& p : particles_in(partOriVert) ) {
1203 theMoth = p;
1204 if (!theMoth) continue;
1205 MotherPDG = theMoth->pdg_id();
1206 MothOriVert = theMoth->production_vertex();
1207 if (MotherPDG == partPDG) break;
1208 }
1209 itr++;
1210 if (itr > 100) {
1211 break;
1212 }
1213 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1214 MothOriVert != partOriVert);
1215 return theMoth;
1216 }
1217
1219
1220 template <class C, class T> T findMatching(C TruthContainer, T p) {
1221 T ptrPart = nullptr;
1222 if (!p) return ptrPart;
1223 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1224 for (T truthParticle : *TruthContainer) {
1225 if (HepMC::is_sim_descendant(p,truthParticle)) {
1226 ptrPart = truthParticle;
1227 break;
1228 }
1229 }
1230 }
1231 else {
1232 for (T truthParticle : TruthContainer) {
1233 if (HepMC::is_sim_descendant(p,truthParticle)) {
1234 ptrPart = truthParticle;
1235 break;
1236 }
1237 }
1238 }
1239 return ptrPart;
1240 }
1242
1243 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1244 auto prodVtx = thePart->production_vertex();
1245 if (!prodVtx) return;
1246 for (const auto& theMother: prodVtx->particles_in()) {
1247 if (!theMother) continue;
1248 allancestors.insert(theMother);
1249 findParticleAncestors(theMother, allancestors);
1250 }
1251 }
1252
1254
1255 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1256 auto endVtx = thePart->end_vertex();
1257 if (!endVtx) return;
1258 for (const auto& theDaughter: endVtx->particles_out()) {
1259 if (!theDaughter) continue;
1260 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1261 allstabledescendants.insert(theDaughter);
1262 }
1263 findParticleStableDescendants(theDaughter, allstabledescendants);
1264 }
1265 }
1266
1270
1271 template <class T> bool isHardScatteringVertex(T pVert) {
1272 if (pVert == nullptr) return false;
1273 T pV = pVert;
1274 int numOfPartIn(0);
1275 int pdg(0);
1276
1277 do {
1278 pVert = pV;
1279 auto incoming = pVert->particles_in();
1280 numOfPartIn = incoming.size();
1281 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1282 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1283
1284 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1285
1286 if (numOfPartIn == 2) {
1287 auto incoming = pVert->particles_in();
1288 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1289 }
1290 return false;
1291}
1292
1296
1297 template <class T, class U>
1298 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1299 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1300 auto vtx = p->production_vertex();
1301 if (!vtx) return false;
1302 bool fromHad = false;
1303 for ( const auto& parent : particles_in(vtx) ) {
1304 if (!parent) continue;
1305 // should this really go into parton-level territory?
1306 // probably depends where BSM particles are being decayed
1307 fromBSM |= isBSM(parent);
1308 if (!isPhysical(parent)) return false;
1309 fromTau |= isTau(parent);
1310 if (isHadron(parent)&&!isBeam(parent)) {
1311 if (!hadron) hadron = parent; // assumes linear hadron parentage
1312 return true;
1313 }
1314 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1315 }
1316 return fromHad;
1317 }
1318
1321
1322 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1323 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1324 decltype(thePart->end_vertex()) pVert(nullptr);
1325 if (EndVert != nullptr) {
1326 do {
1327 bool samePart = false;
1328 pVert = nullptr;
1329 auto outgoing = EndVert->particles_out();
1330 auto incoming = EndVert->particles_in();
1331 for (const auto& itrDaug: outgoing) {
1332 if (!itrDaug) continue;
1333 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1334 // brem on generator level for tau
1335 (outgoing.size() == 1 && incoming.size() == 1 &&
1337 itrDaug->pdg_id() == thePart->pdg_id()) {
1338 samePart = true;
1339 pVert = itrDaug->end_vertex();
1340 }
1341 }
1342 if (samePart) EndVert = pVert;
1343 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1344 }
1345 return EndVert;
1346 }
1347
1349
1350 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1351 if (!theVert) return {};
1352 decltype(theVert->particles_out()) finalStatePart;
1353 auto outgoing = theVert->particles_out();
1354 for (const auto& thePart: outgoing) {
1355 if (!thePart) continue;
1356 finalStatePart.push_back(thePart);
1357 if (isStable(thePart)) continue;
1358 V pVert = findSimulatedEndVertex(thePart);
1359 if (pVert == theVert) break; // to prevent Sherpa loop
1360 if (pVert != nullptr) {
1361 auto vecPart = findFinalStateParticles<V>(pVert);
1362 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1363 }
1364 }
1365 return finalStatePart;
1366 }
1367
1368}
1369#endif

◆ isNeutrino() [1/2]

template<>
bool MC::isNeutrino ( const int & p)
inline

Definition at line 214 of file HepMCHelpers.h.

◆ isNeutrino() [2/2]

template<class T>
bool MC::isNeutrino ( const T & p)
inline

APID: the fourth generation neutrinos are neutrinos.

Definition at line 213 of file HepMCHelpers.h.

213{

◆ isNeutrinoRH() [1/2]

template<>
bool MC::isNeutrinoRH ( const int & p)
inline

Definition at line 422 of file HepMCHelpers.h.

443{
444inline
445auto particles_in (const HepMC::GenVertex* p) {
446 return std::ranges::subrange (p->particles_in_const_begin(),
447 p->particles_in_const_end());
448}
449}
450#endif
451
452namespace MC
453{
454 template <class VTX>
455 auto particles_in (const VTX* p) { return p->particles_in(); }
456 template <class VTX>
457 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
458
459 namespace Pythia8
460 {
462 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
463
464 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
465
466 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
467 }
468
469#include "AtlasPID.h"
470
472 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
473
475 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
476
478 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
479
481 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
482
484 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
485
487 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
488
490 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
491
493 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
494
496 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
497
499 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
500
504 template <class T> inline bool isStableOrSimDecayed(const T& p) {
505 const auto vertex = p->end_vertex();
506 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
507 }
508
510 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
511
513 template <class T> inline bool isSpecialNonInteracting(const T& p) {
514 const int apid = std::abs(p->pdg_id());
515 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
516 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
517 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
518 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
519 return false;
520 }
521
523
524 template <class T> T findMother(T thePart) {
525 auto partOriVert = thePart->production_vertex();
526 if (!partOriVert) return nullptr;
527
528 long partPDG = thePart->pdg_id();
529 long MotherPDG(0);
530
531 auto MothOriVert = partOriVert;
532 MothOriVert = nullptr;
533 T theMoth(nullptr);
534
535 size_t itr = 0;
536 do {
537 if (itr != 0) partOriVert = MothOriVert;
538 for ( const auto& p : particles_in(partOriVert) ) {
539 theMoth = p;
540 if (!theMoth) continue;
541 MotherPDG = theMoth->pdg_id();
542 MothOriVert = theMoth->production_vertex();
543 if (MotherPDG == partPDG) break;
544 }
545 itr++;
546 if (itr > 100) {
547 break;
548 }
549 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
550 MothOriVert != partOriVert);
551 return theMoth;
552 }
553
555
556 template <class C, class T> T findMatching(C TruthContainer, T p) {
557 T ptrPart = nullptr;
558 if (!p) return ptrPart;
559 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
560 for (T truthParticle : *TruthContainer) {
561 if (HepMC::is_sim_descendant(p,truthParticle)) {
562 ptrPart = truthParticle;
563 break;
564 }
565 }
566 }
567 else {
568 for (T truthParticle : TruthContainer) {
569 if (HepMC::is_sim_descendant(p,truthParticle)) {
570 ptrPart = truthParticle;
571 break;
572 }
573 }
574 }
575 return ptrPart;
576 }
578
579 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
580 auto prodVtx = thePart->production_vertex();
581 if (!prodVtx) return;
582 for (const auto& theMother: prodVtx->particles_in()) {
583 if (!theMother) continue;
584 allancestors.insert(theMother);
585 findParticleAncestors(theMother, allancestors);
586 }
587 }
588
590
591 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
592 auto endVtx = thePart->end_vertex();
593 if (!endVtx) return;
594 for (const auto& theDaughter: endVtx->particles_out()) {
595 if (!theDaughter) continue;
596 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
597 allstabledescendants.insert(theDaughter);
598 }
599 findParticleStableDescendants(theDaughter, allstabledescendants);
600 }
601 }
602
606
607 template <class T> bool isHardScatteringVertex(T pVert) {
608 if (pVert == nullptr) return false;
609 T pV = pVert;
610 int numOfPartIn(0);
611 int pdg(0);
612
613 do {
614 pVert = pV;
615 auto incoming = pVert->particles_in();
616 numOfPartIn = incoming.size();
617 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
618 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
619
620 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
621
622 if (numOfPartIn == 2) {
623 auto incoming = pVert->particles_in();
624 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
625 }
626 return false;
627}
628
632
633 template <class T, class U>
634 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
635 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
636 auto vtx = p->production_vertex();
637 if (!vtx) return false;
638 bool fromHad = false;
639 for ( const auto& parent : particles_in(vtx) ) {
640 if (!parent) continue;
641 // should this really go into parton-level territory?
642 // probably depends where BSM particles are being decayed
643 fromBSM |= isBSM(parent);
644 if (!isPhysical(parent)) return false;
645 fromTau |= isTau(parent);
646 if (isHadron(parent)&&!isBeam(parent)) {
647 if (!hadron) hadron = parent; // assumes linear hadron parentage
648 return true;
649 }
650 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
651 }
652 return fromHad;
653 }
654
657
658 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
659 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
660 decltype(thePart->end_vertex()) pVert(nullptr);
661 if (EndVert != nullptr) {
662 do {
663 bool samePart = false;
664 pVert = nullptr;
665 auto outgoing = EndVert->particles_out();
666 auto incoming = EndVert->particles_in();
667 for (const auto& itrDaug: outgoing) {
668 if (!itrDaug) continue;
669 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
670 // brem on generator level for tau
671 (outgoing.size() == 1 && incoming.size() == 1 &&
673 itrDaug->pdg_id() == thePart->pdg_id()) {
674 samePart = true;
675 pVert = itrDaug->end_vertex();
676 }
677 }
678 if (samePart) EndVert = pVert;
679 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
680 }
681 return EndVert;
682 }
683
685
686 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
687 if (!theVert) return {};
688 decltype(theVert->particles_out()) finalStatePart;
689 auto outgoing = theVert->particles_out();
690 for (const auto& thePart: outgoing) {
691 if (!thePart) continue;
692 finalStatePart.push_back(thePart);
693 if (isStable(thePart)) continue;
694 V pVert = findSimulatedEndVertex(thePart);
695 if (pVert == theVert) break; // to prevent Sherpa loop
696 if (pVert != nullptr) {
697 auto vecPart = findFinalStateParticles<V>(pVert);
698 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
699 }
700 }
701 return finalStatePart;
702 }
703
704}
705#endif

◆ isNeutrinoRH() [2/2]

template<class T>
bool MC::isNeutrinoRH ( const T & p)
inline

PDG Rule 12: APID: Helper function for right-handed neutrino states These are generator defined PDG ID values for right handed neutrinos.

(Defined for some MadGraph+Pythia8 samples and referenced in MCTruthClassifierGen.cxx)

Definition at line 421 of file HepMCHelpers.h.

442{
443inline
444auto particles_in (const HepMC::GenVertex* p) {
445 return std::ranges::subrange (p->particles_in_const_begin(),
446 p->particles_in_const_end());
447}
448}
449#endif
450
451namespace MC
452{
453 template <class VTX>
454 auto particles_in (const VTX* p) { return p->particles_in(); }
455 template <class VTX>
456 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
457
458 namespace Pythia8
459 {
461 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
462
463 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
464
465 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
466 }
467
468#include "AtlasPID.h"
469
471 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
472
474 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
475
477 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
478
480 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
481
483 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
484
486 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
487
489 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
490
492 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
493
495 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
496
498 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
499
503 template <class T> inline bool isStableOrSimDecayed(const T& p) {
504 const auto vertex = p->end_vertex();
505 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
506 }
507
509 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
510
512 template <class T> inline bool isSpecialNonInteracting(const T& p) {
513 const int apid = std::abs(p->pdg_id());
514 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
515 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
516 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
517 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
518 return false;
519 }
520
522
523 template <class T> T findMother(T thePart) {
524 auto partOriVert = thePart->production_vertex();
525 if (!partOriVert) return nullptr;
526
527 long partPDG = thePart->pdg_id();
528 long MotherPDG(0);
529
530 auto MothOriVert = partOriVert;
531 MothOriVert = nullptr;
532 T theMoth(nullptr);
533
534 size_t itr = 0;
535 do {
536 if (itr != 0) partOriVert = MothOriVert;
537 for ( const auto& p : particles_in(partOriVert) ) {
538 theMoth = p;
539 if (!theMoth) continue;
540 MotherPDG = theMoth->pdg_id();
541 MothOriVert = theMoth->production_vertex();
542 if (MotherPDG == partPDG) break;
543 }
544 itr++;
545 if (itr > 100) {
546 break;
547 }
548 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
549 MothOriVert != partOriVert);
550 return theMoth;
551 }
552
554
555 template <class C, class T> T findMatching(C TruthContainer, T p) {
556 T ptrPart = nullptr;
557 if (!p) return ptrPart;
558 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
559 for (T truthParticle : *TruthContainer) {
560 if (HepMC::is_sim_descendant(p,truthParticle)) {
561 ptrPart = truthParticle;
562 break;
563 }
564 }
565 }
566 else {
567 for (T truthParticle : TruthContainer) {
568 if (HepMC::is_sim_descendant(p,truthParticle)) {
569 ptrPart = truthParticle;
570 break;
571 }
572 }
573 }
574 return ptrPart;
575 }
577
578 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
579 auto prodVtx = thePart->production_vertex();
580 if (!prodVtx) return;
581 for (const auto& theMother: prodVtx->particles_in()) {
582 if (!theMother) continue;
583 allancestors.insert(theMother);
584 findParticleAncestors(theMother, allancestors);
585 }
586 }
587
589
590 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
591 auto endVtx = thePart->end_vertex();
592 if (!endVtx) return;
593 for (const auto& theDaughter: endVtx->particles_out()) {
594 if (!theDaughter) continue;
595 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
596 allstabledescendants.insert(theDaughter);
597 }
598 findParticleStableDescendants(theDaughter, allstabledescendants);
599 }
600 }
601
605
606 template <class T> bool isHardScatteringVertex(T pVert) {
607 if (pVert == nullptr) return false;
608 T pV = pVert;
609 int numOfPartIn(0);
610 int pdg(0);
611
612 do {
613 pVert = pV;
614 auto incoming = pVert->particles_in();
615 numOfPartIn = incoming.size();
616 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
617 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
618
619 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
620
621 if (numOfPartIn == 2) {
622 auto incoming = pVert->particles_in();
623 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
624 }
625 return false;
626}
627
631
632 template <class T, class U>
633 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
634 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
635 auto vtx = p->production_vertex();
636 if (!vtx) return false;
637 bool fromHad = false;
638 for ( const auto& parent : particles_in(vtx) ) {
639 if (!parent) continue;
640 // should this really go into parton-level territory?
641 // probably depends where BSM particles are being decayed
642 fromBSM |= isBSM(parent);
643 if (!isPhysical(parent)) return false;
644 fromTau |= isTau(parent);
645 if (isHadron(parent)&&!isBeam(parent)) {
646 if (!hadron) hadron = parent; // assumes linear hadron parentage
647 return true;
648 }
649 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
650 }
651 return fromHad;
652 }
653
656
657 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
658 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
659 decltype(thePart->end_vertex()) pVert(nullptr);
660 if (EndVert != nullptr) {
661 do {
662 bool samePart = false;
663 pVert = nullptr;
664 auto outgoing = EndVert->particles_out();
665 auto incoming = EndVert->particles_in();
666 for (const auto& itrDaug: outgoing) {
667 if (!itrDaug) continue;
668 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
669 // brem on generator level for tau
670 (outgoing.size() == 1 && incoming.size() == 1 &&
672 itrDaug->pdg_id() == thePart->pdg_id()) {
673 samePart = true;
674 pVert = itrDaug->end_vertex();
675 }
676 }
677 if (samePart) EndVert = pVert;
678 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
679 }
680 return EndVert;
681 }
682
684
685 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
686 if (!theVert) return {};
687 decltype(theVert->particles_out()) finalStatePart;
688 auto outgoing = theVert->particles_out();
689 for (const auto& thePart: outgoing) {
690 if (!thePart) continue;
691 finalStatePart.push_back(thePart);
692 if (isStable(thePart)) continue;
693 V pVert = findSimulatedEndVertex(thePart);
694 if (pVert == theVert) break; // to prevent Sherpa loop
695 if (pVert != nullptr) {
696 auto vecPart = findFinalStateParticles<V>(pVert);
697 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
698 }
699 }
700 return finalStatePart;
701 }
702
703}
704#endif

◆ isNucleus() [1/3]

template<>
bool MC::isNucleus ( const DecodedPID & p)
inline

Definition at line 704 of file HepMCHelpers.h.

725 {
726inline
727auto particles_in (const HepMC::GenVertex* p) {
728 return std::ranges::subrange (p->particles_in_const_begin(),
729 p->particles_in_const_end());
730}
731}
732#endif
733
734namespace MC
735{
736 template <class VTX>
737 auto particles_in (const VTX* p) { return p->particles_in(); }
738 template <class VTX>
739 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
740
741 namespace Pythia8
742 {
744 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
745
746 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
747
748 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
749 }
750
751#include "AtlasPID.h"
752
754 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
755
757 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
758
760 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
761
763 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
764
766 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
767
769 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
770
772 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
773
775 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
776
778 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
779
781 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
782
786 template <class T> inline bool isStableOrSimDecayed(const T& p) {
787 const auto vertex = p->end_vertex();
788 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
789 }
790
792 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
793
795 template <class T> inline bool isSpecialNonInteracting(const T& p) {
796 const int apid = std::abs(p->pdg_id());
797 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
798 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
799 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
800 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
801 return false;
802 }
803
805
806 template <class T> T findMother(T thePart) {
807 auto partOriVert = thePart->production_vertex();
808 if (!partOriVert) return nullptr;
809
810 long partPDG = thePart->pdg_id();
811 long MotherPDG(0);
812
813 auto MothOriVert = partOriVert;
814 MothOriVert = nullptr;
815 T theMoth(nullptr);
816
817 size_t itr = 0;
818 do {
819 if (itr != 0) partOriVert = MothOriVert;
820 for ( const auto& p : particles_in(partOriVert) ) {
821 theMoth = p;
822 if (!theMoth) continue;
823 MotherPDG = theMoth->pdg_id();
824 MothOriVert = theMoth->production_vertex();
825 if (MotherPDG == partPDG) break;
826 }
827 itr++;
828 if (itr > 100) {
829 break;
830 }
831 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
832 MothOriVert != partOriVert);
833 return theMoth;
834 }
835
837
838 template <class C, class T> T findMatching(C TruthContainer, T p) {
839 T ptrPart = nullptr;
840 if (!p) return ptrPart;
841 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
842 for (T truthParticle : *TruthContainer) {
843 if (HepMC::is_sim_descendant(p,truthParticle)) {
844 ptrPart = truthParticle;
845 break;
846 }
847 }
848 }
849 else {
850 for (T truthParticle : TruthContainer) {
851 if (HepMC::is_sim_descendant(p,truthParticle)) {
852 ptrPart = truthParticle;
853 break;
854 }
855 }
856 }
857 return ptrPart;
858 }
860
861 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
862 auto prodVtx = thePart->production_vertex();
863 if (!prodVtx) return;
864 for (const auto& theMother: prodVtx->particles_in()) {
865 if (!theMother) continue;
866 allancestors.insert(theMother);
867 findParticleAncestors(theMother, allancestors);
868 }
869 }
870
872
873 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
874 auto endVtx = thePart->end_vertex();
875 if (!endVtx) return;
876 for (const auto& theDaughter: endVtx->particles_out()) {
877 if (!theDaughter) continue;
878 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
879 allstabledescendants.insert(theDaughter);
880 }
881 findParticleStableDescendants(theDaughter, allstabledescendants);
882 }
883 }
884
888
889 template <class T> bool isHardScatteringVertex(T pVert) {
890 if (pVert == nullptr) return false;
891 T pV = pVert;
892 int numOfPartIn(0);
893 int pdg(0);
894
895 do {
896 pVert = pV;
897 auto incoming = pVert->particles_in();
898 numOfPartIn = incoming.size();
899 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
900 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
901
902 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
903
904 if (numOfPartIn == 2) {
905 auto incoming = pVert->particles_in();
906 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
907 }
908 return false;
909}
910
914
915 template <class T, class U>
916 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
917 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
918 auto vtx = p->production_vertex();
919 if (!vtx) return false;
920 bool fromHad = false;
921 for ( const auto& parent : particles_in(vtx) ) {
922 if (!parent) continue;
923 // should this really go into parton-level territory?
924 // probably depends where BSM particles are being decayed
925 fromBSM |= isBSM(parent);
926 if (!isPhysical(parent)) return false;
927 fromTau |= isTau(parent);
928 if (isHadron(parent)&&!isBeam(parent)) {
929 if (!hadron) hadron = parent; // assumes linear hadron parentage
930 return true;
931 }
932 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
933 }
934 return fromHad;
935 }
936
939
940 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
941 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
942 decltype(thePart->end_vertex()) pVert(nullptr);
943 if (EndVert != nullptr) {
944 do {
945 bool samePart = false;
946 pVert = nullptr;
947 auto outgoing = EndVert->particles_out();
948 auto incoming = EndVert->particles_in();
949 for (const auto& itrDaug: outgoing) {
950 if (!itrDaug) continue;
951 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
952 // brem on generator level for tau
953 (outgoing.size() == 1 && incoming.size() == 1 &&
955 itrDaug->pdg_id() == thePart->pdg_id()) {
956 samePart = true;
957 pVert = itrDaug->end_vertex();
958 }
959 }
960 if (samePart) EndVert = pVert;
961 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
962 }
963 return EndVert;
964 }
965
967
968 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
969 if (!theVert) return {};
970 decltype(theVert->particles_out()) finalStatePart;
971 auto outgoing = theVert->particles_out();
972 for (const auto& thePart: outgoing) {
973 if (!thePart) continue;
974 finalStatePart.push_back(thePart);
975 if (isStable(thePart)) continue;
976 V pVert = findSimulatedEndVertex(thePart);
977 if (pVert == theVert) break; // to prevent Sherpa loop
978 if (pVert != nullptr) {
979 auto vecPart = findFinalStateParticles<V>(pVert);
980 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
981 }
982 }
983 return finalStatePart;
984 }
985
986}
987#endif

◆ isNucleus() [2/3]

template<>
bool MC::isNucleus ( const int & p)
inline

Definition at line 713 of file HepMCHelpers.h.

734{
735inline
736auto particles_in (const HepMC::GenVertex* p) {
737 return std::ranges::subrange (p->particles_in_const_begin(),
738 p->particles_in_const_end());
739}
740}
741#endif
742
743namespace MC
744{
745 template <class VTX>
746 auto particles_in (const VTX* p) { return p->particles_in(); }
747 template <class VTX>
748 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
749
750 namespace Pythia8
751 {
753 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
754
755 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
756
757 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
758 }
759
760#include "AtlasPID.h"
761
763 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
764
766 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
767
769 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
770
772 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
773
775 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
776
778 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
779
781 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
782
784 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
785
787 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
788
790 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
791
795 template <class T> inline bool isStableOrSimDecayed(const T& p) {
796 const auto vertex = p->end_vertex();
797 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
798 }
799
801 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
802
804 template <class T> inline bool isSpecialNonInteracting(const T& p) {
805 const int apid = std::abs(p->pdg_id());
806 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
807 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
808 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
809 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
810 return false;
811 }
812
814
815 template <class T> T findMother(T thePart) {
816 auto partOriVert = thePart->production_vertex();
817 if (!partOriVert) return nullptr;
818
819 long partPDG = thePart->pdg_id();
820 long MotherPDG(0);
821
822 auto MothOriVert = partOriVert;
823 MothOriVert = nullptr;
824 T theMoth(nullptr);
825
826 size_t itr = 0;
827 do {
828 if (itr != 0) partOriVert = MothOriVert;
829 for ( const auto& p : particles_in(partOriVert) ) {
830 theMoth = p;
831 if (!theMoth) continue;
832 MotherPDG = theMoth->pdg_id();
833 MothOriVert = theMoth->production_vertex();
834 if (MotherPDG == partPDG) break;
835 }
836 itr++;
837 if (itr > 100) {
838 break;
839 }
840 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
841 MothOriVert != partOriVert);
842 return theMoth;
843 }
844
846
847 template <class C, class T> T findMatching(C TruthContainer, T p) {
848 T ptrPart = nullptr;
849 if (!p) return ptrPart;
850 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
851 for (T truthParticle : *TruthContainer) {
852 if (HepMC::is_sim_descendant(p,truthParticle)) {
853 ptrPart = truthParticle;
854 break;
855 }
856 }
857 }
858 else {
859 for (T truthParticle : TruthContainer) {
860 if (HepMC::is_sim_descendant(p,truthParticle)) {
861 ptrPart = truthParticle;
862 break;
863 }
864 }
865 }
866 return ptrPart;
867 }
869
870 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
871 auto prodVtx = thePart->production_vertex();
872 if (!prodVtx) return;
873 for (const auto& theMother: prodVtx->particles_in()) {
874 if (!theMother) continue;
875 allancestors.insert(theMother);
876 findParticleAncestors(theMother, allancestors);
877 }
878 }
879
881
882 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
883 auto endVtx = thePart->end_vertex();
884 if (!endVtx) return;
885 for (const auto& theDaughter: endVtx->particles_out()) {
886 if (!theDaughter) continue;
887 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
888 allstabledescendants.insert(theDaughter);
889 }
890 findParticleStableDescendants(theDaughter, allstabledescendants);
891 }
892 }
893
897
898 template <class T> bool isHardScatteringVertex(T pVert) {
899 if (pVert == nullptr) return false;
900 T pV = pVert;
901 int numOfPartIn(0);
902 int pdg(0);
903
904 do {
905 pVert = pV;
906 auto incoming = pVert->particles_in();
907 numOfPartIn = incoming.size();
908 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
909 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
910
911 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
912
913 if (numOfPartIn == 2) {
914 auto incoming = pVert->particles_in();
915 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
916 }
917 return false;
918}
919
923
924 template <class T, class U>
925 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
926 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
927 auto vtx = p->production_vertex();
928 if (!vtx) return false;
929 bool fromHad = false;
930 for ( const auto& parent : particles_in(vtx) ) {
931 if (!parent) continue;
932 // should this really go into parton-level territory?
933 // probably depends where BSM particles are being decayed
934 fromBSM |= isBSM(parent);
935 if (!isPhysical(parent)) return false;
936 fromTau |= isTau(parent);
937 if (isHadron(parent)&&!isBeam(parent)) {
938 if (!hadron) hadron = parent; // assumes linear hadron parentage
939 return true;
940 }
941 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
942 }
943 return fromHad;
944 }
945
948
949 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
950 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
951 decltype(thePart->end_vertex()) pVert(nullptr);
952 if (EndVert != nullptr) {
953 do {
954 bool samePart = false;
955 pVert = nullptr;
956 auto outgoing = EndVert->particles_out();
957 auto incoming = EndVert->particles_in();
958 for (const auto& itrDaug: outgoing) {
959 if (!itrDaug) continue;
960 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
961 // brem on generator level for tau
962 (outgoing.size() == 1 && incoming.size() == 1 &&
964 itrDaug->pdg_id() == thePart->pdg_id()) {
965 samePart = true;
966 pVert = itrDaug->end_vertex();
967 }
968 }
969 if (samePart) EndVert = pVert;
970 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
971 }
972 return EndVert;
973 }
974
976
977 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
978 if (!theVert) return {};
979 decltype(theVert->particles_out()) finalStatePart;
980 auto outgoing = theVert->particles_out();
981 for (const auto& thePart: outgoing) {
982 if (!thePart) continue;
983 finalStatePart.push_back(thePart);
984 if (isStable(thePart)) continue;
985 V pVert = findSimulatedEndVertex(thePart);
986 if (pVert == theVert) break; // to prevent Sherpa loop
987 if (pVert != nullptr) {
988 auto vecPart = findFinalStateParticles<V>(pVert);
989 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
990 }
991 }
992 return finalStatePart;
993 }
994
995}
996#endif

◆ isNucleus() [3/3]

template<class T>
bool MC::isNucleus ( const T & p)
inline

PDG rule 16 Nuclear codes are given as 10-digit numbers ±10LZZZAAAI.

For a (hyper)nucleus consisting of n_p protons, n_n neutrons and n_Λ Λ’s: A = n_p + n_n + n_Λ gives the total baryon number, Z = n_p gives the total charge, L = n_Λ gives the total number of strange quarks. I gives the isomer level, with I= 0 corresponding to the ground state and I > 0 to excitations, see [http://www.nndc.bnl.gov/amdc/web/nubase en.html], where states denoted m, n, p ,q translate to I= 1–4. As examples, the deuteron is 1000010020 and 235U is 1000922350. To avoid ambiguities, nuclear codes should not be applied to a single hadron, like p, n or Λ^0, where quark-contents-based codes already exist.

Definition at line 703 of file HepMCHelpers.h.

724{
725inline
726auto particles_in (const HepMC::GenVertex* p) {
727 return std::ranges::subrange (p->particles_in_const_begin(),
728 p->particles_in_const_end());
729}
730}
731#endif
732
733namespace MC
734{
735 template <class VTX>
736 auto particles_in (const VTX* p) { return p->particles_in(); }
737 template <class VTX>
738 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
739
740 namespace Pythia8
741 {
743 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
744
745 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
746
747 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
748 }
749
750#include "AtlasPID.h"
751
753 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
754
756 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
757
759 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
760
762 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
763
765 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
766
768 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
769
771 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
772
774 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
775
777 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
778
780 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
781
785 template <class T> inline bool isStableOrSimDecayed(const T& p) {
786 const auto vertex = p->end_vertex();
787 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
788 }
789
791 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
792
794 template <class T> inline bool isSpecialNonInteracting(const T& p) {
795 const int apid = std::abs(p->pdg_id());
796 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
797 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
798 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
799 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
800 return false;
801 }
802
804
805 template <class T> T findMother(T thePart) {
806 auto partOriVert = thePart->production_vertex();
807 if (!partOriVert) return nullptr;
808
809 long partPDG = thePart->pdg_id();
810 long MotherPDG(0);
811
812 auto MothOriVert = partOriVert;
813 MothOriVert = nullptr;
814 T theMoth(nullptr);
815
816 size_t itr = 0;
817 do {
818 if (itr != 0) partOriVert = MothOriVert;
819 for ( const auto& p : particles_in(partOriVert) ) {
820 theMoth = p;
821 if (!theMoth) continue;
822 MotherPDG = theMoth->pdg_id();
823 MothOriVert = theMoth->production_vertex();
824 if (MotherPDG == partPDG) break;
825 }
826 itr++;
827 if (itr > 100) {
828 break;
829 }
830 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
831 MothOriVert != partOriVert);
832 return theMoth;
833 }
834
836
837 template <class C, class T> T findMatching(C TruthContainer, T p) {
838 T ptrPart = nullptr;
839 if (!p) return ptrPart;
840 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
841 for (T truthParticle : *TruthContainer) {
842 if (HepMC::is_sim_descendant(p,truthParticle)) {
843 ptrPart = truthParticle;
844 break;
845 }
846 }
847 }
848 else {
849 for (T truthParticle : TruthContainer) {
850 if (HepMC::is_sim_descendant(p,truthParticle)) {
851 ptrPart = truthParticle;
852 break;
853 }
854 }
855 }
856 return ptrPart;
857 }
859
860 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
861 auto prodVtx = thePart->production_vertex();
862 if (!prodVtx) return;
863 for (const auto& theMother: prodVtx->particles_in()) {
864 if (!theMother) continue;
865 allancestors.insert(theMother);
866 findParticleAncestors(theMother, allancestors);
867 }
868 }
869
871
872 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
873 auto endVtx = thePart->end_vertex();
874 if (!endVtx) return;
875 for (const auto& theDaughter: endVtx->particles_out()) {
876 if (!theDaughter) continue;
877 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
878 allstabledescendants.insert(theDaughter);
879 }
880 findParticleStableDescendants(theDaughter, allstabledescendants);
881 }
882 }
883
887
888 template <class T> bool isHardScatteringVertex(T pVert) {
889 if (pVert == nullptr) return false;
890 T pV = pVert;
891 int numOfPartIn(0);
892 int pdg(0);
893
894 do {
895 pVert = pV;
896 auto incoming = pVert->particles_in();
897 numOfPartIn = incoming.size();
898 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
899 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
900
901 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
902
903 if (numOfPartIn == 2) {
904 auto incoming = pVert->particles_in();
905 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
906 }
907 return false;
908}
909
913
914 template <class T, class U>
915 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
916 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
917 auto vtx = p->production_vertex();
918 if (!vtx) return false;
919 bool fromHad = false;
920 for ( const auto& parent : particles_in(vtx) ) {
921 if (!parent) continue;
922 // should this really go into parton-level territory?
923 // probably depends where BSM particles are being decayed
924 fromBSM |= isBSM(parent);
925 if (!isPhysical(parent)) return false;
926 fromTau |= isTau(parent);
927 if (isHadron(parent)&&!isBeam(parent)) {
928 if (!hadron) hadron = parent; // assumes linear hadron parentage
929 return true;
930 }
931 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
932 }
933 return fromHad;
934 }
935
938
939 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
940 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
941 decltype(thePart->end_vertex()) pVert(nullptr);
942 if (EndVert != nullptr) {
943 do {
944 bool samePart = false;
945 pVert = nullptr;
946 auto outgoing = EndVert->particles_out();
947 auto incoming = EndVert->particles_in();
948 for (const auto& itrDaug: outgoing) {
949 if (!itrDaug) continue;
950 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
951 // brem on generator level for tau
952 (outgoing.size() == 1 && incoming.size() == 1 &&
954 itrDaug->pdg_id() == thePart->pdg_id()) {
955 samePart = true;
956 pVert = itrDaug->end_vertex();
957 }
958 }
959 if (samePart) EndVert = pVert;
960 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
961 }
962 return EndVert;
963 }
964
966
967 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
968 if (!theVert) return {};
969 decltype(theVert->particles_out()) finalStatePart;
970 auto outgoing = theVert->particles_out();
971 for (const auto& thePart: outgoing) {
972 if (!thePart) continue;
973 finalStatePart.push_back(thePart);
974 if (isStable(thePart)) continue;
975 V pVert = findSimulatedEndVertex(thePart);
976 if (pVert == theVert) break; // to prevent Sherpa loop
977 if (pVert != nullptr) {
978 auto vecPart = findFinalStateParticles<V>(pVert);
979 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
980 }
981 }
982 return finalStatePart;
983 }
984
985}
986#endif

◆ isParton()

template<class T>
bool MC::isParton ( const T & p)
inline

Definition at line 1104 of file HepMCHelpers.h.

1125{
1126inline
1127auto particles_in (const HepMC::GenVertex* p) {
1128 return std::ranges::subrange (p->particles_in_const_begin(),
1129 p->particles_in_const_end());
1130}
1131}
1132#endif
1133
1134namespace MC
1135{
1136 template <class VTX>
1137 auto particles_in (const VTX* p) { return p->particles_in(); }
1138 template <class VTX>
1139 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1140
1141 namespace Pythia8
1142 {
1144 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1145
1146 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1147
1148 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1149 }
1150
1151#include "AtlasPID.h"
1152
1154 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1155
1157 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1158
1160 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1161
1163 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1164
1166 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1167
1169 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1170
1172 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1173
1175 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1176
1178 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1179
1181 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1182
1186 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1187 const auto vertex = p->end_vertex();
1188 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1189 }
1190
1192 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1193
1195 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1196 const int apid = std::abs(p->pdg_id());
1197 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1198 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1199 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1200 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1201 return false;
1202 }
1203
1205
1206 template <class T> T findMother(T thePart) {
1207 auto partOriVert = thePart->production_vertex();
1208 if (!partOriVert) return nullptr;
1209
1210 long partPDG = thePart->pdg_id();
1211 long MotherPDG(0);
1212
1213 auto MothOriVert = partOriVert;
1214 MothOriVert = nullptr;
1215 T theMoth(nullptr);
1216
1217 size_t itr = 0;
1218 do {
1219 if (itr != 0) partOriVert = MothOriVert;
1220 for ( const auto& p : particles_in(partOriVert) ) {
1221 theMoth = p;
1222 if (!theMoth) continue;
1223 MotherPDG = theMoth->pdg_id();
1224 MothOriVert = theMoth->production_vertex();
1225 if (MotherPDG == partPDG) break;
1226 }
1227 itr++;
1228 if (itr > 100) {
1229 break;
1230 }
1231 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1232 MothOriVert != partOriVert);
1233 return theMoth;
1234 }
1235
1237
1238 template <class C, class T> T findMatching(C TruthContainer, T p) {
1239 T ptrPart = nullptr;
1240 if (!p) return ptrPart;
1241 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1242 for (T truthParticle : *TruthContainer) {
1243 if (HepMC::is_sim_descendant(p,truthParticle)) {
1244 ptrPart = truthParticle;
1245 break;
1246 }
1247 }
1248 }
1249 else {
1250 for (T truthParticle : TruthContainer) {
1251 if (HepMC::is_sim_descendant(p,truthParticle)) {
1252 ptrPart = truthParticle;
1253 break;
1254 }
1255 }
1256 }
1257 return ptrPart;
1258 }
1260
1261 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1262 auto prodVtx = thePart->production_vertex();
1263 if (!prodVtx) return;
1264 for (const auto& theMother: prodVtx->particles_in()) {
1265 if (!theMother) continue;
1266 allancestors.insert(theMother);
1267 findParticleAncestors(theMother, allancestors);
1268 }
1269 }
1270
1272
1273 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1274 auto endVtx = thePart->end_vertex();
1275 if (!endVtx) return;
1276 for (const auto& theDaughter: endVtx->particles_out()) {
1277 if (!theDaughter) continue;
1278 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1279 allstabledescendants.insert(theDaughter);
1280 }
1281 findParticleStableDescendants(theDaughter, allstabledescendants);
1282 }
1283 }
1284
1288
1289 template <class T> bool isHardScatteringVertex(T pVert) {
1290 if (pVert == nullptr) return false;
1291 T pV = pVert;
1292 int numOfPartIn(0);
1293 int pdg(0);
1294
1295 do {
1296 pVert = pV;
1297 auto incoming = pVert->particles_in();
1298 numOfPartIn = incoming.size();
1299 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1300 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1301
1302 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1303
1304 if (numOfPartIn == 2) {
1305 auto incoming = pVert->particles_in();
1306 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1307 }
1308 return false;
1309}
1310
1314
1315 template <class T, class U>
1316 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1317 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1318 auto vtx = p->production_vertex();
1319 if (!vtx) return false;
1320 bool fromHad = false;
1321 for ( const auto& parent : particles_in(vtx) ) {
1322 if (!parent) continue;
1323 // should this really go into parton-level territory?
1324 // probably depends where BSM particles are being decayed
1325 fromBSM |= isBSM(parent);
1326 if (!isPhysical(parent)) return false;
1327 fromTau |= isTau(parent);
1328 if (isHadron(parent)&&!isBeam(parent)) {
1329 if (!hadron) hadron = parent; // assumes linear hadron parentage
1330 return true;
1331 }
1332 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1333 }
1334 return fromHad;
1335 }
1336
1339
1340 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1341 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1342 decltype(thePart->end_vertex()) pVert(nullptr);
1343 if (EndVert != nullptr) {
1344 do {
1345 bool samePart = false;
1346 pVert = nullptr;
1347 auto outgoing = EndVert->particles_out();
1348 auto incoming = EndVert->particles_in();
1349 for (const auto& itrDaug: outgoing) {
1350 if (!itrDaug) continue;
1351 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1352 // brem on generator level for tau
1353 (outgoing.size() == 1 && incoming.size() == 1 &&
1355 itrDaug->pdg_id() == thePart->pdg_id()) {
1356 samePart = true;
1357 pVert = itrDaug->end_vertex();
1358 }
1359 }
1360 if (samePart) EndVert = pVert;
1361 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1362 }
1363 return EndVert;
1364 }
1365
1367
1368 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1369 if (!theVert) return {};
1370 decltype(theVert->particles_out()) finalStatePart;
1371 auto outgoing = theVert->particles_out();
1372 for (const auto& thePart: outgoing) {
1373 if (!thePart) continue;
1374 finalStatePart.push_back(thePart);
1375 if (isStable(thePart)) continue;
1376 V pVert = findSimulatedEndVertex(thePart);
1377 if (pVert == theVert) break; // to prevent Sherpa loop
1378 if (pVert != nullptr) {
1379 auto vecPart = findFinalStateParticles<V>(pVert);
1380 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1381 }
1382 }
1383 return finalStatePart;
1384 }
1385
1386}
1387#endif

◆ isPentaquark() [1/3]

template<>
bool MC::isPentaquark ( const DecodedPID & p)
inline

Definition at line 344 of file HepMCHelpers.h.

365 {
366inline
367auto particles_in (const HepMC::GenVertex* p) {
368 return std::ranges::subrange (p->particles_in_const_begin(),
369 p->particles_in_const_end());
370}
371}
372#endif
373
374namespace MC
375{
376 template <class VTX>
377 auto particles_in (const VTX* p) { return p->particles_in(); }
378 template <class VTX>
379 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
380
381 namespace Pythia8
382 {
384 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
385
386 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
387
388 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
389 }
390
391#include "AtlasPID.h"
392
394 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
395
397 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
398
400 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
401
403 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
404
406 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
407
409 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
410
412 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
413
415 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
416
418 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
419
421 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
422
426 template <class T> inline bool isStableOrSimDecayed(const T& p) {
427 const auto vertex = p->end_vertex();
428 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
429 }
430
432 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
433
435 template <class T> inline bool isSpecialNonInteracting(const T& p) {
436 const int apid = std::abs(p->pdg_id());
437 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
438 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
439 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
440 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
441 return false;
442 }
443
445
446 template <class T> T findMother(T thePart) {
447 auto partOriVert = thePart->production_vertex();
448 if (!partOriVert) return nullptr;
449
450 long partPDG = thePart->pdg_id();
451 long MotherPDG(0);
452
453 auto MothOriVert = partOriVert;
454 MothOriVert = nullptr;
455 T theMoth(nullptr);
456
457 size_t itr = 0;
458 do {
459 if (itr != 0) partOriVert = MothOriVert;
460 for ( const auto& p : particles_in(partOriVert) ) {
461 theMoth = p;
462 if (!theMoth) continue;
463 MotherPDG = theMoth->pdg_id();
464 MothOriVert = theMoth->production_vertex();
465 if (MotherPDG == partPDG) break;
466 }
467 itr++;
468 if (itr > 100) {
469 break;
470 }
471 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
472 MothOriVert != partOriVert);
473 return theMoth;
474 }
475
477
478 template <class C, class T> T findMatching(C TruthContainer, T p) {
479 T ptrPart = nullptr;
480 if (!p) return ptrPart;
481 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
482 for (T truthParticle : *TruthContainer) {
483 if (HepMC::is_sim_descendant(p,truthParticle)) {
484 ptrPart = truthParticle;
485 break;
486 }
487 }
488 }
489 else {
490 for (T truthParticle : TruthContainer) {
491 if (HepMC::is_sim_descendant(p,truthParticle)) {
492 ptrPart = truthParticle;
493 break;
494 }
495 }
496 }
497 return ptrPart;
498 }
500
501 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
502 auto prodVtx = thePart->production_vertex();
503 if (!prodVtx) return;
504 for (const auto& theMother: prodVtx->particles_in()) {
505 if (!theMother) continue;
506 allancestors.insert(theMother);
507 findParticleAncestors(theMother, allancestors);
508 }
509 }
510
512
513 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
514 auto endVtx = thePart->end_vertex();
515 if (!endVtx) return;
516 for (const auto& theDaughter: endVtx->particles_out()) {
517 if (!theDaughter) continue;
518 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
519 allstabledescendants.insert(theDaughter);
520 }
521 findParticleStableDescendants(theDaughter, allstabledescendants);
522 }
523 }
524
528
529 template <class T> bool isHardScatteringVertex(T pVert) {
530 if (pVert == nullptr) return false;
531 T pV = pVert;
532 int numOfPartIn(0);
533 int pdg(0);
534
535 do {
536 pVert = pV;
537 auto incoming = pVert->particles_in();
538 numOfPartIn = incoming.size();
539 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
540 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
541
542 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
543
544 if (numOfPartIn == 2) {
545 auto incoming = pVert->particles_in();
546 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
547 }
548 return false;
549}
550
554
555 template <class T, class U>
556 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
557 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
558 auto vtx = p->production_vertex();
559 if (!vtx) return false;
560 bool fromHad = false;
561 for ( const auto& parent : particles_in(vtx) ) {
562 if (!parent) continue;
563 // should this really go into parton-level territory?
564 // probably depends where BSM particles are being decayed
565 fromBSM |= isBSM(parent);
566 if (!isPhysical(parent)) return false;
567 fromTau |= isTau(parent);
568 if (isHadron(parent)&&!isBeam(parent)) {
569 if (!hadron) hadron = parent; // assumes linear hadron parentage
570 return true;
571 }
572 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
573 }
574 return fromHad;
575 }
576
579
580 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
581 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
582 decltype(thePart->end_vertex()) pVert(nullptr);
583 if (EndVert != nullptr) {
584 do {
585 bool samePart = false;
586 pVert = nullptr;
587 auto outgoing = EndVert->particles_out();
588 auto incoming = EndVert->particles_in();
589 for (const auto& itrDaug: outgoing) {
590 if (!itrDaug) continue;
591 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
592 // brem on generator level for tau
593 (outgoing.size() == 1 && incoming.size() == 1 &&
595 itrDaug->pdg_id() == thePart->pdg_id()) {
596 samePart = true;
597 pVert = itrDaug->end_vertex();
598 }
599 }
600 if (samePart) EndVert = pVert;
601 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
602 }
603 return EndVert;
604 }
605
607
608 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
609 if (!theVert) return {};
610 decltype(theVert->particles_out()) finalStatePart;
611 auto outgoing = theVert->particles_out();
612 for (const auto& thePart: outgoing) {
613 if (!thePart) continue;
614 finalStatePart.push_back(thePart);
615 if (isStable(thePart)) continue;
616 V pVert = findSimulatedEndVertex(thePart);
617 if (pVert == theVert) break; // to prevent Sherpa loop
618 if (pVert != nullptr) {
619 auto vecPart = findFinalStateParticles<V>(pVert);
620 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
621 }
622 }
623 return finalStatePart;
624 }
625
626}
627#endif

◆ isPentaquark() [2/3]

template<>
bool MC::isPentaquark ( const int & p)
inline

Definition at line 349 of file HepMCHelpers.h.

370{
371inline
372auto particles_in (const HepMC::GenVertex* p) {
373 return std::ranges::subrange (p->particles_in_const_begin(),
374 p->particles_in_const_end());
375}
376}
377#endif
378
379namespace MC
380{
381 template <class VTX>
382 auto particles_in (const VTX* p) { return p->particles_in(); }
383 template <class VTX>
384 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
385
386 namespace Pythia8
387 {
389 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
390
391 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
392
393 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
394 }
395
396#include "AtlasPID.h"
397
399 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
400
402 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
403
405 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
406
408 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
409
411 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
412
414 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
415
417 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
418
420 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
421
423 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
424
426 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
427
431 template <class T> inline bool isStableOrSimDecayed(const T& p) {
432 const auto vertex = p->end_vertex();
433 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
434 }
435
437 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
438
440 template <class T> inline bool isSpecialNonInteracting(const T& p) {
441 const int apid = std::abs(p->pdg_id());
442 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
443 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
444 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
445 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
446 return false;
447 }
448
450
451 template <class T> T findMother(T thePart) {
452 auto partOriVert = thePart->production_vertex();
453 if (!partOriVert) return nullptr;
454
455 long partPDG = thePart->pdg_id();
456 long MotherPDG(0);
457
458 auto MothOriVert = partOriVert;
459 MothOriVert = nullptr;
460 T theMoth(nullptr);
461
462 size_t itr = 0;
463 do {
464 if (itr != 0) partOriVert = MothOriVert;
465 for ( const auto& p : particles_in(partOriVert) ) {
466 theMoth = p;
467 if (!theMoth) continue;
468 MotherPDG = theMoth->pdg_id();
469 MothOriVert = theMoth->production_vertex();
470 if (MotherPDG == partPDG) break;
471 }
472 itr++;
473 if (itr > 100) {
474 break;
475 }
476 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
477 MothOriVert != partOriVert);
478 return theMoth;
479 }
480
482
483 template <class C, class T> T findMatching(C TruthContainer, T p) {
484 T ptrPart = nullptr;
485 if (!p) return ptrPart;
486 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
487 for (T truthParticle : *TruthContainer) {
488 if (HepMC::is_sim_descendant(p,truthParticle)) {
489 ptrPart = truthParticle;
490 break;
491 }
492 }
493 }
494 else {
495 for (T truthParticle : TruthContainer) {
496 if (HepMC::is_sim_descendant(p,truthParticle)) {
497 ptrPart = truthParticle;
498 break;
499 }
500 }
501 }
502 return ptrPart;
503 }
505
506 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
507 auto prodVtx = thePart->production_vertex();
508 if (!prodVtx) return;
509 for (const auto& theMother: prodVtx->particles_in()) {
510 if (!theMother) continue;
511 allancestors.insert(theMother);
512 findParticleAncestors(theMother, allancestors);
513 }
514 }
515
517
518 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
519 auto endVtx = thePart->end_vertex();
520 if (!endVtx) return;
521 for (const auto& theDaughter: endVtx->particles_out()) {
522 if (!theDaughter) continue;
523 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
524 allstabledescendants.insert(theDaughter);
525 }
526 findParticleStableDescendants(theDaughter, allstabledescendants);
527 }
528 }
529
533
534 template <class T> bool isHardScatteringVertex(T pVert) {
535 if (pVert == nullptr) return false;
536 T pV = pVert;
537 int numOfPartIn(0);
538 int pdg(0);
539
540 do {
541 pVert = pV;
542 auto incoming = pVert->particles_in();
543 numOfPartIn = incoming.size();
544 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
545 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
546
547 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
548
549 if (numOfPartIn == 2) {
550 auto incoming = pVert->particles_in();
551 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
552 }
553 return false;
554}
555
559
560 template <class T, class U>
561 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
562 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
563 auto vtx = p->production_vertex();
564 if (!vtx) return false;
565 bool fromHad = false;
566 for ( const auto& parent : particles_in(vtx) ) {
567 if (!parent) continue;
568 // should this really go into parton-level territory?
569 // probably depends where BSM particles are being decayed
570 fromBSM |= isBSM(parent);
571 if (!isPhysical(parent)) return false;
572 fromTau |= isTau(parent);
573 if (isHadron(parent)&&!isBeam(parent)) {
574 if (!hadron) hadron = parent; // assumes linear hadron parentage
575 return true;
576 }
577 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
578 }
579 return fromHad;
580 }
581
584
585 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
586 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
587 decltype(thePart->end_vertex()) pVert(nullptr);
588 if (EndVert != nullptr) {
589 do {
590 bool samePart = false;
591 pVert = nullptr;
592 auto outgoing = EndVert->particles_out();
593 auto incoming = EndVert->particles_in();
594 for (const auto& itrDaug: outgoing) {
595 if (!itrDaug) continue;
596 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
597 // brem on generator level for tau
598 (outgoing.size() == 1 && incoming.size() == 1 &&
600 itrDaug->pdg_id() == thePart->pdg_id()) {
601 samePart = true;
602 pVert = itrDaug->end_vertex();
603 }
604 }
605 if (samePart) EndVert = pVert;
606 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
607 }
608 return EndVert;
609 }
610
612
613 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
614 if (!theVert) return {};
615 decltype(theVert->particles_out()) finalStatePart;
616 auto outgoing = theVert->particles_out();
617 for (const auto& thePart: outgoing) {
618 if (!thePart) continue;
619 finalStatePart.push_back(thePart);
620 if (isStable(thePart)) continue;
621 V pVert = findSimulatedEndVertex(thePart);
622 if (pVert == theVert) break; // to prevent Sherpa loop
623 if (pVert != nullptr) {
624 auto vecPart = findFinalStateParticles<V>(pVert);
625 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
626 }
627 }
628 return finalStatePart;
629 }
630
631}
632#endif

◆ isPentaquark() [3/3]

template<class T>
bool MC::isPentaquark ( const T & p)
inline

PDG rule 15 The 9-digit penta-quark codes are ±1nrnLnq1nq2nq3nq4nq5nJ, sorted such that nq1≥nq2≥nq3≥nq4.

In the particle the first four are quarks and the fifth an antiquark while the opposite holds in the antiparticle, which is given with a negative sign. The nr, nL, and nJ numbers have the same meaning as for ordinary hadrons.

Definition at line 343 of file HepMCHelpers.h.

364{
365inline
366auto particles_in (const HepMC::GenVertex* p) {
367 return std::ranges::subrange (p->particles_in_const_begin(),
368 p->particles_in_const_end());
369}
370}
371#endif
372
373namespace MC
374{
375 template <class VTX>
376 auto particles_in (const VTX* p) { return p->particles_in(); }
377 template <class VTX>
378 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
379
380 namespace Pythia8
381 {
383 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
384
385 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
386
387 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
388 }
389
390#include "AtlasPID.h"
391
393 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
394
396 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
397
399 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
400
402 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
403
405 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
406
408 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
409
411 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
412
414 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
415
417 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
418
420 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
421
425 template <class T> inline bool isStableOrSimDecayed(const T& p) {
426 const auto vertex = p->end_vertex();
427 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
428 }
429
431 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
432
434 template <class T> inline bool isSpecialNonInteracting(const T& p) {
435 const int apid = std::abs(p->pdg_id());
436 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
437 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
438 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
439 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
440 return false;
441 }
442
444
445 template <class T> T findMother(T thePart) {
446 auto partOriVert = thePart->production_vertex();
447 if (!partOriVert) return nullptr;
448
449 long partPDG = thePart->pdg_id();
450 long MotherPDG(0);
451
452 auto MothOriVert = partOriVert;
453 MothOriVert = nullptr;
454 T theMoth(nullptr);
455
456 size_t itr = 0;
457 do {
458 if (itr != 0) partOriVert = MothOriVert;
459 for ( const auto& p : particles_in(partOriVert) ) {
460 theMoth = p;
461 if (!theMoth) continue;
462 MotherPDG = theMoth->pdg_id();
463 MothOriVert = theMoth->production_vertex();
464 if (MotherPDG == partPDG) break;
465 }
466 itr++;
467 if (itr > 100) {
468 break;
469 }
470 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
471 MothOriVert != partOriVert);
472 return theMoth;
473 }
474
476
477 template <class C, class T> T findMatching(C TruthContainer, T p) {
478 T ptrPart = nullptr;
479 if (!p) return ptrPart;
480 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
481 for (T truthParticle : *TruthContainer) {
482 if (HepMC::is_sim_descendant(p,truthParticle)) {
483 ptrPart = truthParticle;
484 break;
485 }
486 }
487 }
488 else {
489 for (T truthParticle : TruthContainer) {
490 if (HepMC::is_sim_descendant(p,truthParticle)) {
491 ptrPart = truthParticle;
492 break;
493 }
494 }
495 }
496 return ptrPart;
497 }
499
500 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
501 auto prodVtx = thePart->production_vertex();
502 if (!prodVtx) return;
503 for (const auto& theMother: prodVtx->particles_in()) {
504 if (!theMother) continue;
505 allancestors.insert(theMother);
506 findParticleAncestors(theMother, allancestors);
507 }
508 }
509
511
512 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
513 auto endVtx = thePart->end_vertex();
514 if (!endVtx) return;
515 for (const auto& theDaughter: endVtx->particles_out()) {
516 if (!theDaughter) continue;
517 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
518 allstabledescendants.insert(theDaughter);
519 }
520 findParticleStableDescendants(theDaughter, allstabledescendants);
521 }
522 }
523
527
528 template <class T> bool isHardScatteringVertex(T pVert) {
529 if (pVert == nullptr) return false;
530 T pV = pVert;
531 int numOfPartIn(0);
532 int pdg(0);
533
534 do {
535 pVert = pV;
536 auto incoming = pVert->particles_in();
537 numOfPartIn = incoming.size();
538 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
539 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
540
541 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
542
543 if (numOfPartIn == 2) {
544 auto incoming = pVert->particles_in();
545 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
546 }
547 return false;
548}
549
553
554 template <class T, class U>
555 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
556 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
557 auto vtx = p->production_vertex();
558 if (!vtx) return false;
559 bool fromHad = false;
560 for ( const auto& parent : particles_in(vtx) ) {
561 if (!parent) continue;
562 // should this really go into parton-level territory?
563 // probably depends where BSM particles are being decayed
564 fromBSM |= isBSM(parent);
565 if (!isPhysical(parent)) return false;
566 fromTau |= isTau(parent);
567 if (isHadron(parent)&&!isBeam(parent)) {
568 if (!hadron) hadron = parent; // assumes linear hadron parentage
569 return true;
570 }
571 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
572 }
573 return fromHad;
574 }
575
578
579 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
580 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
581 decltype(thePart->end_vertex()) pVert(nullptr);
582 if (EndVert != nullptr) {
583 do {
584 bool samePart = false;
585 pVert = nullptr;
586 auto outgoing = EndVert->particles_out();
587 auto incoming = EndVert->particles_in();
588 for (const auto& itrDaug: outgoing) {
589 if (!itrDaug) continue;
590 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
591 // brem on generator level for tau
592 (outgoing.size() == 1 && incoming.size() == 1 &&
594 itrDaug->pdg_id() == thePart->pdg_id()) {
595 samePart = true;
596 pVert = itrDaug->end_vertex();
597 }
598 }
599 if (samePart) EndVert = pVert;
600 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
601 }
602 return EndVert;
603 }
604
606
607 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
608 if (!theVert) return {};
609 decltype(theVert->particles_out()) finalStatePart;
610 auto outgoing = theVert->particles_out();
611 for (const auto& thePart: outgoing) {
612 if (!thePart) continue;
613 finalStatePart.push_back(thePart);
614 if (isStable(thePart)) continue;
615 V pVert = findSimulatedEndVertex(thePart);
616 if (pVert == theVert) break; // to prevent Sherpa loop
617 if (pVert != nullptr) {
618 auto vecPart = findFinalStateParticles<V>(pVert);
619 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
620 }
621 }
622 return finalStatePart;
623 }
624
625}
626#endif

◆ isPhoton() [1/2]

template<>
bool MC::isPhoton ( const int & p)
inline

Definition at line 378 of file HepMCHelpers.h.

399{
400inline
401auto particles_in (const HepMC::GenVertex* p) {
402 return std::ranges::subrange (p->particles_in_const_begin(),
403 p->particles_in_const_end());
404}
405}
406#endif
407
408namespace MC
409{
410 template <class VTX>
411 auto particles_in (const VTX* p) { return p->particles_in(); }
412 template <class VTX>
413 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
414
415 namespace Pythia8
416 {
418 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
419
420 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
421
422 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
423 }
424
425#include "AtlasPID.h"
426
428 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
429
431 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
432
434 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
435
437 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
438
440 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
441
443 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
444
446 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
447
449 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
450
452 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
453
455 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
456
460 template <class T> inline bool isStableOrSimDecayed(const T& p) {
461 const auto vertex = p->end_vertex();
462 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
463 }
464
466 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
467
469 template <class T> inline bool isSpecialNonInteracting(const T& p) {
470 const int apid = std::abs(p->pdg_id());
471 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
472 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
473 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
474 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
475 return false;
476 }
477
479
480 template <class T> T findMother(T thePart) {
481 auto partOriVert = thePart->production_vertex();
482 if (!partOriVert) return nullptr;
483
484 long partPDG = thePart->pdg_id();
485 long MotherPDG(0);
486
487 auto MothOriVert = partOriVert;
488 MothOriVert = nullptr;
489 T theMoth(nullptr);
490
491 size_t itr = 0;
492 do {
493 if (itr != 0) partOriVert = MothOriVert;
494 for ( const auto& p : particles_in(partOriVert) ) {
495 theMoth = p;
496 if (!theMoth) continue;
497 MotherPDG = theMoth->pdg_id();
498 MothOriVert = theMoth->production_vertex();
499 if (MotherPDG == partPDG) break;
500 }
501 itr++;
502 if (itr > 100) {
503 break;
504 }
505 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
506 MothOriVert != partOriVert);
507 return theMoth;
508 }
509
511
512 template <class C, class T> T findMatching(C TruthContainer, T p) {
513 T ptrPart = nullptr;
514 if (!p) return ptrPart;
515 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
516 for (T truthParticle : *TruthContainer) {
517 if (HepMC::is_sim_descendant(p,truthParticle)) {
518 ptrPart = truthParticle;
519 break;
520 }
521 }
522 }
523 else {
524 for (T truthParticle : TruthContainer) {
525 if (HepMC::is_sim_descendant(p,truthParticle)) {
526 ptrPart = truthParticle;
527 break;
528 }
529 }
530 }
531 return ptrPart;
532 }
534
535 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
536 auto prodVtx = thePart->production_vertex();
537 if (!prodVtx) return;
538 for (const auto& theMother: prodVtx->particles_in()) {
539 if (!theMother) continue;
540 allancestors.insert(theMother);
541 findParticleAncestors(theMother, allancestors);
542 }
543 }
544
546
547 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
548 auto endVtx = thePart->end_vertex();
549 if (!endVtx) return;
550 for (const auto& theDaughter: endVtx->particles_out()) {
551 if (!theDaughter) continue;
552 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
553 allstabledescendants.insert(theDaughter);
554 }
555 findParticleStableDescendants(theDaughter, allstabledescendants);
556 }
557 }
558
562
563 template <class T> bool isHardScatteringVertex(T pVert) {
564 if (pVert == nullptr) return false;
565 T pV = pVert;
566 int numOfPartIn(0);
567 int pdg(0);
568
569 do {
570 pVert = pV;
571 auto incoming = pVert->particles_in();
572 numOfPartIn = incoming.size();
573 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
574 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
575
576 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
577
578 if (numOfPartIn == 2) {
579 auto incoming = pVert->particles_in();
580 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
581 }
582 return false;
583}
584
588
589 template <class T, class U>
590 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
591 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
592 auto vtx = p->production_vertex();
593 if (!vtx) return false;
594 bool fromHad = false;
595 for ( const auto& parent : particles_in(vtx) ) {
596 if (!parent) continue;
597 // should this really go into parton-level territory?
598 // probably depends where BSM particles are being decayed
599 fromBSM |= isBSM(parent);
600 if (!isPhysical(parent)) return false;
601 fromTau |= isTau(parent);
602 if (isHadron(parent)&&!isBeam(parent)) {
603 if (!hadron) hadron = parent; // assumes linear hadron parentage
604 return true;
605 }
606 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
607 }
608 return fromHad;
609 }
610
613
614 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
615 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
616 decltype(thePart->end_vertex()) pVert(nullptr);
617 if (EndVert != nullptr) {
618 do {
619 bool samePart = false;
620 pVert = nullptr;
621 auto outgoing = EndVert->particles_out();
622 auto incoming = EndVert->particles_in();
623 for (const auto& itrDaug: outgoing) {
624 if (!itrDaug) continue;
625 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
626 // brem on generator level for tau
627 (outgoing.size() == 1 && incoming.size() == 1 &&
629 itrDaug->pdg_id() == thePart->pdg_id()) {
630 samePart = true;
631 pVert = itrDaug->end_vertex();
632 }
633 }
634 if (samePart) EndVert = pVert;
635 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
636 }
637 return EndVert;
638 }
639
641
642 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
643 if (!theVert) return {};
644 decltype(theVert->particles_out()) finalStatePart;
645 auto outgoing = theVert->particles_out();
646 for (const auto& thePart: outgoing) {
647 if (!thePart) continue;
648 finalStatePart.push_back(thePart);
649 if (isStable(thePart)) continue;
650 V pVert = findSimulatedEndVertex(thePart);
651 if (pVert == theVert) break; // to prevent Sherpa loop
652 if (pVert != nullptr) {
653 auto vecPart = findFinalStateParticles<V>(pVert);
654 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
655 }
656 }
657 return finalStatePart;
658 }
659
660}
661#endif

◆ isPhoton() [2/2]

template<class T>
bool MC::isPhoton ( const T & p)
inline

Definition at line 377 of file HepMCHelpers.h.

398{
399inline
400auto particles_in (const HepMC::GenVertex* p) {
401 return std::ranges::subrange (p->particles_in_const_begin(),
402 p->particles_in_const_end());
403}
404}
405#endif
406
407namespace MC
408{
409 template <class VTX>
410 auto particles_in (const VTX* p) { return p->particles_in(); }
411 template <class VTX>
412 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
413
414 namespace Pythia8
415 {
417 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
418
419 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
420
421 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
422 }
423
424#include "AtlasPID.h"
425
427 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
428
430 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
431
433 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
434
436 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
437
439 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
440
442 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
443
445 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
446
448 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
449
451 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
452
454 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
455
459 template <class T> inline bool isStableOrSimDecayed(const T& p) {
460 const auto vertex = p->end_vertex();
461 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
462 }
463
465 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
466
468 template <class T> inline bool isSpecialNonInteracting(const T& p) {
469 const int apid = std::abs(p->pdg_id());
470 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
471 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
472 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
473 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
474 return false;
475 }
476
478
479 template <class T> T findMother(T thePart) {
480 auto partOriVert = thePart->production_vertex();
481 if (!partOriVert) return nullptr;
482
483 long partPDG = thePart->pdg_id();
484 long MotherPDG(0);
485
486 auto MothOriVert = partOriVert;
487 MothOriVert = nullptr;
488 T theMoth(nullptr);
489
490 size_t itr = 0;
491 do {
492 if (itr != 0) partOriVert = MothOriVert;
493 for ( const auto& p : particles_in(partOriVert) ) {
494 theMoth = p;
495 if (!theMoth) continue;
496 MotherPDG = theMoth->pdg_id();
497 MothOriVert = theMoth->production_vertex();
498 if (MotherPDG == partPDG) break;
499 }
500 itr++;
501 if (itr > 100) {
502 break;
503 }
504 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
505 MothOriVert != partOriVert);
506 return theMoth;
507 }
508
510
511 template <class C, class T> T findMatching(C TruthContainer, T p) {
512 T ptrPart = nullptr;
513 if (!p) return ptrPart;
514 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
515 for (T truthParticle : *TruthContainer) {
516 if (HepMC::is_sim_descendant(p,truthParticle)) {
517 ptrPart = truthParticle;
518 break;
519 }
520 }
521 }
522 else {
523 for (T truthParticle : TruthContainer) {
524 if (HepMC::is_sim_descendant(p,truthParticle)) {
525 ptrPart = truthParticle;
526 break;
527 }
528 }
529 }
530 return ptrPart;
531 }
533
534 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
535 auto prodVtx = thePart->production_vertex();
536 if (!prodVtx) return;
537 for (const auto& theMother: prodVtx->particles_in()) {
538 if (!theMother) continue;
539 allancestors.insert(theMother);
540 findParticleAncestors(theMother, allancestors);
541 }
542 }
543
545
546 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
547 auto endVtx = thePart->end_vertex();
548 if (!endVtx) return;
549 for (const auto& theDaughter: endVtx->particles_out()) {
550 if (!theDaughter) continue;
551 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
552 allstabledescendants.insert(theDaughter);
553 }
554 findParticleStableDescendants(theDaughter, allstabledescendants);
555 }
556 }
557
561
562 template <class T> bool isHardScatteringVertex(T pVert) {
563 if (pVert == nullptr) return false;
564 T pV = pVert;
565 int numOfPartIn(0);
566 int pdg(0);
567
568 do {
569 pVert = pV;
570 auto incoming = pVert->particles_in();
571 numOfPartIn = incoming.size();
572 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
573 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
574
575 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
576
577 if (numOfPartIn == 2) {
578 auto incoming = pVert->particles_in();
579 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
580 }
581 return false;
582}
583
587
588 template <class T, class U>
589 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
590 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
591 auto vtx = p->production_vertex();
592 if (!vtx) return false;
593 bool fromHad = false;
594 for ( const auto& parent : particles_in(vtx) ) {
595 if (!parent) continue;
596 // should this really go into parton-level territory?
597 // probably depends where BSM particles are being decayed
598 fromBSM |= isBSM(parent);
599 if (!isPhysical(parent)) return false;
600 fromTau |= isTau(parent);
601 if (isHadron(parent)&&!isBeam(parent)) {
602 if (!hadron) hadron = parent; // assumes linear hadron parentage
603 return true;
604 }
605 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
606 }
607 return fromHad;
608 }
609
612
613 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
614 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
615 decltype(thePart->end_vertex()) pVert(nullptr);
616 if (EndVert != nullptr) {
617 do {
618 bool samePart = false;
619 pVert = nullptr;
620 auto outgoing = EndVert->particles_out();
621 auto incoming = EndVert->particles_in();
622 for (const auto& itrDaug: outgoing) {
623 if (!itrDaug) continue;
624 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
625 // brem on generator level for tau
626 (outgoing.size() == 1 && incoming.size() == 1 &&
628 itrDaug->pdg_id() == thePart->pdg_id()) {
629 samePart = true;
630 pVert = itrDaug->end_vertex();
631 }
632 }
633 if (samePart) EndVert = pVert;
634 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
635 }
636 return EndVert;
637 }
638
640
641 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
642 if (!theVert) return {};
643 decltype(theVert->particles_out()) finalStatePart;
644 auto outgoing = theVert->particles_out();
645 for (const auto& thePart: outgoing) {
646 if (!thePart) continue;
647 finalStatePart.push_back(thePart);
648 if (isStable(thePart)) continue;
649 V pVert = findSimulatedEndVertex(thePart);
650 if (pVert == theVert) break; // to prevent Sherpa loop
651 if (pVert != nullptr) {
652 auto vecPart = findFinalStateParticles<V>(pVert);
653 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
654 }
655 }
656 return finalStatePart;
657 }
658
659}
660#endif

◆ isPhysical()

template<class T>
bool MC::isPhysical ( const T & p)
inline

Identify if the particle is physical, i.e. is stable or decayed.

Definition at line 69 of file HepMCHelpers.h.

69{ return isStable<T>(p) || isDecayed<T>(p); }

◆ isPythia8Specific() [1/3]

template<>
bool MC::isPythia8Specific ( const DecodedPID & p)
inline

Definition at line 413 of file HepMCHelpers.h.

434{
435inline
436auto particles_in (const HepMC::GenVertex* p) {
437 return std::ranges::subrange (p->particles_in_const_begin(),
438 p->particles_in_const_end());
439}
440}
441#endif
442
443namespace MC
444{
445 template <class VTX>
446 auto particles_in (const VTX* p) { return p->particles_in(); }
447 template <class VTX>
448 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
449
450 namespace Pythia8
451 {
453 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
454
455 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
456
457 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
458 }
459
460#include "AtlasPID.h"
461
463 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
464
466 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
467
469 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
470
472 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
473
475 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
476
478 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
479
481 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
482
484 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
485
487 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
488
490 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
491
495 template <class T> inline bool isStableOrSimDecayed(const T& p) {
496 const auto vertex = p->end_vertex();
497 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
498 }
499
501 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
502
504 template <class T> inline bool isSpecialNonInteracting(const T& p) {
505 const int apid = std::abs(p->pdg_id());
506 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
507 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
508 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
509 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
510 return false;
511 }
512
514
515 template <class T> T findMother(T thePart) {
516 auto partOriVert = thePart->production_vertex();
517 if (!partOriVert) return nullptr;
518
519 long partPDG = thePart->pdg_id();
520 long MotherPDG(0);
521
522 auto MothOriVert = partOriVert;
523 MothOriVert = nullptr;
524 T theMoth(nullptr);
525
526 size_t itr = 0;
527 do {
528 if (itr != 0) partOriVert = MothOriVert;
529 for ( const auto& p : particles_in(partOriVert) ) {
530 theMoth = p;
531 if (!theMoth) continue;
532 MotherPDG = theMoth->pdg_id();
533 MothOriVert = theMoth->production_vertex();
534 if (MotherPDG == partPDG) break;
535 }
536 itr++;
537 if (itr > 100) {
538 break;
539 }
540 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
541 MothOriVert != partOriVert);
542 return theMoth;
543 }
544
546
547 template <class C, class T> T findMatching(C TruthContainer, T p) {
548 T ptrPart = nullptr;
549 if (!p) return ptrPart;
550 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
551 for (T truthParticle : *TruthContainer) {
552 if (HepMC::is_sim_descendant(p,truthParticle)) {
553 ptrPart = truthParticle;
554 break;
555 }
556 }
557 }
558 else {
559 for (T truthParticle : TruthContainer) {
560 if (HepMC::is_sim_descendant(p,truthParticle)) {
561 ptrPart = truthParticle;
562 break;
563 }
564 }
565 }
566 return ptrPart;
567 }
569
570 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
571 auto prodVtx = thePart->production_vertex();
572 if (!prodVtx) return;
573 for (const auto& theMother: prodVtx->particles_in()) {
574 if (!theMother) continue;
575 allancestors.insert(theMother);
576 findParticleAncestors(theMother, allancestors);
577 }
578 }
579
581
582 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
583 auto endVtx = thePart->end_vertex();
584 if (!endVtx) return;
585 for (const auto& theDaughter: endVtx->particles_out()) {
586 if (!theDaughter) continue;
587 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
588 allstabledescendants.insert(theDaughter);
589 }
590 findParticleStableDescendants(theDaughter, allstabledescendants);
591 }
592 }
593
597
598 template <class T> bool isHardScatteringVertex(T pVert) {
599 if (pVert == nullptr) return false;
600 T pV = pVert;
601 int numOfPartIn(0);
602 int pdg(0);
603
604 do {
605 pVert = pV;
606 auto incoming = pVert->particles_in();
607 numOfPartIn = incoming.size();
608 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
609 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
610
611 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
612
613 if (numOfPartIn == 2) {
614 auto incoming = pVert->particles_in();
615 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
616 }
617 return false;
618}
619
623
624 template <class T, class U>
625 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
626 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
627 auto vtx = p->production_vertex();
628 if (!vtx) return false;
629 bool fromHad = false;
630 for ( const auto& parent : particles_in(vtx) ) {
631 if (!parent) continue;
632 // should this really go into parton-level territory?
633 // probably depends where BSM particles are being decayed
634 fromBSM |= isBSM(parent);
635 if (!isPhysical(parent)) return false;
636 fromTau |= isTau(parent);
637 if (isHadron(parent)&&!isBeam(parent)) {
638 if (!hadron) hadron = parent; // assumes linear hadron parentage
639 return true;
640 }
641 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
642 }
643 return fromHad;
644 }
645
648
649 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
650 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
651 decltype(thePart->end_vertex()) pVert(nullptr);
652 if (EndVert != nullptr) {
653 do {
654 bool samePart = false;
655 pVert = nullptr;
656 auto outgoing = EndVert->particles_out();
657 auto incoming = EndVert->particles_in();
658 for (const auto& itrDaug: outgoing) {
659 if (!itrDaug) continue;
660 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
661 // brem on generator level for tau
662 (outgoing.size() == 1 && incoming.size() == 1 &&
664 itrDaug->pdg_id() == thePart->pdg_id()) {
665 samePart = true;
666 pVert = itrDaug->end_vertex();
667 }
668 }
669 if (samePart) EndVert = pVert;
670 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
671 }
672 return EndVert;
673 }
674
676
677 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
678 if (!theVert) return {};
679 decltype(theVert->particles_out()) finalStatePart;
680 auto outgoing = theVert->particles_out();
681 for (const auto& thePart: outgoing) {
682 if (!thePart) continue;
683 finalStatePart.push_back(thePart);
684 if (isStable(thePart)) continue;
685 V pVert = findSimulatedEndVertex(thePart);
686 if (pVert == theVert) break; // to prevent Sherpa loop
687 if (pVert != nullptr) {
688 auto vecPart = findFinalStateParticles<V>(pVert);
689 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
690 }
691 }
692 return finalStatePart;
693 }
694
695}
696#endif

◆ isPythia8Specific() [2/3]

template<>
bool MC::isPythia8Specific ( const int & p)
inline

Definition at line 414 of file HepMCHelpers.h.

435{
436inline
437auto particles_in (const HepMC::GenVertex* p) {
438 return std::ranges::subrange (p->particles_in_const_begin(),
439 p->particles_in_const_end());
440}
441}
442#endif
443
444namespace MC
445{
446 template <class VTX>
447 auto particles_in (const VTX* p) { return p->particles_in(); }
448 template <class VTX>
449 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
450
451 namespace Pythia8
452 {
454 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
455
456 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
457
458 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
459 }
460
461#include "AtlasPID.h"
462
464 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
465
467 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
468
470 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
471
473 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
474
476 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
477
479 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
480
482 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
483
485 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
486
488 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
489
491 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
492
496 template <class T> inline bool isStableOrSimDecayed(const T& p) {
497 const auto vertex = p->end_vertex();
498 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
499 }
500
502 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
503
505 template <class T> inline bool isSpecialNonInteracting(const T& p) {
506 const int apid = std::abs(p->pdg_id());
507 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
508 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
509 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
510 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
511 return false;
512 }
513
515
516 template <class T> T findMother(T thePart) {
517 auto partOriVert = thePart->production_vertex();
518 if (!partOriVert) return nullptr;
519
520 long partPDG = thePart->pdg_id();
521 long MotherPDG(0);
522
523 auto MothOriVert = partOriVert;
524 MothOriVert = nullptr;
525 T theMoth(nullptr);
526
527 size_t itr = 0;
528 do {
529 if (itr != 0) partOriVert = MothOriVert;
530 for ( const auto& p : particles_in(partOriVert) ) {
531 theMoth = p;
532 if (!theMoth) continue;
533 MotherPDG = theMoth->pdg_id();
534 MothOriVert = theMoth->production_vertex();
535 if (MotherPDG == partPDG) break;
536 }
537 itr++;
538 if (itr > 100) {
539 break;
540 }
541 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
542 MothOriVert != partOriVert);
543 return theMoth;
544 }
545
547
548 template <class C, class T> T findMatching(C TruthContainer, T p) {
549 T ptrPart = nullptr;
550 if (!p) return ptrPart;
551 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
552 for (T truthParticle : *TruthContainer) {
553 if (HepMC::is_sim_descendant(p,truthParticle)) {
554 ptrPart = truthParticle;
555 break;
556 }
557 }
558 }
559 else {
560 for (T truthParticle : TruthContainer) {
561 if (HepMC::is_sim_descendant(p,truthParticle)) {
562 ptrPart = truthParticle;
563 break;
564 }
565 }
566 }
567 return ptrPart;
568 }
570
571 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
572 auto prodVtx = thePart->production_vertex();
573 if (!prodVtx) return;
574 for (const auto& theMother: prodVtx->particles_in()) {
575 if (!theMother) continue;
576 allancestors.insert(theMother);
577 findParticleAncestors(theMother, allancestors);
578 }
579 }
580
582
583 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
584 auto endVtx = thePart->end_vertex();
585 if (!endVtx) return;
586 for (const auto& theDaughter: endVtx->particles_out()) {
587 if (!theDaughter) continue;
588 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
589 allstabledescendants.insert(theDaughter);
590 }
591 findParticleStableDescendants(theDaughter, allstabledescendants);
592 }
593 }
594
598
599 template <class T> bool isHardScatteringVertex(T pVert) {
600 if (pVert == nullptr) return false;
601 T pV = pVert;
602 int numOfPartIn(0);
603 int pdg(0);
604
605 do {
606 pVert = pV;
607 auto incoming = pVert->particles_in();
608 numOfPartIn = incoming.size();
609 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
610 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
611
612 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
613
614 if (numOfPartIn == 2) {
615 auto incoming = pVert->particles_in();
616 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
617 }
618 return false;
619}
620
624
625 template <class T, class U>
626 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
627 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
628 auto vtx = p->production_vertex();
629 if (!vtx) return false;
630 bool fromHad = false;
631 for ( const auto& parent : particles_in(vtx) ) {
632 if (!parent) continue;
633 // should this really go into parton-level territory?
634 // probably depends where BSM particles are being decayed
635 fromBSM |= isBSM(parent);
636 if (!isPhysical(parent)) return false;
637 fromTau |= isTau(parent);
638 if (isHadron(parent)&&!isBeam(parent)) {
639 if (!hadron) hadron = parent; // assumes linear hadron parentage
640 return true;
641 }
642 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
643 }
644 return fromHad;
645 }
646
649
650 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
651 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
652 decltype(thePart->end_vertex()) pVert(nullptr);
653 if (EndVert != nullptr) {
654 do {
655 bool samePart = false;
656 pVert = nullptr;
657 auto outgoing = EndVert->particles_out();
658 auto incoming = EndVert->particles_in();
659 for (const auto& itrDaug: outgoing) {
660 if (!itrDaug) continue;
661 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
662 // brem on generator level for tau
663 (outgoing.size() == 1 && incoming.size() == 1 &&
665 itrDaug->pdg_id() == thePart->pdg_id()) {
666 samePart = true;
667 pVert = itrDaug->end_vertex();
668 }
669 }
670 if (samePart) EndVert = pVert;
671 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
672 }
673 return EndVert;
674 }
675
677
678 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
679 if (!theVert) return {};
680 decltype(theVert->particles_out()) finalStatePart;
681 auto outgoing = theVert->particles_out();
682 for (const auto& thePart: outgoing) {
683 if (!thePart) continue;
684 finalStatePart.push_back(thePart);
685 if (isStable(thePart)) continue;
686 V pVert = findSimulatedEndVertex(thePart);
687 if (pVert == theVert) break; // to prevent Sherpa loop
688 if (pVert != nullptr) {
689 auto vecPart = findFinalStateParticles<V>(pVert);
690 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
691 }
692 }
693 return finalStatePart;
694 }
695
696}
697#endif

◆ isPythia8Specific() [3/3]

template<class T>
bool MC::isPythia8Specific ( const T & p)
inline

Definition at line 412 of file HepMCHelpers.h.

433{
434inline
435auto particles_in (const HepMC::GenVertex* p) {
436 return std::ranges::subrange (p->particles_in_const_begin(),
437 p->particles_in_const_end());
438}
439}
440#endif
441
442namespace MC
443{
444 template <class VTX>
445 auto particles_in (const VTX* p) { return p->particles_in(); }
446 template <class VTX>
447 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
448
449 namespace Pythia8
450 {
452 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
453
454 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
455
456 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
457 }
458
459#include "AtlasPID.h"
460
462 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
463
465 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
466
468 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
469
471 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
472
474 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
475
477 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
478
480 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
481
483 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
484
486 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
487
489 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
490
494 template <class T> inline bool isStableOrSimDecayed(const T& p) {
495 const auto vertex = p->end_vertex();
496 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
497 }
498
500 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
501
503 template <class T> inline bool isSpecialNonInteracting(const T& p) {
504 const int apid = std::abs(p->pdg_id());
505 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
506 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
507 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
508 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
509 return false;
510 }
511
513
514 template <class T> T findMother(T thePart) {
515 auto partOriVert = thePart->production_vertex();
516 if (!partOriVert) return nullptr;
517
518 long partPDG = thePart->pdg_id();
519 long MotherPDG(0);
520
521 auto MothOriVert = partOriVert;
522 MothOriVert = nullptr;
523 T theMoth(nullptr);
524
525 size_t itr = 0;
526 do {
527 if (itr != 0) partOriVert = MothOriVert;
528 for ( const auto& p : particles_in(partOriVert) ) {
529 theMoth = p;
530 if (!theMoth) continue;
531 MotherPDG = theMoth->pdg_id();
532 MothOriVert = theMoth->production_vertex();
533 if (MotherPDG == partPDG) break;
534 }
535 itr++;
536 if (itr > 100) {
537 break;
538 }
539 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
540 MothOriVert != partOriVert);
541 return theMoth;
542 }
543
545
546 template <class C, class T> T findMatching(C TruthContainer, T p) {
547 T ptrPart = nullptr;
548 if (!p) return ptrPart;
549 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
550 for (T truthParticle : *TruthContainer) {
551 if (HepMC::is_sim_descendant(p,truthParticle)) {
552 ptrPart = truthParticle;
553 break;
554 }
555 }
556 }
557 else {
558 for (T truthParticle : TruthContainer) {
559 if (HepMC::is_sim_descendant(p,truthParticle)) {
560 ptrPart = truthParticle;
561 break;
562 }
563 }
564 }
565 return ptrPart;
566 }
568
569 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
570 auto prodVtx = thePart->production_vertex();
571 if (!prodVtx) return;
572 for (const auto& theMother: prodVtx->particles_in()) {
573 if (!theMother) continue;
574 allancestors.insert(theMother);
575 findParticleAncestors(theMother, allancestors);
576 }
577 }
578
580
581 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
582 auto endVtx = thePart->end_vertex();
583 if (!endVtx) return;
584 for (const auto& theDaughter: endVtx->particles_out()) {
585 if (!theDaughter) continue;
586 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
587 allstabledescendants.insert(theDaughter);
588 }
589 findParticleStableDescendants(theDaughter, allstabledescendants);
590 }
591 }
592
596
597 template <class T> bool isHardScatteringVertex(T pVert) {
598 if (pVert == nullptr) return false;
599 T pV = pVert;
600 int numOfPartIn(0);
601 int pdg(0);
602
603 do {
604 pVert = pV;
605 auto incoming = pVert->particles_in();
606 numOfPartIn = incoming.size();
607 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
608 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
609
610 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
611
612 if (numOfPartIn == 2) {
613 auto incoming = pVert->particles_in();
614 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
615 }
616 return false;
617}
618
622
623 template <class T, class U>
624 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
625 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
626 auto vtx = p->production_vertex();
627 if (!vtx) return false;
628 bool fromHad = false;
629 for ( const auto& parent : particles_in(vtx) ) {
630 if (!parent) continue;
631 // should this really go into parton-level territory?
632 // probably depends where BSM particles are being decayed
633 fromBSM |= isBSM(parent);
634 if (!isPhysical(parent)) return false;
635 fromTau |= isTau(parent);
636 if (isHadron(parent)&&!isBeam(parent)) {
637 if (!hadron) hadron = parent; // assumes linear hadron parentage
638 return true;
639 }
640 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
641 }
642 return fromHad;
643 }
644
647
648 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
649 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
650 decltype(thePart->end_vertex()) pVert(nullptr);
651 if (EndVert != nullptr) {
652 do {
653 bool samePart = false;
654 pVert = nullptr;
655 auto outgoing = EndVert->particles_out();
656 auto incoming = EndVert->particles_in();
657 for (const auto& itrDaug: outgoing) {
658 if (!itrDaug) continue;
659 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
660 // brem on generator level for tau
661 (outgoing.size() == 1 && incoming.size() == 1 &&
663 itrDaug->pdg_id() == thePart->pdg_id()) {
664 samePart = true;
665 pVert = itrDaug->end_vertex();
666 }
667 }
668 if (samePart) EndVert = pVert;
669 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
670 }
671 return EndVert;
672 }
673
675
676 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
677 if (!theVert) return {};
678 decltype(theVert->particles_out()) finalStatePart;
679 auto outgoing = theVert->particles_out();
680 for (const auto& thePart: outgoing) {
681 if (!thePart) continue;
682 finalStatePart.push_back(thePart);
683 if (isStable(thePart)) continue;
684 V pVert = findSimulatedEndVertex(thePart);
685 if (pVert == theVert) break; // to prevent Sherpa loop
686 if (pVert != nullptr) {
687 auto vecPart = findFinalStateParticles<V>(pVert);
688 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
689 }
690 }
691 return finalStatePart;
692 }
693
694}
695#endif

◆ isQuark() [1/3]

template<>
bool MC::isQuark ( const DecodedPID & p)
inline

Definition at line 170 of file HepMCHelpers.h.

170{

◆ isQuark() [2/3]

template<>
bool MC::isQuark ( const int & p)
inline

Definition at line 169 of file HepMCHelpers.h.

◆ isQuark() [3/3]

template<class T>
bool MC::isQuark ( const T & p)
inline

PDG rule 2: Quarks and leptons are numbered consecutively starting from 1 and 11 respectively; to do this they are first ordered by family and within families by weak isospin.

APID: the fourth generation quarks are quarks.

Definition at line 168 of file HepMCHelpers.h.

◆ isQuarkonium() [1/3]

template<>
bool MC::isQuarkonium ( const DecodedPID & p)
inline

Definition at line 275 of file HepMCHelpers.h.

275 {
276 auto vecPart = findFinalStateParticles<V>(pVert);
277 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
278 }

◆ isQuarkonium() [2/3]

template<>
bool MC::isQuarkonium ( const int & p)
inline

Definition at line 279 of file HepMCHelpers.h.

◆ isQuarkonium() [3/3]

template<class T>
bool MC::isQuarkonium ( const T & p)
inline

Is this a heavy-flavour quarkonium meson?

Note
Original by LHCb in Rivet analysis LHCB_2016_I1504058
phi = s,sbar is not considered quarkonium

Definition at line 274 of file HepMCHelpers.h.

◆ isRBaryon() [1/3]

template<>
bool MC::isRBaryon ( const DecodedPID & p)
inline

Definition at line 591 of file HepMCHelpers.h.

612 {
613inline
614auto particles_in (const HepMC::GenVertex* p) {
615 return std::ranges::subrange (p->particles_in_const_begin(),
616 p->particles_in_const_end());
617}
618}
619#endif
620
621namespace MC
622{
623 template <class VTX>
624 auto particles_in (const VTX* p) { return p->particles_in(); }
625 template <class VTX>
626 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
627
628 namespace Pythia8
629 {
631 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
632
633 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
634
635 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
636 }
637
638#include "AtlasPID.h"
639
641 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
642
644 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
645
647 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
648
650 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
651
653 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
654
656 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
657
659 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
660
662 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
663
665 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
666
668 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
669
673 template <class T> inline bool isStableOrSimDecayed(const T& p) {
674 const auto vertex = p->end_vertex();
675 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
676 }
677
679 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
680
682 template <class T> inline bool isSpecialNonInteracting(const T& p) {
683 const int apid = std::abs(p->pdg_id());
684 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
685 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
686 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
687 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
688 return false;
689 }
690
692
693 template <class T> T findMother(T thePart) {
694 auto partOriVert = thePart->production_vertex();
695 if (!partOriVert) return nullptr;
696
697 long partPDG = thePart->pdg_id();
698 long MotherPDG(0);
699
700 auto MothOriVert = partOriVert;
701 MothOriVert = nullptr;
702 T theMoth(nullptr);
703
704 size_t itr = 0;
705 do {
706 if (itr != 0) partOriVert = MothOriVert;
707 for ( const auto& p : particles_in(partOriVert) ) {
708 theMoth = p;
709 if (!theMoth) continue;
710 MotherPDG = theMoth->pdg_id();
711 MothOriVert = theMoth->production_vertex();
712 if (MotherPDG == partPDG) break;
713 }
714 itr++;
715 if (itr > 100) {
716 break;
717 }
718 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
719 MothOriVert != partOriVert);
720 return theMoth;
721 }
722
724
725 template <class C, class T> T findMatching(C TruthContainer, T p) {
726 T ptrPart = nullptr;
727 if (!p) return ptrPart;
728 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
729 for (T truthParticle : *TruthContainer) {
730 if (HepMC::is_sim_descendant(p,truthParticle)) {
731 ptrPart = truthParticle;
732 break;
733 }
734 }
735 }
736 else {
737 for (T truthParticle : TruthContainer) {
738 if (HepMC::is_sim_descendant(p,truthParticle)) {
739 ptrPart = truthParticle;
740 break;
741 }
742 }
743 }
744 return ptrPart;
745 }
747
748 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
749 auto prodVtx = thePart->production_vertex();
750 if (!prodVtx) return;
751 for (const auto& theMother: prodVtx->particles_in()) {
752 if (!theMother) continue;
753 allancestors.insert(theMother);
754 findParticleAncestors(theMother, allancestors);
755 }
756 }
757
759
760 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
761 auto endVtx = thePart->end_vertex();
762 if (!endVtx) return;
763 for (const auto& theDaughter: endVtx->particles_out()) {
764 if (!theDaughter) continue;
765 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
766 allstabledescendants.insert(theDaughter);
767 }
768 findParticleStableDescendants(theDaughter, allstabledescendants);
769 }
770 }
771
775
776 template <class T> bool isHardScatteringVertex(T pVert) {
777 if (pVert == nullptr) return false;
778 T pV = pVert;
779 int numOfPartIn(0);
780 int pdg(0);
781
782 do {
783 pVert = pV;
784 auto incoming = pVert->particles_in();
785 numOfPartIn = incoming.size();
786 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
787 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
788
789 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
790
791 if (numOfPartIn == 2) {
792 auto incoming = pVert->particles_in();
793 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
794 }
795 return false;
796}
797
801
802 template <class T, class U>
803 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
804 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
805 auto vtx = p->production_vertex();
806 if (!vtx) return false;
807 bool fromHad = false;
808 for ( const auto& parent : particles_in(vtx) ) {
809 if (!parent) continue;
810 // should this really go into parton-level territory?
811 // probably depends where BSM particles are being decayed
812 fromBSM |= isBSM(parent);
813 if (!isPhysical(parent)) return false;
814 fromTau |= isTau(parent);
815 if (isHadron(parent)&&!isBeam(parent)) {
816 if (!hadron) hadron = parent; // assumes linear hadron parentage
817 return true;
818 }
819 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
820 }
821 return fromHad;
822 }
823
826
827 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
828 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
829 decltype(thePart->end_vertex()) pVert(nullptr);
830 if (EndVert != nullptr) {
831 do {
832 bool samePart = false;
833 pVert = nullptr;
834 auto outgoing = EndVert->particles_out();
835 auto incoming = EndVert->particles_in();
836 for (const auto& itrDaug: outgoing) {
837 if (!itrDaug) continue;
838 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
839 // brem on generator level for tau
840 (outgoing.size() == 1 && incoming.size() == 1 &&
842 itrDaug->pdg_id() == thePart->pdg_id()) {
843 samePart = true;
844 pVert = itrDaug->end_vertex();
845 }
846 }
847 if (samePart) EndVert = pVert;
848 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
849 }
850 return EndVert;
851 }
852
854
855 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
856 if (!theVert) return {};
857 decltype(theVert->particles_out()) finalStatePart;
858 auto outgoing = theVert->particles_out();
859 for (const auto& thePart: outgoing) {
860 if (!thePart) continue;
861 finalStatePart.push_back(thePart);
862 if (isStable(thePart)) continue;
863 V pVert = findSimulatedEndVertex(thePart);
864 if (pVert == theVert) break; // to prevent Sherpa loop
865 if (pVert != nullptr) {
866 auto vecPart = findFinalStateParticles<V>(pVert);
867 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
868 }
869 }
870 return finalStatePart;
871 }
872
873}
874#endif

◆ isRBaryon() [2/3]

template<>
bool MC::isRBaryon ( const int & p)
inline

Definition at line 601 of file HepMCHelpers.h.

622{
623inline
624auto particles_in (const HepMC::GenVertex* p) {
625 return std::ranges::subrange (p->particles_in_const_begin(),
626 p->particles_in_const_end());
627}
628}
629#endif
630
631namespace MC
632{
633 template <class VTX>
634 auto particles_in (const VTX* p) { return p->particles_in(); }
635 template <class VTX>
636 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
637
638 namespace Pythia8
639 {
641 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
642
643 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
644
645 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
646 }
647
648#include "AtlasPID.h"
649
651 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
652
654 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
655
657 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
658
660 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
661
663 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
664
666 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
667
669 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
670
672 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
673
675 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
676
678 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
679
683 template <class T> inline bool isStableOrSimDecayed(const T& p) {
684 const auto vertex = p->end_vertex();
685 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
686 }
687
689 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
690
692 template <class T> inline bool isSpecialNonInteracting(const T& p) {
693 const int apid = std::abs(p->pdg_id());
694 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
695 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
696 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
697 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
698 return false;
699 }
700
702
703 template <class T> T findMother(T thePart) {
704 auto partOriVert = thePart->production_vertex();
705 if (!partOriVert) return nullptr;
706
707 long partPDG = thePart->pdg_id();
708 long MotherPDG(0);
709
710 auto MothOriVert = partOriVert;
711 MothOriVert = nullptr;
712 T theMoth(nullptr);
713
714 size_t itr = 0;
715 do {
716 if (itr != 0) partOriVert = MothOriVert;
717 for ( const auto& p : particles_in(partOriVert) ) {
718 theMoth = p;
719 if (!theMoth) continue;
720 MotherPDG = theMoth->pdg_id();
721 MothOriVert = theMoth->production_vertex();
722 if (MotherPDG == partPDG) break;
723 }
724 itr++;
725 if (itr > 100) {
726 break;
727 }
728 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
729 MothOriVert != partOriVert);
730 return theMoth;
731 }
732
734
735 template <class C, class T> T findMatching(C TruthContainer, T p) {
736 T ptrPart = nullptr;
737 if (!p) return ptrPart;
738 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
739 for (T truthParticle : *TruthContainer) {
740 if (HepMC::is_sim_descendant(p,truthParticle)) {
741 ptrPart = truthParticle;
742 break;
743 }
744 }
745 }
746 else {
747 for (T truthParticle : TruthContainer) {
748 if (HepMC::is_sim_descendant(p,truthParticle)) {
749 ptrPart = truthParticle;
750 break;
751 }
752 }
753 }
754 return ptrPart;
755 }
757
758 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
759 auto prodVtx = thePart->production_vertex();
760 if (!prodVtx) return;
761 for (const auto& theMother: prodVtx->particles_in()) {
762 if (!theMother) continue;
763 allancestors.insert(theMother);
764 findParticleAncestors(theMother, allancestors);
765 }
766 }
767
769
770 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
771 auto endVtx = thePart->end_vertex();
772 if (!endVtx) return;
773 for (const auto& theDaughter: endVtx->particles_out()) {
774 if (!theDaughter) continue;
775 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
776 allstabledescendants.insert(theDaughter);
777 }
778 findParticleStableDescendants(theDaughter, allstabledescendants);
779 }
780 }
781
785
786 template <class T> bool isHardScatteringVertex(T pVert) {
787 if (pVert == nullptr) return false;
788 T pV = pVert;
789 int numOfPartIn(0);
790 int pdg(0);
791
792 do {
793 pVert = pV;
794 auto incoming = pVert->particles_in();
795 numOfPartIn = incoming.size();
796 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
797 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
798
799 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
800
801 if (numOfPartIn == 2) {
802 auto incoming = pVert->particles_in();
803 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
804 }
805 return false;
806}
807
811
812 template <class T, class U>
813 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
814 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
815 auto vtx = p->production_vertex();
816 if (!vtx) return false;
817 bool fromHad = false;
818 for ( const auto& parent : particles_in(vtx) ) {
819 if (!parent) continue;
820 // should this really go into parton-level territory?
821 // probably depends where BSM particles are being decayed
822 fromBSM |= isBSM(parent);
823 if (!isPhysical(parent)) return false;
824 fromTau |= isTau(parent);
825 if (isHadron(parent)&&!isBeam(parent)) {
826 if (!hadron) hadron = parent; // assumes linear hadron parentage
827 return true;
828 }
829 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
830 }
831 return fromHad;
832 }
833
836
837 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
838 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
839 decltype(thePart->end_vertex()) pVert(nullptr);
840 if (EndVert != nullptr) {
841 do {
842 bool samePart = false;
843 pVert = nullptr;
844 auto outgoing = EndVert->particles_out();
845 auto incoming = EndVert->particles_in();
846 for (const auto& itrDaug: outgoing) {
847 if (!itrDaug) continue;
848 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
849 // brem on generator level for tau
850 (outgoing.size() == 1 && incoming.size() == 1 &&
852 itrDaug->pdg_id() == thePart->pdg_id()) {
853 samePart = true;
854 pVert = itrDaug->end_vertex();
855 }
856 }
857 if (samePart) EndVert = pVert;
858 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
859 }
860 return EndVert;
861 }
862
864
865 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
866 if (!theVert) return {};
867 decltype(theVert->particles_out()) finalStatePart;
868 auto outgoing = theVert->particles_out();
869 for (const auto& thePart: outgoing) {
870 if (!thePart) continue;
871 finalStatePart.push_back(thePart);
872 if (isStable(thePart)) continue;
873 V pVert = findSimulatedEndVertex(thePart);
874 if (pVert == theVert) break; // to prevent Sherpa loop
875 if (pVert != nullptr) {
876 auto vecPart = findFinalStateParticles<V>(pVert);
877 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
878 }
879 }
880 return finalStatePart;
881 }
882
883}
884#endif

◆ isRBaryon() [3/3]

template<class T>
bool MC::isRBaryon ( const T & p)
inline

Definition at line 590 of file HepMCHelpers.h.

611{
612inline
613auto particles_in (const HepMC::GenVertex* p) {
614 return std::ranges::subrange (p->particles_in_const_begin(),
615 p->particles_in_const_end());
616}
617}
618#endif
619
620namespace MC
621{
622 template <class VTX>
623 auto particles_in (const VTX* p) { return p->particles_in(); }
624 template <class VTX>
625 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
626
627 namespace Pythia8
628 {
630 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
631
632 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
633
634 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
635 }
636
637#include "AtlasPID.h"
638
640 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
641
643 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
644
646 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
647
649 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
650
652 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
653
655 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
656
658 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
659
661 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
662
664 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
665
667 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
668
672 template <class T> inline bool isStableOrSimDecayed(const T& p) {
673 const auto vertex = p->end_vertex();
674 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
675 }
676
678 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
679
681 template <class T> inline bool isSpecialNonInteracting(const T& p) {
682 const int apid = std::abs(p->pdg_id());
683 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
684 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
685 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
686 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
687 return false;
688 }
689
691
692 template <class T> T findMother(T thePart) {
693 auto partOriVert = thePart->production_vertex();
694 if (!partOriVert) return nullptr;
695
696 long partPDG = thePart->pdg_id();
697 long MotherPDG(0);
698
699 auto MothOriVert = partOriVert;
700 MothOriVert = nullptr;
701 T theMoth(nullptr);
702
703 size_t itr = 0;
704 do {
705 if (itr != 0) partOriVert = MothOriVert;
706 for ( const auto& p : particles_in(partOriVert) ) {
707 theMoth = p;
708 if (!theMoth) continue;
709 MotherPDG = theMoth->pdg_id();
710 MothOriVert = theMoth->production_vertex();
711 if (MotherPDG == partPDG) break;
712 }
713 itr++;
714 if (itr > 100) {
715 break;
716 }
717 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
718 MothOriVert != partOriVert);
719 return theMoth;
720 }
721
723
724 template <class C, class T> T findMatching(C TruthContainer, T p) {
725 T ptrPart = nullptr;
726 if (!p) return ptrPart;
727 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
728 for (T truthParticle : *TruthContainer) {
729 if (HepMC::is_sim_descendant(p,truthParticle)) {
730 ptrPart = truthParticle;
731 break;
732 }
733 }
734 }
735 else {
736 for (T truthParticle : TruthContainer) {
737 if (HepMC::is_sim_descendant(p,truthParticle)) {
738 ptrPart = truthParticle;
739 break;
740 }
741 }
742 }
743 return ptrPart;
744 }
746
747 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
748 auto prodVtx = thePart->production_vertex();
749 if (!prodVtx) return;
750 for (const auto& theMother: prodVtx->particles_in()) {
751 if (!theMother) continue;
752 allancestors.insert(theMother);
753 findParticleAncestors(theMother, allancestors);
754 }
755 }
756
758
759 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
760 auto endVtx = thePart->end_vertex();
761 if (!endVtx) return;
762 for (const auto& theDaughter: endVtx->particles_out()) {
763 if (!theDaughter) continue;
764 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
765 allstabledescendants.insert(theDaughter);
766 }
767 findParticleStableDescendants(theDaughter, allstabledescendants);
768 }
769 }
770
774
775 template <class T> bool isHardScatteringVertex(T pVert) {
776 if (pVert == nullptr) return false;
777 T pV = pVert;
778 int numOfPartIn(0);
779 int pdg(0);
780
781 do {
782 pVert = pV;
783 auto incoming = pVert->particles_in();
784 numOfPartIn = incoming.size();
785 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
786 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
787
788 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
789
790 if (numOfPartIn == 2) {
791 auto incoming = pVert->particles_in();
792 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
793 }
794 return false;
795}
796
800
801 template <class T, class U>
802 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
803 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
804 auto vtx = p->production_vertex();
805 if (!vtx) return false;
806 bool fromHad = false;
807 for ( const auto& parent : particles_in(vtx) ) {
808 if (!parent) continue;
809 // should this really go into parton-level territory?
810 // probably depends where BSM particles are being decayed
811 fromBSM |= isBSM(parent);
812 if (!isPhysical(parent)) return false;
813 fromTau |= isTau(parent);
814 if (isHadron(parent)&&!isBeam(parent)) {
815 if (!hadron) hadron = parent; // assumes linear hadron parentage
816 return true;
817 }
818 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
819 }
820 return fromHad;
821 }
822
825
826 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
827 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
828 decltype(thePart->end_vertex()) pVert(nullptr);
829 if (EndVert != nullptr) {
830 do {
831 bool samePart = false;
832 pVert = nullptr;
833 auto outgoing = EndVert->particles_out();
834 auto incoming = EndVert->particles_in();
835 for (const auto& itrDaug: outgoing) {
836 if (!itrDaug) continue;
837 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
838 // brem on generator level for tau
839 (outgoing.size() == 1 && incoming.size() == 1 &&
841 itrDaug->pdg_id() == thePart->pdg_id()) {
842 samePart = true;
843 pVert = itrDaug->end_vertex();
844 }
845 }
846 if (samePart) EndVert = pVert;
847 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
848 }
849 return EndVert;
850 }
851
853
854 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
855 if (!theVert) return {};
856 decltype(theVert->particles_out()) finalStatePart;
857 auto outgoing = theVert->particles_out();
858 for (const auto& thePart: outgoing) {
859 if (!thePart) continue;
860 finalStatePart.push_back(thePart);
861 if (isStable(thePart)) continue;
862 V pVert = findSimulatedEndVertex(thePart);
863 if (pVert == theVert) break; // to prevent Sherpa loop
864 if (pVert != nullptr) {
865 auto vecPart = findFinalStateParticles<V>(pVert);
866 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
867 }
868 }
869 return finalStatePart;
870 }
871
872}
873#endif

◆ isResonance()

template<class T>
bool MC::isResonance ( const T & p)
inline

Definition at line 401 of file HepMCHelpers.h.

422{
423inline
424auto particles_in (const HepMC::GenVertex* p) {
425 return std::ranges::subrange (p->particles_in_const_begin(),
426 p->particles_in_const_end());
427}
428}
429#endif
430
431namespace MC
432{
433 template <class VTX>
434 auto particles_in (const VTX* p) { return p->particles_in(); }
435 template <class VTX>
436 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
437
438 namespace Pythia8
439 {
441 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
442
443 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
444
445 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
446 }
447
448#include "AtlasPID.h"
449
451 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
452
454 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
455
457 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
458
460 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
461
463 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
464
466 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
467
469 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
470
472 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
473
475 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
476
478 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
479
483 template <class T> inline bool isStableOrSimDecayed(const T& p) {
484 const auto vertex = p->end_vertex();
485 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
486 }
487
489 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
490
492 template <class T> inline bool isSpecialNonInteracting(const T& p) {
493 const int apid = std::abs(p->pdg_id());
494 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
495 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
496 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
497 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
498 return false;
499 }
500
502
503 template <class T> T findMother(T thePart) {
504 auto partOriVert = thePart->production_vertex();
505 if (!partOriVert) return nullptr;
506
507 long partPDG = thePart->pdg_id();
508 long MotherPDG(0);
509
510 auto MothOriVert = partOriVert;
511 MothOriVert = nullptr;
512 T theMoth(nullptr);
513
514 size_t itr = 0;
515 do {
516 if (itr != 0) partOriVert = MothOriVert;
517 for ( const auto& p : particles_in(partOriVert) ) {
518 theMoth = p;
519 if (!theMoth) continue;
520 MotherPDG = theMoth->pdg_id();
521 MothOriVert = theMoth->production_vertex();
522 if (MotherPDG == partPDG) break;
523 }
524 itr++;
525 if (itr > 100) {
526 break;
527 }
528 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
529 MothOriVert != partOriVert);
530 return theMoth;
531 }
532
534
535 template <class C, class T> T findMatching(C TruthContainer, T p) {
536 T ptrPart = nullptr;
537 if (!p) return ptrPart;
538 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
539 for (T truthParticle : *TruthContainer) {
540 if (HepMC::is_sim_descendant(p,truthParticle)) {
541 ptrPart = truthParticle;
542 break;
543 }
544 }
545 }
546 else {
547 for (T truthParticle : TruthContainer) {
548 if (HepMC::is_sim_descendant(p,truthParticle)) {
549 ptrPart = truthParticle;
550 break;
551 }
552 }
553 }
554 return ptrPart;
555 }
557
558 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
559 auto prodVtx = thePart->production_vertex();
560 if (!prodVtx) return;
561 for (const auto& theMother: prodVtx->particles_in()) {
562 if (!theMother) continue;
563 allancestors.insert(theMother);
564 findParticleAncestors(theMother, allancestors);
565 }
566 }
567
569
570 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
571 auto endVtx = thePart->end_vertex();
572 if (!endVtx) return;
573 for (const auto& theDaughter: endVtx->particles_out()) {
574 if (!theDaughter) continue;
575 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
576 allstabledescendants.insert(theDaughter);
577 }
578 findParticleStableDescendants(theDaughter, allstabledescendants);
579 }
580 }
581
585
586 template <class T> bool isHardScatteringVertex(T pVert) {
587 if (pVert == nullptr) return false;
588 T pV = pVert;
589 int numOfPartIn(0);
590 int pdg(0);
591
592 do {
593 pVert = pV;
594 auto incoming = pVert->particles_in();
595 numOfPartIn = incoming.size();
596 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
597 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
598
599 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
600
601 if (numOfPartIn == 2) {
602 auto incoming = pVert->particles_in();
603 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
604 }
605 return false;
606}
607
611
612 template <class T, class U>
613 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
614 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
615 auto vtx = p->production_vertex();
616 if (!vtx) return false;
617 bool fromHad = false;
618 for ( const auto& parent : particles_in(vtx) ) {
619 if (!parent) continue;
620 // should this really go into parton-level territory?
621 // probably depends where BSM particles are being decayed
622 fromBSM |= isBSM(parent);
623 if (!isPhysical(parent)) return false;
624 fromTau |= isTau(parent);
625 if (isHadron(parent)&&!isBeam(parent)) {
626 if (!hadron) hadron = parent; // assumes linear hadron parentage
627 return true;
628 }
629 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
630 }
631 return fromHad;
632 }
633
636
637 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
638 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
639 decltype(thePart->end_vertex()) pVert(nullptr);
640 if (EndVert != nullptr) {
641 do {
642 bool samePart = false;
643 pVert = nullptr;
644 auto outgoing = EndVert->particles_out();
645 auto incoming = EndVert->particles_in();
646 for (const auto& itrDaug: outgoing) {
647 if (!itrDaug) continue;
648 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
649 // brem on generator level for tau
650 (outgoing.size() == 1 && incoming.size() == 1 &&
652 itrDaug->pdg_id() == thePart->pdg_id()) {
653 samePart = true;
654 pVert = itrDaug->end_vertex();
655 }
656 }
657 if (samePart) EndVert = pVert;
658 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
659 }
660 return EndVert;
661 }
662
664
665 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
666 if (!theVert) return {};
667 decltype(theVert->particles_out()) finalStatePart;
668 auto outgoing = theVert->particles_out();
669 for (const auto& thePart: outgoing) {
670 if (!thePart) continue;
671 finalStatePart.push_back(thePart);
672 if (isStable(thePart)) continue;
673 V pVert = findSimulatedEndVertex(thePart);
674 if (pVert == theVert) break; // to prevent Sherpa loop
675 if (pVert != nullptr) {
676 auto vecPart = findFinalStateParticles<V>(pVert);
677 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
678 }
679 }
680 return finalStatePart;
681 }
682
683}
684#endif

◆ isRGlueball() [1/3]

template<>
bool MC::isRGlueball ( const DecodedPID & p)
inline

Definition at line 564 of file HepMCHelpers.h.

585 {
586inline
587auto particles_in (const HepMC::GenVertex* p) {
588 return std::ranges::subrange (p->particles_in_const_begin(),
589 p->particles_in_const_end());
590}
591}
592#endif
593
594namespace MC
595{
596 template <class VTX>
597 auto particles_in (const VTX* p) { return p->particles_in(); }
598 template <class VTX>
599 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
600
601 namespace Pythia8
602 {
604 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
605
606 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
607
608 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
609 }
610
611#include "AtlasPID.h"
612
614 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
615
617 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
618
620 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
621
623 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
624
626 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
627
629 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
630
632 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
633
635 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
636
638 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
639
641 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
642
646 template <class T> inline bool isStableOrSimDecayed(const T& p) {
647 const auto vertex = p->end_vertex();
648 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
649 }
650
652 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
653
655 template <class T> inline bool isSpecialNonInteracting(const T& p) {
656 const int apid = std::abs(p->pdg_id());
657 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
658 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
659 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
660 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
661 return false;
662 }
663
665
666 template <class T> T findMother(T thePart) {
667 auto partOriVert = thePart->production_vertex();
668 if (!partOriVert) return nullptr;
669
670 long partPDG = thePart->pdg_id();
671 long MotherPDG(0);
672
673 auto MothOriVert = partOriVert;
674 MothOriVert = nullptr;
675 T theMoth(nullptr);
676
677 size_t itr = 0;
678 do {
679 if (itr != 0) partOriVert = MothOriVert;
680 for ( const auto& p : particles_in(partOriVert) ) {
681 theMoth = p;
682 if (!theMoth) continue;
683 MotherPDG = theMoth->pdg_id();
684 MothOriVert = theMoth->production_vertex();
685 if (MotherPDG == partPDG) break;
686 }
687 itr++;
688 if (itr > 100) {
689 break;
690 }
691 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
692 MothOriVert != partOriVert);
693 return theMoth;
694 }
695
697
698 template <class C, class T> T findMatching(C TruthContainer, T p) {
699 T ptrPart = nullptr;
700 if (!p) return ptrPart;
701 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
702 for (T truthParticle : *TruthContainer) {
703 if (HepMC::is_sim_descendant(p,truthParticle)) {
704 ptrPart = truthParticle;
705 break;
706 }
707 }
708 }
709 else {
710 for (T truthParticle : TruthContainer) {
711 if (HepMC::is_sim_descendant(p,truthParticle)) {
712 ptrPart = truthParticle;
713 break;
714 }
715 }
716 }
717 return ptrPart;
718 }
720
721 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
722 auto prodVtx = thePart->production_vertex();
723 if (!prodVtx) return;
724 for (const auto& theMother: prodVtx->particles_in()) {
725 if (!theMother) continue;
726 allancestors.insert(theMother);
727 findParticleAncestors(theMother, allancestors);
728 }
729 }
730
732
733 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
734 auto endVtx = thePart->end_vertex();
735 if (!endVtx) return;
736 for (const auto& theDaughter: endVtx->particles_out()) {
737 if (!theDaughter) continue;
738 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
739 allstabledescendants.insert(theDaughter);
740 }
741 findParticleStableDescendants(theDaughter, allstabledescendants);
742 }
743 }
744
748
749 template <class T> bool isHardScatteringVertex(T pVert) {
750 if (pVert == nullptr) return false;
751 T pV = pVert;
752 int numOfPartIn(0);
753 int pdg(0);
754
755 do {
756 pVert = pV;
757 auto incoming = pVert->particles_in();
758 numOfPartIn = incoming.size();
759 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
760 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
761
762 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
763
764 if (numOfPartIn == 2) {
765 auto incoming = pVert->particles_in();
766 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
767 }
768 return false;
769}
770
774
775 template <class T, class U>
776 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
777 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
778 auto vtx = p->production_vertex();
779 if (!vtx) return false;
780 bool fromHad = false;
781 for ( const auto& parent : particles_in(vtx) ) {
782 if (!parent) continue;
783 // should this really go into parton-level territory?
784 // probably depends where BSM particles are being decayed
785 fromBSM |= isBSM(parent);
786 if (!isPhysical(parent)) return false;
787 fromTau |= isTau(parent);
788 if (isHadron(parent)&&!isBeam(parent)) {
789 if (!hadron) hadron = parent; // assumes linear hadron parentage
790 return true;
791 }
792 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
793 }
794 return fromHad;
795 }
796
799
800 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
801 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
802 decltype(thePart->end_vertex()) pVert(nullptr);
803 if (EndVert != nullptr) {
804 do {
805 bool samePart = false;
806 pVert = nullptr;
807 auto outgoing = EndVert->particles_out();
808 auto incoming = EndVert->particles_in();
809 for (const auto& itrDaug: outgoing) {
810 if (!itrDaug) continue;
811 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
812 // brem on generator level for tau
813 (outgoing.size() == 1 && incoming.size() == 1 &&
815 itrDaug->pdg_id() == thePart->pdg_id()) {
816 samePart = true;
817 pVert = itrDaug->end_vertex();
818 }
819 }
820 if (samePart) EndVert = pVert;
821 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
822 }
823 return EndVert;
824 }
825
827
828 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
829 if (!theVert) return {};
830 decltype(theVert->particles_out()) finalStatePart;
831 auto outgoing = theVert->particles_out();
832 for (const auto& thePart: outgoing) {
833 if (!thePart) continue;
834 finalStatePart.push_back(thePart);
835 if (isStable(thePart)) continue;
836 V pVert = findSimulatedEndVertex(thePart);
837 if (pVert == theVert) break; // to prevent Sherpa loop
838 if (pVert != nullptr) {
839 auto vecPart = findFinalStateParticles<V>(pVert);
840 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
841 }
842 }
843 return finalStatePart;
844 }
845
846}
847#endif

◆ isRGlueball() [2/3]

template<>
bool MC::isRGlueball ( const int & p)
inline

Definition at line 571 of file HepMCHelpers.h.

592{
593inline
594auto particles_in (const HepMC::GenVertex* p) {
595 return std::ranges::subrange (p->particles_in_const_begin(),
596 p->particles_in_const_end());
597}
598}
599#endif
600
601namespace MC
602{
603 template <class VTX>
604 auto particles_in (const VTX* p) { return p->particles_in(); }
605 template <class VTX>
606 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
607
608 namespace Pythia8
609 {
611 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
612
613 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
614
615 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
616 }
617
618#include "AtlasPID.h"
619
621 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
622
624 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
625
627 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
628
630 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
631
633 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
634
636 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
637
639 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
640
642 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
643
645 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
646
648 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
649
653 template <class T> inline bool isStableOrSimDecayed(const T& p) {
654 const auto vertex = p->end_vertex();
655 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
656 }
657
659 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
660
662 template <class T> inline bool isSpecialNonInteracting(const T& p) {
663 const int apid = std::abs(p->pdg_id());
664 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
665 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
666 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
667 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
668 return false;
669 }
670
672
673 template <class T> T findMother(T thePart) {
674 auto partOriVert = thePart->production_vertex();
675 if (!partOriVert) return nullptr;
676
677 long partPDG = thePart->pdg_id();
678 long MotherPDG(0);
679
680 auto MothOriVert = partOriVert;
681 MothOriVert = nullptr;
682 T theMoth(nullptr);
683
684 size_t itr = 0;
685 do {
686 if (itr != 0) partOriVert = MothOriVert;
687 for ( const auto& p : particles_in(partOriVert) ) {
688 theMoth = p;
689 if (!theMoth) continue;
690 MotherPDG = theMoth->pdg_id();
691 MothOriVert = theMoth->production_vertex();
692 if (MotherPDG == partPDG) break;
693 }
694 itr++;
695 if (itr > 100) {
696 break;
697 }
698 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
699 MothOriVert != partOriVert);
700 return theMoth;
701 }
702
704
705 template <class C, class T> T findMatching(C TruthContainer, T p) {
706 T ptrPart = nullptr;
707 if (!p) return ptrPart;
708 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
709 for (T truthParticle : *TruthContainer) {
710 if (HepMC::is_sim_descendant(p,truthParticle)) {
711 ptrPart = truthParticle;
712 break;
713 }
714 }
715 }
716 else {
717 for (T truthParticle : TruthContainer) {
718 if (HepMC::is_sim_descendant(p,truthParticle)) {
719 ptrPart = truthParticle;
720 break;
721 }
722 }
723 }
724 return ptrPart;
725 }
727
728 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
729 auto prodVtx = thePart->production_vertex();
730 if (!prodVtx) return;
731 for (const auto& theMother: prodVtx->particles_in()) {
732 if (!theMother) continue;
733 allancestors.insert(theMother);
734 findParticleAncestors(theMother, allancestors);
735 }
736 }
737
739
740 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
741 auto endVtx = thePart->end_vertex();
742 if (!endVtx) return;
743 for (const auto& theDaughter: endVtx->particles_out()) {
744 if (!theDaughter) continue;
745 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
746 allstabledescendants.insert(theDaughter);
747 }
748 findParticleStableDescendants(theDaughter, allstabledescendants);
749 }
750 }
751
755
756 template <class T> bool isHardScatteringVertex(T pVert) {
757 if (pVert == nullptr) return false;
758 T pV = pVert;
759 int numOfPartIn(0);
760 int pdg(0);
761
762 do {
763 pVert = pV;
764 auto incoming = pVert->particles_in();
765 numOfPartIn = incoming.size();
766 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
767 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
768
769 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
770
771 if (numOfPartIn == 2) {
772 auto incoming = pVert->particles_in();
773 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
774 }
775 return false;
776}
777
781
782 template <class T, class U>
783 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
784 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
785 auto vtx = p->production_vertex();
786 if (!vtx) return false;
787 bool fromHad = false;
788 for ( const auto& parent : particles_in(vtx) ) {
789 if (!parent) continue;
790 // should this really go into parton-level territory?
791 // probably depends where BSM particles are being decayed
792 fromBSM |= isBSM(parent);
793 if (!isPhysical(parent)) return false;
794 fromTau |= isTau(parent);
795 if (isHadron(parent)&&!isBeam(parent)) {
796 if (!hadron) hadron = parent; // assumes linear hadron parentage
797 return true;
798 }
799 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
800 }
801 return fromHad;
802 }
803
806
807 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
808 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
809 decltype(thePart->end_vertex()) pVert(nullptr);
810 if (EndVert != nullptr) {
811 do {
812 bool samePart = false;
813 pVert = nullptr;
814 auto outgoing = EndVert->particles_out();
815 auto incoming = EndVert->particles_in();
816 for (const auto& itrDaug: outgoing) {
817 if (!itrDaug) continue;
818 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
819 // brem on generator level for tau
820 (outgoing.size() == 1 && incoming.size() == 1 &&
822 itrDaug->pdg_id() == thePart->pdg_id()) {
823 samePart = true;
824 pVert = itrDaug->end_vertex();
825 }
826 }
827 if (samePart) EndVert = pVert;
828 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
829 }
830 return EndVert;
831 }
832
834
835 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
836 if (!theVert) return {};
837 decltype(theVert->particles_out()) finalStatePart;
838 auto outgoing = theVert->particles_out();
839 for (const auto& thePart: outgoing) {
840 if (!thePart) continue;
841 finalStatePart.push_back(thePart);
842 if (isStable(thePart)) continue;
843 V pVert = findSimulatedEndVertex(thePart);
844 if (pVert == theVert) break; // to prevent Sherpa loop
845 if (pVert != nullptr) {
846 auto vecPart = findFinalStateParticles<V>(pVert);
847 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
848 }
849 }
850 return finalStatePart;
851 }
852
853}
854#endif

◆ isRGlueball() [3/3]

template<class T>
bool MC::isRGlueball ( const T & p)
inline

PDG rule 11g: Within several scenarios of new physics, it is possible to have colored particles sufficiently long-lived for color-singlet hadronic states to form around them.

In the context of supersymmetric scenarios, these states are called R-hadrons, since they carry odd R- parity. R-hadron codes, defined here, should be viewed as templates for corresponding codes also in other scenarios, for any long-lived particle that is either an unflavored color octet or a flavored color triplet. The R-hadron code is obtained by combining the SUSY particle code with a code for the light degrees of freedom, with as many intermediate zeros removed from the former as required to make place for the latter at the end. (To exemplify, a sparticle n00000n˜q combined with quarks q1 and q2 obtains code n00n˜qnq1 nq2 nJ .) Specifically, the new-particle spin decouples in the limit of large masses, so that the final nJ digit is defined by the spin state of the light-quark system alone. An appropriate number of nq digits is used to define the ordinary-quark content. As usual, 9 rather than 21 is used to denote a gluon/gluino in composite states. The sign of the hadron agrees with that of the constituent new particle (a color triplet) where there is a distinct new antiparticle, and else is defined as for normal hadrons. Particle names are R with the flavor content as lower index. APID: Definition of R-Glueballs: 100099X (X=1,3), 100999Y (Y=1,5) APID: NB In the current numbering scheme, some states with 2 gluinos + gluon or 2 gluons + gluino could have degenerate PDG_IDs.

Definition at line 563 of file HepMCHelpers.h.

584{
585inline
586auto particles_in (const HepMC::GenVertex* p) {
587 return std::ranges::subrange (p->particles_in_const_begin(),
588 p->particles_in_const_end());
589}
590}
591#endif
592
593namespace MC
594{
595 template <class VTX>
596 auto particles_in (const VTX* p) { return p->particles_in(); }
597 template <class VTX>
598 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
599
600 namespace Pythia8
601 {
603 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
604
605 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
606
607 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
608 }
609
610#include "AtlasPID.h"
611
613 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
614
616 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
617
619 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
620
622 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
623
625 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
626
628 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
629
631 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
632
634 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
635
637 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
638
640 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
641
645 template <class T> inline bool isStableOrSimDecayed(const T& p) {
646 const auto vertex = p->end_vertex();
647 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
648 }
649
651 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
652
654 template <class T> inline bool isSpecialNonInteracting(const T& p) {
655 const int apid = std::abs(p->pdg_id());
656 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
657 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
658 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
659 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
660 return false;
661 }
662
664
665 template <class T> T findMother(T thePart) {
666 auto partOriVert = thePart->production_vertex();
667 if (!partOriVert) return nullptr;
668
669 long partPDG = thePart->pdg_id();
670 long MotherPDG(0);
671
672 auto MothOriVert = partOriVert;
673 MothOriVert = nullptr;
674 T theMoth(nullptr);
675
676 size_t itr = 0;
677 do {
678 if (itr != 0) partOriVert = MothOriVert;
679 for ( const auto& p : particles_in(partOriVert) ) {
680 theMoth = p;
681 if (!theMoth) continue;
682 MotherPDG = theMoth->pdg_id();
683 MothOriVert = theMoth->production_vertex();
684 if (MotherPDG == partPDG) break;
685 }
686 itr++;
687 if (itr > 100) {
688 break;
689 }
690 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
691 MothOriVert != partOriVert);
692 return theMoth;
693 }
694
696
697 template <class C, class T> T findMatching(C TruthContainer, T p) {
698 T ptrPart = nullptr;
699 if (!p) return ptrPart;
700 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
701 for (T truthParticle : *TruthContainer) {
702 if (HepMC::is_sim_descendant(p,truthParticle)) {
703 ptrPart = truthParticle;
704 break;
705 }
706 }
707 }
708 else {
709 for (T truthParticle : TruthContainer) {
710 if (HepMC::is_sim_descendant(p,truthParticle)) {
711 ptrPart = truthParticle;
712 break;
713 }
714 }
715 }
716 return ptrPart;
717 }
719
720 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
721 auto prodVtx = thePart->production_vertex();
722 if (!prodVtx) return;
723 for (const auto& theMother: prodVtx->particles_in()) {
724 if (!theMother) continue;
725 allancestors.insert(theMother);
726 findParticleAncestors(theMother, allancestors);
727 }
728 }
729
731
732 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
733 auto endVtx = thePart->end_vertex();
734 if (!endVtx) return;
735 for (const auto& theDaughter: endVtx->particles_out()) {
736 if (!theDaughter) continue;
737 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
738 allstabledescendants.insert(theDaughter);
739 }
740 findParticleStableDescendants(theDaughter, allstabledescendants);
741 }
742 }
743
747
748 template <class T> bool isHardScatteringVertex(T pVert) {
749 if (pVert == nullptr) return false;
750 T pV = pVert;
751 int numOfPartIn(0);
752 int pdg(0);
753
754 do {
755 pVert = pV;
756 auto incoming = pVert->particles_in();
757 numOfPartIn = incoming.size();
758 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
759 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
760
761 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
762
763 if (numOfPartIn == 2) {
764 auto incoming = pVert->particles_in();
765 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
766 }
767 return false;
768}
769
773
774 template <class T, class U>
775 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
776 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
777 auto vtx = p->production_vertex();
778 if (!vtx) return false;
779 bool fromHad = false;
780 for ( const auto& parent : particles_in(vtx) ) {
781 if (!parent) continue;
782 // should this really go into parton-level territory?
783 // probably depends where BSM particles are being decayed
784 fromBSM |= isBSM(parent);
785 if (!isPhysical(parent)) return false;
786 fromTau |= isTau(parent);
787 if (isHadron(parent)&&!isBeam(parent)) {
788 if (!hadron) hadron = parent; // assumes linear hadron parentage
789 return true;
790 }
791 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
792 }
793 return fromHad;
794 }
795
798
799 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
800 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
801 decltype(thePart->end_vertex()) pVert(nullptr);
802 if (EndVert != nullptr) {
803 do {
804 bool samePart = false;
805 pVert = nullptr;
806 auto outgoing = EndVert->particles_out();
807 auto incoming = EndVert->particles_in();
808 for (const auto& itrDaug: outgoing) {
809 if (!itrDaug) continue;
810 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
811 // brem on generator level for tau
812 (outgoing.size() == 1 && incoming.size() == 1 &&
814 itrDaug->pdg_id() == thePart->pdg_id()) {
815 samePart = true;
816 pVert = itrDaug->end_vertex();
817 }
818 }
819 if (samePart) EndVert = pVert;
820 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
821 }
822 return EndVert;
823 }
824
826
827 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
828 if (!theVert) return {};
829 decltype(theVert->particles_out()) finalStatePart;
830 auto outgoing = theVert->particles_out();
831 for (const auto& thePart: outgoing) {
832 if (!thePart) continue;
833 finalStatePart.push_back(thePart);
834 if (isStable(thePart)) continue;
835 V pVert = findSimulatedEndVertex(thePart);
836 if (pVert == theVert) break; // to prevent Sherpa loop
837 if (pVert != nullptr) {
838 auto vecPart = findFinalStateParticles<V>(pVert);
839 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
840 }
841 }
842 return finalStatePart;
843 }
844
845}
846#endif

◆ isRHadron() [1/3]

template<>
bool MC::isRHadron ( const DecodedPID & p)
inline

Definition at line 605 of file HepMCHelpers.h.

626 {
627inline
628auto particles_in (const HepMC::GenVertex* p) {
629 return std::ranges::subrange (p->particles_in_const_begin(),
630 p->particles_in_const_end());
631}
632}
633#endif
634
635namespace MC
636{
637 template <class VTX>
638 auto particles_in (const VTX* p) { return p->particles_in(); }
639 template <class VTX>
640 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
641
642 namespace Pythia8
643 {
645 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
646
647 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
648
649 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
650 }
651
652#include "AtlasPID.h"
653
655 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
656
658 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
659
661 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
662
664 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
665
667 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
668
670 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
671
673 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
674
676 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
677
679 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
680
682 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
683
687 template <class T> inline bool isStableOrSimDecayed(const T& p) {
688 const auto vertex = p->end_vertex();
689 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
690 }
691
693 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
694
696 template <class T> inline bool isSpecialNonInteracting(const T& p) {
697 const int apid = std::abs(p->pdg_id());
698 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
699 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
700 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
701 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
702 return false;
703 }
704
706
707 template <class T> T findMother(T thePart) {
708 auto partOriVert = thePart->production_vertex();
709 if (!partOriVert) return nullptr;
710
711 long partPDG = thePart->pdg_id();
712 long MotherPDG(0);
713
714 auto MothOriVert = partOriVert;
715 MothOriVert = nullptr;
716 T theMoth(nullptr);
717
718 size_t itr = 0;
719 do {
720 if (itr != 0) partOriVert = MothOriVert;
721 for ( const auto& p : particles_in(partOriVert) ) {
722 theMoth = p;
723 if (!theMoth) continue;
724 MotherPDG = theMoth->pdg_id();
725 MothOriVert = theMoth->production_vertex();
726 if (MotherPDG == partPDG) break;
727 }
728 itr++;
729 if (itr > 100) {
730 break;
731 }
732 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
733 MothOriVert != partOriVert);
734 return theMoth;
735 }
736
738
739 template <class C, class T> T findMatching(C TruthContainer, T p) {
740 T ptrPart = nullptr;
741 if (!p) return ptrPart;
742 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
743 for (T truthParticle : *TruthContainer) {
744 if (HepMC::is_sim_descendant(p,truthParticle)) {
745 ptrPart = truthParticle;
746 break;
747 }
748 }
749 }
750 else {
751 for (T truthParticle : TruthContainer) {
752 if (HepMC::is_sim_descendant(p,truthParticle)) {
753 ptrPart = truthParticle;
754 break;
755 }
756 }
757 }
758 return ptrPart;
759 }
761
762 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
763 auto prodVtx = thePart->production_vertex();
764 if (!prodVtx) return;
765 for (const auto& theMother: prodVtx->particles_in()) {
766 if (!theMother) continue;
767 allancestors.insert(theMother);
768 findParticleAncestors(theMother, allancestors);
769 }
770 }
771
773
774 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
775 auto endVtx = thePart->end_vertex();
776 if (!endVtx) return;
777 for (const auto& theDaughter: endVtx->particles_out()) {
778 if (!theDaughter) continue;
779 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
780 allstabledescendants.insert(theDaughter);
781 }
782 findParticleStableDescendants(theDaughter, allstabledescendants);
783 }
784 }
785
789
790 template <class T> bool isHardScatteringVertex(T pVert) {
791 if (pVert == nullptr) return false;
792 T pV = pVert;
793 int numOfPartIn(0);
794 int pdg(0);
795
796 do {
797 pVert = pV;
798 auto incoming = pVert->particles_in();
799 numOfPartIn = incoming.size();
800 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
801 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
802
803 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
804
805 if (numOfPartIn == 2) {
806 auto incoming = pVert->particles_in();
807 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
808 }
809 return false;
810}
811
815
816 template <class T, class U>
817 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
818 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
819 auto vtx = p->production_vertex();
820 if (!vtx) return false;
821 bool fromHad = false;
822 for ( const auto& parent : particles_in(vtx) ) {
823 if (!parent) continue;
824 // should this really go into parton-level territory?
825 // probably depends where BSM particles are being decayed
826 fromBSM |= isBSM(parent);
827 if (!isPhysical(parent)) return false;
828 fromTau |= isTau(parent);
829 if (isHadron(parent)&&!isBeam(parent)) {
830 if (!hadron) hadron = parent; // assumes linear hadron parentage
831 return true;
832 }
833 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
834 }
835 return fromHad;
836 }
837
840
841 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
842 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
843 decltype(thePart->end_vertex()) pVert(nullptr);
844 if (EndVert != nullptr) {
845 do {
846 bool samePart = false;
847 pVert = nullptr;
848 auto outgoing = EndVert->particles_out();
849 auto incoming = EndVert->particles_in();
850 for (const auto& itrDaug: outgoing) {
851 if (!itrDaug) continue;
852 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
853 // brem on generator level for tau
854 (outgoing.size() == 1 && incoming.size() == 1 &&
856 itrDaug->pdg_id() == thePart->pdg_id()) {
857 samePart = true;
858 pVert = itrDaug->end_vertex();
859 }
860 }
861 if (samePart) EndVert = pVert;
862 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
863 }
864 return EndVert;
865 }
866
868
869 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
870 if (!theVert) return {};
871 decltype(theVert->particles_out()) finalStatePart;
872 auto outgoing = theVert->particles_out();
873 for (const auto& thePart: outgoing) {
874 if (!thePart) continue;
875 finalStatePart.push_back(thePart);
876 if (isStable(thePart)) continue;
877 V pVert = findSimulatedEndVertex(thePart);
878 if (pVert == theVert) break; // to prevent Sherpa loop
879 if (pVert != nullptr) {
880 auto vecPart = findFinalStateParticles<V>(pVert);
881 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
882 }
883 }
884 return finalStatePart;
885 }
886
887}
888#endif

◆ isRHadron() [2/3]

template<>
bool MC::isRHadron ( const int & p)
inline

Definition at line 608 of file HepMCHelpers.h.

629{
630inline
631auto particles_in (const HepMC::GenVertex* p) {
632 return std::ranges::subrange (p->particles_in_const_begin(),
633 p->particles_in_const_end());
634}
635}
636#endif
637
638namespace MC
639{
640 template <class VTX>
641 auto particles_in (const VTX* p) { return p->particles_in(); }
642 template <class VTX>
643 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
644
645 namespace Pythia8
646 {
648 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
649
650 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
651
652 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
653 }
654
655#include "AtlasPID.h"
656
658 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
659
661 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
662
664 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
665
667 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
668
670 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
671
673 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
674
676 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
677
679 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
680
682 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
683
685 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
686
690 template <class T> inline bool isStableOrSimDecayed(const T& p) {
691 const auto vertex = p->end_vertex();
692 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
693 }
694
696 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
697
699 template <class T> inline bool isSpecialNonInteracting(const T& p) {
700 const int apid = std::abs(p->pdg_id());
701 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
702 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
703 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
704 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
705 return false;
706 }
707
709
710 template <class T> T findMother(T thePart) {
711 auto partOriVert = thePart->production_vertex();
712 if (!partOriVert) return nullptr;
713
714 long partPDG = thePart->pdg_id();
715 long MotherPDG(0);
716
717 auto MothOriVert = partOriVert;
718 MothOriVert = nullptr;
719 T theMoth(nullptr);
720
721 size_t itr = 0;
722 do {
723 if (itr != 0) partOriVert = MothOriVert;
724 for ( const auto& p : particles_in(partOriVert) ) {
725 theMoth = p;
726 if (!theMoth) continue;
727 MotherPDG = theMoth->pdg_id();
728 MothOriVert = theMoth->production_vertex();
729 if (MotherPDG == partPDG) break;
730 }
731 itr++;
732 if (itr > 100) {
733 break;
734 }
735 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
736 MothOriVert != partOriVert);
737 return theMoth;
738 }
739
741
742 template <class C, class T> T findMatching(C TruthContainer, T p) {
743 T ptrPart = nullptr;
744 if (!p) return ptrPart;
745 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
746 for (T truthParticle : *TruthContainer) {
747 if (HepMC::is_sim_descendant(p,truthParticle)) {
748 ptrPart = truthParticle;
749 break;
750 }
751 }
752 }
753 else {
754 for (T truthParticle : TruthContainer) {
755 if (HepMC::is_sim_descendant(p,truthParticle)) {
756 ptrPart = truthParticle;
757 break;
758 }
759 }
760 }
761 return ptrPart;
762 }
764
765 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
766 auto prodVtx = thePart->production_vertex();
767 if (!prodVtx) return;
768 for (const auto& theMother: prodVtx->particles_in()) {
769 if (!theMother) continue;
770 allancestors.insert(theMother);
771 findParticleAncestors(theMother, allancestors);
772 }
773 }
774
776
777 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
778 auto endVtx = thePart->end_vertex();
779 if (!endVtx) return;
780 for (const auto& theDaughter: endVtx->particles_out()) {
781 if (!theDaughter) continue;
782 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
783 allstabledescendants.insert(theDaughter);
784 }
785 findParticleStableDescendants(theDaughter, allstabledescendants);
786 }
787 }
788
792
793 template <class T> bool isHardScatteringVertex(T pVert) {
794 if (pVert == nullptr) return false;
795 T pV = pVert;
796 int numOfPartIn(0);
797 int pdg(0);
798
799 do {
800 pVert = pV;
801 auto incoming = pVert->particles_in();
802 numOfPartIn = incoming.size();
803 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
804 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
805
806 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
807
808 if (numOfPartIn == 2) {
809 auto incoming = pVert->particles_in();
810 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
811 }
812 return false;
813}
814
818
819 template <class T, class U>
820 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
821 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
822 auto vtx = p->production_vertex();
823 if (!vtx) return false;
824 bool fromHad = false;
825 for ( const auto& parent : particles_in(vtx) ) {
826 if (!parent) continue;
827 // should this really go into parton-level territory?
828 // probably depends where BSM particles are being decayed
829 fromBSM |= isBSM(parent);
830 if (!isPhysical(parent)) return false;
831 fromTau |= isTau(parent);
832 if (isHadron(parent)&&!isBeam(parent)) {
833 if (!hadron) hadron = parent; // assumes linear hadron parentage
834 return true;
835 }
836 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
837 }
838 return fromHad;
839 }
840
843
844 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
845 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
846 decltype(thePart->end_vertex()) pVert(nullptr);
847 if (EndVert != nullptr) {
848 do {
849 bool samePart = false;
850 pVert = nullptr;
851 auto outgoing = EndVert->particles_out();
852 auto incoming = EndVert->particles_in();
853 for (const auto& itrDaug: outgoing) {
854 if (!itrDaug) continue;
855 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
856 // brem on generator level for tau
857 (outgoing.size() == 1 && incoming.size() == 1 &&
859 itrDaug->pdg_id() == thePart->pdg_id()) {
860 samePart = true;
861 pVert = itrDaug->end_vertex();
862 }
863 }
864 if (samePart) EndVert = pVert;
865 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
866 }
867 return EndVert;
868 }
869
871
872 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
873 if (!theVert) return {};
874 decltype(theVert->particles_out()) finalStatePart;
875 auto outgoing = theVert->particles_out();
876 for (const auto& thePart: outgoing) {
877 if (!thePart) continue;
878 finalStatePart.push_back(thePart);
879 if (isStable(thePart)) continue;
880 V pVert = findSimulatedEndVertex(thePart);
881 if (pVert == theVert) break; // to prevent Sherpa loop
882 if (pVert != nullptr) {
883 auto vecPart = findFinalStateParticles<V>(pVert);
884 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
885 }
886 }
887 return finalStatePart;
888 }
889
890}
891#endif

◆ isRHadron() [3/3]

template<class T>
bool MC::isRHadron ( const T & p)
inline

Definition at line 604 of file HepMCHelpers.h.

625{
626inline
627auto particles_in (const HepMC::GenVertex* p) {
628 return std::ranges::subrange (p->particles_in_const_begin(),
629 p->particles_in_const_end());
630}
631}
632#endif
633
634namespace MC
635{
636 template <class VTX>
637 auto particles_in (const VTX* p) { return p->particles_in(); }
638 template <class VTX>
639 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
640
641 namespace Pythia8
642 {
644 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
645
646 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
647
648 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
649 }
650
651#include "AtlasPID.h"
652
654 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
655
657 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
658
660 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
661
663 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
664
666 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
667
669 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
670
672 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
673
675 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
676
678 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
679
681 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
682
686 template <class T> inline bool isStableOrSimDecayed(const T& p) {
687 const auto vertex = p->end_vertex();
688 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
689 }
690
692 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
693
695 template <class T> inline bool isSpecialNonInteracting(const T& p) {
696 const int apid = std::abs(p->pdg_id());
697 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
698 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
699 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
700 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
701 return false;
702 }
703
705
706 template <class T> T findMother(T thePart) {
707 auto partOriVert = thePart->production_vertex();
708 if (!partOriVert) return nullptr;
709
710 long partPDG = thePart->pdg_id();
711 long MotherPDG(0);
712
713 auto MothOriVert = partOriVert;
714 MothOriVert = nullptr;
715 T theMoth(nullptr);
716
717 size_t itr = 0;
718 do {
719 if (itr != 0) partOriVert = MothOriVert;
720 for ( const auto& p : particles_in(partOriVert) ) {
721 theMoth = p;
722 if (!theMoth) continue;
723 MotherPDG = theMoth->pdg_id();
724 MothOriVert = theMoth->production_vertex();
725 if (MotherPDG == partPDG) break;
726 }
727 itr++;
728 if (itr > 100) {
729 break;
730 }
731 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
732 MothOriVert != partOriVert);
733 return theMoth;
734 }
735
737
738 template <class C, class T> T findMatching(C TruthContainer, T p) {
739 T ptrPart = nullptr;
740 if (!p) return ptrPart;
741 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
742 for (T truthParticle : *TruthContainer) {
743 if (HepMC::is_sim_descendant(p,truthParticle)) {
744 ptrPart = truthParticle;
745 break;
746 }
747 }
748 }
749 else {
750 for (T truthParticle : TruthContainer) {
751 if (HepMC::is_sim_descendant(p,truthParticle)) {
752 ptrPart = truthParticle;
753 break;
754 }
755 }
756 }
757 return ptrPart;
758 }
760
761 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
762 auto prodVtx = thePart->production_vertex();
763 if (!prodVtx) return;
764 for (const auto& theMother: prodVtx->particles_in()) {
765 if (!theMother) continue;
766 allancestors.insert(theMother);
767 findParticleAncestors(theMother, allancestors);
768 }
769 }
770
772
773 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
774 auto endVtx = thePart->end_vertex();
775 if (!endVtx) return;
776 for (const auto& theDaughter: endVtx->particles_out()) {
777 if (!theDaughter) continue;
778 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
779 allstabledescendants.insert(theDaughter);
780 }
781 findParticleStableDescendants(theDaughter, allstabledescendants);
782 }
783 }
784
788
789 template <class T> bool isHardScatteringVertex(T pVert) {
790 if (pVert == nullptr) return false;
791 T pV = pVert;
792 int numOfPartIn(0);
793 int pdg(0);
794
795 do {
796 pVert = pV;
797 auto incoming = pVert->particles_in();
798 numOfPartIn = incoming.size();
799 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
800 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
801
802 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
803
804 if (numOfPartIn == 2) {
805 auto incoming = pVert->particles_in();
806 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
807 }
808 return false;
809}
810
814
815 template <class T, class U>
816 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
817 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
818 auto vtx = p->production_vertex();
819 if (!vtx) return false;
820 bool fromHad = false;
821 for ( const auto& parent : particles_in(vtx) ) {
822 if (!parent) continue;
823 // should this really go into parton-level territory?
824 // probably depends where BSM particles are being decayed
825 fromBSM |= isBSM(parent);
826 if (!isPhysical(parent)) return false;
827 fromTau |= isTau(parent);
828 if (isHadron(parent)&&!isBeam(parent)) {
829 if (!hadron) hadron = parent; // assumes linear hadron parentage
830 return true;
831 }
832 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
833 }
834 return fromHad;
835 }
836
839
840 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
841 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
842 decltype(thePart->end_vertex()) pVert(nullptr);
843 if (EndVert != nullptr) {
844 do {
845 bool samePart = false;
846 pVert = nullptr;
847 auto outgoing = EndVert->particles_out();
848 auto incoming = EndVert->particles_in();
849 for (const auto& itrDaug: outgoing) {
850 if (!itrDaug) continue;
851 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
852 // brem on generator level for tau
853 (outgoing.size() == 1 && incoming.size() == 1 &&
855 itrDaug->pdg_id() == thePart->pdg_id()) {
856 samePart = true;
857 pVert = itrDaug->end_vertex();
858 }
859 }
860 if (samePart) EndVert = pVert;
861 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
862 }
863 return EndVert;
864 }
865
867
868 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
869 if (!theVert) return {};
870 decltype(theVert->particles_out()) finalStatePart;
871 auto outgoing = theVert->particles_out();
872 for (const auto& thePart: outgoing) {
873 if (!thePart) continue;
874 finalStatePart.push_back(thePart);
875 if (isStable(thePart)) continue;
876 V pVert = findSimulatedEndVertex(thePart);
877 if (pVert == theVert) break; // to prevent Sherpa loop
878 if (pVert != nullptr) {
879 auto vecPart = findFinalStateParticles<V>(pVert);
880 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
881 }
882 }
883 return finalStatePart;
884 }
885
886}
887#endif

◆ isRMeson() [1/3]

template<>
bool MC::isRMeson ( const DecodedPID & p)
inline

Definition at line 576 of file HepMCHelpers.h.

597 {
598inline
599auto particles_in (const HepMC::GenVertex* p) {
600 return std::ranges::subrange (p->particles_in_const_begin(),
601 p->particles_in_const_end());
602}
603}
604#endif
605
606namespace MC
607{
608 template <class VTX>
609 auto particles_in (const VTX* p) { return p->particles_in(); }
610 template <class VTX>
611 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
612
613 namespace Pythia8
614 {
616 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
617
618 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
619
620 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
621 }
622
623#include "AtlasPID.h"
624
626 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
627
629 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
630
632 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
633
635 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
636
638 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
639
641 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
642
644 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
645
647 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
648
650 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
651
653 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
654
658 template <class T> inline bool isStableOrSimDecayed(const T& p) {
659 const auto vertex = p->end_vertex();
660 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
661 }
662
664 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
665
667 template <class T> inline bool isSpecialNonInteracting(const T& p) {
668 const int apid = std::abs(p->pdg_id());
669 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
670 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
671 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
672 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
673 return false;
674 }
675
677
678 template <class T> T findMother(T thePart) {
679 auto partOriVert = thePart->production_vertex();
680 if (!partOriVert) return nullptr;
681
682 long partPDG = thePart->pdg_id();
683 long MotherPDG(0);
684
685 auto MothOriVert = partOriVert;
686 MothOriVert = nullptr;
687 T theMoth(nullptr);
688
689 size_t itr = 0;
690 do {
691 if (itr != 0) partOriVert = MothOriVert;
692 for ( const auto& p : particles_in(partOriVert) ) {
693 theMoth = p;
694 if (!theMoth) continue;
695 MotherPDG = theMoth->pdg_id();
696 MothOriVert = theMoth->production_vertex();
697 if (MotherPDG == partPDG) break;
698 }
699 itr++;
700 if (itr > 100) {
701 break;
702 }
703 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
704 MothOriVert != partOriVert);
705 return theMoth;
706 }
707
709
710 template <class C, class T> T findMatching(C TruthContainer, T p) {
711 T ptrPart = nullptr;
712 if (!p) return ptrPart;
713 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
714 for (T truthParticle : *TruthContainer) {
715 if (HepMC::is_sim_descendant(p,truthParticle)) {
716 ptrPart = truthParticle;
717 break;
718 }
719 }
720 }
721 else {
722 for (T truthParticle : TruthContainer) {
723 if (HepMC::is_sim_descendant(p,truthParticle)) {
724 ptrPart = truthParticle;
725 break;
726 }
727 }
728 }
729 return ptrPart;
730 }
732
733 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
734 auto prodVtx = thePart->production_vertex();
735 if (!prodVtx) return;
736 for (const auto& theMother: prodVtx->particles_in()) {
737 if (!theMother) continue;
738 allancestors.insert(theMother);
739 findParticleAncestors(theMother, allancestors);
740 }
741 }
742
744
745 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
746 auto endVtx = thePart->end_vertex();
747 if (!endVtx) return;
748 for (const auto& theDaughter: endVtx->particles_out()) {
749 if (!theDaughter) continue;
750 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
751 allstabledescendants.insert(theDaughter);
752 }
753 findParticleStableDescendants(theDaughter, allstabledescendants);
754 }
755 }
756
760
761 template <class T> bool isHardScatteringVertex(T pVert) {
762 if (pVert == nullptr) return false;
763 T pV = pVert;
764 int numOfPartIn(0);
765 int pdg(0);
766
767 do {
768 pVert = pV;
769 auto incoming = pVert->particles_in();
770 numOfPartIn = incoming.size();
771 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
772 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
773
774 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
775
776 if (numOfPartIn == 2) {
777 auto incoming = pVert->particles_in();
778 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
779 }
780 return false;
781}
782
786
787 template <class T, class U>
788 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
789 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
790 auto vtx = p->production_vertex();
791 if (!vtx) return false;
792 bool fromHad = false;
793 for ( const auto& parent : particles_in(vtx) ) {
794 if (!parent) continue;
795 // should this really go into parton-level territory?
796 // probably depends where BSM particles are being decayed
797 fromBSM |= isBSM(parent);
798 if (!isPhysical(parent)) return false;
799 fromTau |= isTau(parent);
800 if (isHadron(parent)&&!isBeam(parent)) {
801 if (!hadron) hadron = parent; // assumes linear hadron parentage
802 return true;
803 }
804 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
805 }
806 return fromHad;
807 }
808
811
812 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
813 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
814 decltype(thePart->end_vertex()) pVert(nullptr);
815 if (EndVert != nullptr) {
816 do {
817 bool samePart = false;
818 pVert = nullptr;
819 auto outgoing = EndVert->particles_out();
820 auto incoming = EndVert->particles_in();
821 for (const auto& itrDaug: outgoing) {
822 if (!itrDaug) continue;
823 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
824 // brem on generator level for tau
825 (outgoing.size() == 1 && incoming.size() == 1 &&
827 itrDaug->pdg_id() == thePart->pdg_id()) {
828 samePart = true;
829 pVert = itrDaug->end_vertex();
830 }
831 }
832 if (samePart) EndVert = pVert;
833 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
834 }
835 return EndVert;
836 }
837
839
840 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
841 if (!theVert) return {};
842 decltype(theVert->particles_out()) finalStatePart;
843 auto outgoing = theVert->particles_out();
844 for (const auto& thePart: outgoing) {
845 if (!thePart) continue;
846 finalStatePart.push_back(thePart);
847 if (isStable(thePart)) continue;
848 V pVert = findSimulatedEndVertex(thePart);
849 if (pVert == theVert) break; // to prevent Sherpa loop
850 if (pVert != nullptr) {
851 auto vecPart = findFinalStateParticles<V>(pVert);
852 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
853 }
854 }
855 return finalStatePart;
856 }
857
858}
859#endif

◆ isRMeson() [2/3]

template<>
bool MC::isRMeson ( const int & p)
inline

Definition at line 586 of file HepMCHelpers.h.

607{
608inline
609auto particles_in (const HepMC::GenVertex* p) {
610 return std::ranges::subrange (p->particles_in_const_begin(),
611 p->particles_in_const_end());
612}
613}
614#endif
615
616namespace MC
617{
618 template <class VTX>
619 auto particles_in (const VTX* p) { return p->particles_in(); }
620 template <class VTX>
621 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
622
623 namespace Pythia8
624 {
626 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
627
628 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
629
630 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
631 }
632
633#include "AtlasPID.h"
634
636 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
637
639 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
640
642 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
643
645 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
646
648 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
649
651 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
652
654 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
655
657 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
658
660 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
661
663 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
664
668 template <class T> inline bool isStableOrSimDecayed(const T& p) {
669 const auto vertex = p->end_vertex();
670 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
671 }
672
674 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
675
677 template <class T> inline bool isSpecialNonInteracting(const T& p) {
678 const int apid = std::abs(p->pdg_id());
679 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
680 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
681 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
682 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
683 return false;
684 }
685
687
688 template <class T> T findMother(T thePart) {
689 auto partOriVert = thePart->production_vertex();
690 if (!partOriVert) return nullptr;
691
692 long partPDG = thePart->pdg_id();
693 long MotherPDG(0);
694
695 auto MothOriVert = partOriVert;
696 MothOriVert = nullptr;
697 T theMoth(nullptr);
698
699 size_t itr = 0;
700 do {
701 if (itr != 0) partOriVert = MothOriVert;
702 for ( const auto& p : particles_in(partOriVert) ) {
703 theMoth = p;
704 if (!theMoth) continue;
705 MotherPDG = theMoth->pdg_id();
706 MothOriVert = theMoth->production_vertex();
707 if (MotherPDG == partPDG) break;
708 }
709 itr++;
710 if (itr > 100) {
711 break;
712 }
713 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
714 MothOriVert != partOriVert);
715 return theMoth;
716 }
717
719
720 template <class C, class T> T findMatching(C TruthContainer, T p) {
721 T ptrPart = nullptr;
722 if (!p) return ptrPart;
723 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
724 for (T truthParticle : *TruthContainer) {
725 if (HepMC::is_sim_descendant(p,truthParticle)) {
726 ptrPart = truthParticle;
727 break;
728 }
729 }
730 }
731 else {
732 for (T truthParticle : TruthContainer) {
733 if (HepMC::is_sim_descendant(p,truthParticle)) {
734 ptrPart = truthParticle;
735 break;
736 }
737 }
738 }
739 return ptrPart;
740 }
742
743 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
744 auto prodVtx = thePart->production_vertex();
745 if (!prodVtx) return;
746 for (const auto& theMother: prodVtx->particles_in()) {
747 if (!theMother) continue;
748 allancestors.insert(theMother);
749 findParticleAncestors(theMother, allancestors);
750 }
751 }
752
754
755 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
756 auto endVtx = thePart->end_vertex();
757 if (!endVtx) return;
758 for (const auto& theDaughter: endVtx->particles_out()) {
759 if (!theDaughter) continue;
760 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
761 allstabledescendants.insert(theDaughter);
762 }
763 findParticleStableDescendants(theDaughter, allstabledescendants);
764 }
765 }
766
770
771 template <class T> bool isHardScatteringVertex(T pVert) {
772 if (pVert == nullptr) return false;
773 T pV = pVert;
774 int numOfPartIn(0);
775 int pdg(0);
776
777 do {
778 pVert = pV;
779 auto incoming = pVert->particles_in();
780 numOfPartIn = incoming.size();
781 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
782 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
783
784 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
785
786 if (numOfPartIn == 2) {
787 auto incoming = pVert->particles_in();
788 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
789 }
790 return false;
791}
792
796
797 template <class T, class U>
798 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
799 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
800 auto vtx = p->production_vertex();
801 if (!vtx) return false;
802 bool fromHad = false;
803 for ( const auto& parent : particles_in(vtx) ) {
804 if (!parent) continue;
805 // should this really go into parton-level territory?
806 // probably depends where BSM particles are being decayed
807 fromBSM |= isBSM(parent);
808 if (!isPhysical(parent)) return false;
809 fromTau |= isTau(parent);
810 if (isHadron(parent)&&!isBeam(parent)) {
811 if (!hadron) hadron = parent; // assumes linear hadron parentage
812 return true;
813 }
814 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
815 }
816 return fromHad;
817 }
818
821
822 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
823 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
824 decltype(thePart->end_vertex()) pVert(nullptr);
825 if (EndVert != nullptr) {
826 do {
827 bool samePart = false;
828 pVert = nullptr;
829 auto outgoing = EndVert->particles_out();
830 auto incoming = EndVert->particles_in();
831 for (const auto& itrDaug: outgoing) {
832 if (!itrDaug) continue;
833 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
834 // brem on generator level for tau
835 (outgoing.size() == 1 && incoming.size() == 1 &&
837 itrDaug->pdg_id() == thePart->pdg_id()) {
838 samePart = true;
839 pVert = itrDaug->end_vertex();
840 }
841 }
842 if (samePart) EndVert = pVert;
843 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
844 }
845 return EndVert;
846 }
847
849
850 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
851 if (!theVert) return {};
852 decltype(theVert->particles_out()) finalStatePart;
853 auto outgoing = theVert->particles_out();
854 for (const auto& thePart: outgoing) {
855 if (!thePart) continue;
856 finalStatePart.push_back(thePart);
857 if (isStable(thePart)) continue;
858 V pVert = findSimulatedEndVertex(thePart);
859 if (pVert == theVert) break; // to prevent Sherpa loop
860 if (pVert != nullptr) {
861 auto vecPart = findFinalStateParticles<V>(pVert);
862 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
863 }
864 }
865 return finalStatePart;
866 }
867
868}
869#endif

◆ isRMeson() [3/3]

template<class T>
bool MC::isRMeson ( const T & p)
inline

Definition at line 575 of file HepMCHelpers.h.

596{
597inline
598auto particles_in (const HepMC::GenVertex* p) {
599 return std::ranges::subrange (p->particles_in_const_begin(),
600 p->particles_in_const_end());
601}
602}
603#endif
604
605namespace MC
606{
607 template <class VTX>
608 auto particles_in (const VTX* p) { return p->particles_in(); }
609 template <class VTX>
610 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
611
612 namespace Pythia8
613 {
615 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
616
617 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
618
619 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
620 }
621
622#include "AtlasPID.h"
623
625 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
626
628 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
629
631 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
632
634 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
635
637 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
638
640 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
641
643 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
644
646 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
647
649 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
650
652 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
653
657 template <class T> inline bool isStableOrSimDecayed(const T& p) {
658 const auto vertex = p->end_vertex();
659 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
660 }
661
663 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
664
666 template <class T> inline bool isSpecialNonInteracting(const T& p) {
667 const int apid = std::abs(p->pdg_id());
668 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
669 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
670 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
671 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
672 return false;
673 }
674
676
677 template <class T> T findMother(T thePart) {
678 auto partOriVert = thePart->production_vertex();
679 if (!partOriVert) return nullptr;
680
681 long partPDG = thePart->pdg_id();
682 long MotherPDG(0);
683
684 auto MothOriVert = partOriVert;
685 MothOriVert = nullptr;
686 T theMoth(nullptr);
687
688 size_t itr = 0;
689 do {
690 if (itr != 0) partOriVert = MothOriVert;
691 for ( const auto& p : particles_in(partOriVert) ) {
692 theMoth = p;
693 if (!theMoth) continue;
694 MotherPDG = theMoth->pdg_id();
695 MothOriVert = theMoth->production_vertex();
696 if (MotherPDG == partPDG) break;
697 }
698 itr++;
699 if (itr > 100) {
700 break;
701 }
702 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
703 MothOriVert != partOriVert);
704 return theMoth;
705 }
706
708
709 template <class C, class T> T findMatching(C TruthContainer, T p) {
710 T ptrPart = nullptr;
711 if (!p) return ptrPart;
712 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
713 for (T truthParticle : *TruthContainer) {
714 if (HepMC::is_sim_descendant(p,truthParticle)) {
715 ptrPart = truthParticle;
716 break;
717 }
718 }
719 }
720 else {
721 for (T truthParticle : TruthContainer) {
722 if (HepMC::is_sim_descendant(p,truthParticle)) {
723 ptrPart = truthParticle;
724 break;
725 }
726 }
727 }
728 return ptrPart;
729 }
731
732 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
733 auto prodVtx = thePart->production_vertex();
734 if (!prodVtx) return;
735 for (const auto& theMother: prodVtx->particles_in()) {
736 if (!theMother) continue;
737 allancestors.insert(theMother);
738 findParticleAncestors(theMother, allancestors);
739 }
740 }
741
743
744 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
745 auto endVtx = thePart->end_vertex();
746 if (!endVtx) return;
747 for (const auto& theDaughter: endVtx->particles_out()) {
748 if (!theDaughter) continue;
749 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
750 allstabledescendants.insert(theDaughter);
751 }
752 findParticleStableDescendants(theDaughter, allstabledescendants);
753 }
754 }
755
759
760 template <class T> bool isHardScatteringVertex(T pVert) {
761 if (pVert == nullptr) return false;
762 T pV = pVert;
763 int numOfPartIn(0);
764 int pdg(0);
765
766 do {
767 pVert = pV;
768 auto incoming = pVert->particles_in();
769 numOfPartIn = incoming.size();
770 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
771 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
772
773 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
774
775 if (numOfPartIn == 2) {
776 auto incoming = pVert->particles_in();
777 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
778 }
779 return false;
780}
781
785
786 template <class T, class U>
787 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
788 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
789 auto vtx = p->production_vertex();
790 if (!vtx) return false;
791 bool fromHad = false;
792 for ( const auto& parent : particles_in(vtx) ) {
793 if (!parent) continue;
794 // should this really go into parton-level territory?
795 // probably depends where BSM particles are being decayed
796 fromBSM |= isBSM(parent);
797 if (!isPhysical(parent)) return false;
798 fromTau |= isTau(parent);
799 if (isHadron(parent)&&!isBeam(parent)) {
800 if (!hadron) hadron = parent; // assumes linear hadron parentage
801 return true;
802 }
803 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
804 }
805 return fromHad;
806 }
807
810
811 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
812 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
813 decltype(thePart->end_vertex()) pVert(nullptr);
814 if (EndVert != nullptr) {
815 do {
816 bool samePart = false;
817 pVert = nullptr;
818 auto outgoing = EndVert->particles_out();
819 auto incoming = EndVert->particles_in();
820 for (const auto& itrDaug: outgoing) {
821 if (!itrDaug) continue;
822 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
823 // brem on generator level for tau
824 (outgoing.size() == 1 && incoming.size() == 1 &&
826 itrDaug->pdg_id() == thePart->pdg_id()) {
827 samePart = true;
828 pVert = itrDaug->end_vertex();
829 }
830 }
831 if (samePart) EndVert = pVert;
832 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
833 }
834 return EndVert;
835 }
836
838
839 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
840 if (!theVert) return {};
841 decltype(theVert->particles_out()) finalStatePart;
842 auto outgoing = theVert->particles_out();
843 for (const auto& thePart: outgoing) {
844 if (!thePart) continue;
845 finalStatePart.push_back(thePart);
846 if (isStable(thePart)) continue;
847 V pVert = findSimulatedEndVertex(thePart);
848 if (pVert == theVert) break; // to prevent Sherpa loop
849 if (pVert != nullptr) {
850 auto vecPart = findFinalStateParticles<V>(pVert);
851 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
852 }
853 }
854 return finalStatePart;
855 }
856
857}
858#endif

◆ isSimInteracting()

template<class T>
bool MC::isSimInteracting ( const T & p)
inline

Identify if the particle could interact with the detector during the simulation, e.g. not a neutrino or WIMP.

Definition at line 78 of file HepMCHelpers.h.

78{ return isGenStable<T>(p) && isInteracting<T>(p);}

◆ isSimStable()

template<class T>
bool MC::isSimStable ( const T & p)
inline

Identify if the particle is considered stable at the post-detector-sim stage.

Definition at line 75 of file HepMCHelpers.h.

75{ return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}

◆ isSlepton() [1/3]

template<>
bool MC::isSlepton ( const DecodedPID & p)
inline

Definition at line 484 of file HepMCHelpers.h.

505{
506inline
507auto particles_in (const HepMC::GenVertex* p) {
508 return std::ranges::subrange (p->particles_in_const_begin(),
509 p->particles_in_const_end());
510}
511}
512#endif
513
514namespace MC
515{
516 template <class VTX>
517 auto particles_in (const VTX* p) { return p->particles_in(); }
518 template <class VTX>
519 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
520
521 namespace Pythia8
522 {
524 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
525
526 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
527
528 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
529 }
530
531#include "AtlasPID.h"
532
534 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
535
537 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
538
540 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
541
543 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
544
546 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
547
549 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
550
552 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
553
555 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
556
558 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
559
561 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
562
566 template <class T> inline bool isStableOrSimDecayed(const T& p) {
567 const auto vertex = p->end_vertex();
568 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
569 }
570
572 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
573
575 template <class T> inline bool isSpecialNonInteracting(const T& p) {
576 const int apid = std::abs(p->pdg_id());
577 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
578 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
579 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
580 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
581 return false;
582 }
583
585
586 template <class T> T findMother(T thePart) {
587 auto partOriVert = thePart->production_vertex();
588 if (!partOriVert) return nullptr;
589
590 long partPDG = thePart->pdg_id();
591 long MotherPDG(0);
592
593 auto MothOriVert = partOriVert;
594 MothOriVert = nullptr;
595 T theMoth(nullptr);
596
597 size_t itr = 0;
598 do {
599 if (itr != 0) partOriVert = MothOriVert;
600 for ( const auto& p : particles_in(partOriVert) ) {
601 theMoth = p;
602 if (!theMoth) continue;
603 MotherPDG = theMoth->pdg_id();
604 MothOriVert = theMoth->production_vertex();
605 if (MotherPDG == partPDG) break;
606 }
607 itr++;
608 if (itr > 100) {
609 break;
610 }
611 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
612 MothOriVert != partOriVert);
613 return theMoth;
614 }
615
617
618 template <class C, class T> T findMatching(C TruthContainer, T p) {
619 T ptrPart = nullptr;
620 if (!p) return ptrPart;
621 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
622 for (T truthParticle : *TruthContainer) {
623 if (HepMC::is_sim_descendant(p,truthParticle)) {
624 ptrPart = truthParticle;
625 break;
626 }
627 }
628 }
629 else {
630 for (T truthParticle : TruthContainer) {
631 if (HepMC::is_sim_descendant(p,truthParticle)) {
632 ptrPart = truthParticle;
633 break;
634 }
635 }
636 }
637 return ptrPart;
638 }
640
641 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
642 auto prodVtx = thePart->production_vertex();
643 if (!prodVtx) return;
644 for (const auto& theMother: prodVtx->particles_in()) {
645 if (!theMother) continue;
646 allancestors.insert(theMother);
647 findParticleAncestors(theMother, allancestors);
648 }
649 }
650
652
653 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
654 auto endVtx = thePart->end_vertex();
655 if (!endVtx) return;
656 for (const auto& theDaughter: endVtx->particles_out()) {
657 if (!theDaughter) continue;
658 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
659 allstabledescendants.insert(theDaughter);
660 }
661 findParticleStableDescendants(theDaughter, allstabledescendants);
662 }
663 }
664
668
669 template <class T> bool isHardScatteringVertex(T pVert) {
670 if (pVert == nullptr) return false;
671 T pV = pVert;
672 int numOfPartIn(0);
673 int pdg(0);
674
675 do {
676 pVert = pV;
677 auto incoming = pVert->particles_in();
678 numOfPartIn = incoming.size();
679 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
680 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
681
682 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
683
684 if (numOfPartIn == 2) {
685 auto incoming = pVert->particles_in();
686 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
687 }
688 return false;
689}
690
694
695 template <class T, class U>
696 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
697 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
698 auto vtx = p->production_vertex();
699 if (!vtx) return false;
700 bool fromHad = false;
701 for ( const auto& parent : particles_in(vtx) ) {
702 if (!parent) continue;
703 // should this really go into parton-level territory?
704 // probably depends where BSM particles are being decayed
705 fromBSM |= isBSM(parent);
706 if (!isPhysical(parent)) return false;
707 fromTau |= isTau(parent);
708 if (isHadron(parent)&&!isBeam(parent)) {
709 if (!hadron) hadron = parent; // assumes linear hadron parentage
710 return true;
711 }
712 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
713 }
714 return fromHad;
715 }
716
719
720 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
721 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
722 decltype(thePart->end_vertex()) pVert(nullptr);
723 if (EndVert != nullptr) {
724 do {
725 bool samePart = false;
726 pVert = nullptr;
727 auto outgoing = EndVert->particles_out();
728 auto incoming = EndVert->particles_in();
729 for (const auto& itrDaug: outgoing) {
730 if (!itrDaug) continue;
731 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
732 // brem on generator level for tau
733 (outgoing.size() == 1 && incoming.size() == 1 &&
735 itrDaug->pdg_id() == thePart->pdg_id()) {
736 samePart = true;
737 pVert = itrDaug->end_vertex();
738 }
739 }
740 if (samePart) EndVert = pVert;
741 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
742 }
743 return EndVert;
744 }
745
747
748 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
749 if (!theVert) return {};
750 decltype(theVert->particles_out()) finalStatePart;
751 auto outgoing = theVert->particles_out();
752 for (const auto& thePart: outgoing) {
753 if (!thePart) continue;
754 finalStatePart.push_back(thePart);
755 if (isStable(thePart)) continue;
756 V pVert = findSimulatedEndVertex(thePart);
757 if (pVert == theVert) break; // to prevent Sherpa loop
758 if (pVert != nullptr) {
759 auto vecPart = findFinalStateParticles<V>(pVert);
760 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
761 }
762 }
763 return finalStatePart;
764 }
765
766}
767#endif

◆ isSlepton() [2/3]

template<>
bool MC::isSlepton ( const int & p)
inline

Definition at line 485 of file HepMCHelpers.h.

506{
507inline
508auto particles_in (const HepMC::GenVertex* p) {
509 return std::ranges::subrange (p->particles_in_const_begin(),
510 p->particles_in_const_end());
511}
512}
513#endif
514
515namespace MC
516{
517 template <class VTX>
518 auto particles_in (const VTX* p) { return p->particles_in(); }
519 template <class VTX>
520 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
521
522 namespace Pythia8
523 {
525 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
526
527 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
528
529 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
530 }
531
532#include "AtlasPID.h"
533
535 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
536
538 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
539
541 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
542
544 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
545
547 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
548
550 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
551
553 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
554
556 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
557
559 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
560
562 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
563
567 template <class T> inline bool isStableOrSimDecayed(const T& p) {
568 const auto vertex = p->end_vertex();
569 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
570 }
571
573 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
574
576 template <class T> inline bool isSpecialNonInteracting(const T& p) {
577 const int apid = std::abs(p->pdg_id());
578 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
579 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
580 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
581 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
582 return false;
583 }
584
586
587 template <class T> T findMother(T thePart) {
588 auto partOriVert = thePart->production_vertex();
589 if (!partOriVert) return nullptr;
590
591 long partPDG = thePart->pdg_id();
592 long MotherPDG(0);
593
594 auto MothOriVert = partOriVert;
595 MothOriVert = nullptr;
596 T theMoth(nullptr);
597
598 size_t itr = 0;
599 do {
600 if (itr != 0) partOriVert = MothOriVert;
601 for ( const auto& p : particles_in(partOriVert) ) {
602 theMoth = p;
603 if (!theMoth) continue;
604 MotherPDG = theMoth->pdg_id();
605 MothOriVert = theMoth->production_vertex();
606 if (MotherPDG == partPDG) break;
607 }
608 itr++;
609 if (itr > 100) {
610 break;
611 }
612 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
613 MothOriVert != partOriVert);
614 return theMoth;
615 }
616
618
619 template <class C, class T> T findMatching(C TruthContainer, T p) {
620 T ptrPart = nullptr;
621 if (!p) return ptrPart;
622 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
623 for (T truthParticle : *TruthContainer) {
624 if (HepMC::is_sim_descendant(p,truthParticle)) {
625 ptrPart = truthParticle;
626 break;
627 }
628 }
629 }
630 else {
631 for (T truthParticle : TruthContainer) {
632 if (HepMC::is_sim_descendant(p,truthParticle)) {
633 ptrPart = truthParticle;
634 break;
635 }
636 }
637 }
638 return ptrPart;
639 }
641
642 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
643 auto prodVtx = thePart->production_vertex();
644 if (!prodVtx) return;
645 for (const auto& theMother: prodVtx->particles_in()) {
646 if (!theMother) continue;
647 allancestors.insert(theMother);
648 findParticleAncestors(theMother, allancestors);
649 }
650 }
651
653
654 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
655 auto endVtx = thePart->end_vertex();
656 if (!endVtx) return;
657 for (const auto& theDaughter: endVtx->particles_out()) {
658 if (!theDaughter) continue;
659 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
660 allstabledescendants.insert(theDaughter);
661 }
662 findParticleStableDescendants(theDaughter, allstabledescendants);
663 }
664 }
665
669
670 template <class T> bool isHardScatteringVertex(T pVert) {
671 if (pVert == nullptr) return false;
672 T pV = pVert;
673 int numOfPartIn(0);
674 int pdg(0);
675
676 do {
677 pVert = pV;
678 auto incoming = pVert->particles_in();
679 numOfPartIn = incoming.size();
680 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
681 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
682
683 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
684
685 if (numOfPartIn == 2) {
686 auto incoming = pVert->particles_in();
687 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
688 }
689 return false;
690}
691
695
696 template <class T, class U>
697 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
698 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
699 auto vtx = p->production_vertex();
700 if (!vtx) return false;
701 bool fromHad = false;
702 for ( const auto& parent : particles_in(vtx) ) {
703 if (!parent) continue;
704 // should this really go into parton-level territory?
705 // probably depends where BSM particles are being decayed
706 fromBSM |= isBSM(parent);
707 if (!isPhysical(parent)) return false;
708 fromTau |= isTau(parent);
709 if (isHadron(parent)&&!isBeam(parent)) {
710 if (!hadron) hadron = parent; // assumes linear hadron parentage
711 return true;
712 }
713 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
714 }
715 return fromHad;
716 }
717
720
721 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
722 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
723 decltype(thePart->end_vertex()) pVert(nullptr);
724 if (EndVert != nullptr) {
725 do {
726 bool samePart = false;
727 pVert = nullptr;
728 auto outgoing = EndVert->particles_out();
729 auto incoming = EndVert->particles_in();
730 for (const auto& itrDaug: outgoing) {
731 if (!itrDaug) continue;
732 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
733 // brem on generator level for tau
734 (outgoing.size() == 1 && incoming.size() == 1 &&
736 itrDaug->pdg_id() == thePart->pdg_id()) {
737 samePart = true;
738 pVert = itrDaug->end_vertex();
739 }
740 }
741 if (samePart) EndVert = pVert;
742 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
743 }
744 return EndVert;
745 }
746
748
749 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
750 if (!theVert) return {};
751 decltype(theVert->particles_out()) finalStatePart;
752 auto outgoing = theVert->particles_out();
753 for (const auto& thePart: outgoing) {
754 if (!thePart) continue;
755 finalStatePart.push_back(thePart);
756 if (isStable(thePart)) continue;
757 V pVert = findSimulatedEndVertex(thePart);
758 if (pVert == theVert) break; // to prevent Sherpa loop
759 if (pVert != nullptr) {
760 auto vecPart = findFinalStateParticles<V>(pVert);
761 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
762 }
763 }
764 return finalStatePart;
765 }
766
767}
768#endif

◆ isSlepton() [3/3]

template<class T>
bool MC::isSlepton ( const T & p)
inline

Definition at line 483 of file HepMCHelpers.h.

504{
505inline
506auto particles_in (const HepMC::GenVertex* p) {
507 return std::ranges::subrange (p->particles_in_const_begin(),
508 p->particles_in_const_end());
509}
510}
511#endif
512
513namespace MC
514{
515 template <class VTX>
516 auto particles_in (const VTX* p) { return p->particles_in(); }
517 template <class VTX>
518 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
519
520 namespace Pythia8
521 {
523 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
524
525 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
526
527 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
528 }
529
530#include "AtlasPID.h"
531
533 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
534
536 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
537
539 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
540
542 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
543
545 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
546
548 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
549
551 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
552
554 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
555
557 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
558
560 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
561
565 template <class T> inline bool isStableOrSimDecayed(const T& p) {
566 const auto vertex = p->end_vertex();
567 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
568 }
569
571 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
572
574 template <class T> inline bool isSpecialNonInteracting(const T& p) {
575 const int apid = std::abs(p->pdg_id());
576 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
577 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
578 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
579 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
580 return false;
581 }
582
584
585 template <class T> T findMother(T thePart) {
586 auto partOriVert = thePart->production_vertex();
587 if (!partOriVert) return nullptr;
588
589 long partPDG = thePart->pdg_id();
590 long MotherPDG(0);
591
592 auto MothOriVert = partOriVert;
593 MothOriVert = nullptr;
594 T theMoth(nullptr);
595
596 size_t itr = 0;
597 do {
598 if (itr != 0) partOriVert = MothOriVert;
599 for ( const auto& p : particles_in(partOriVert) ) {
600 theMoth = p;
601 if (!theMoth) continue;
602 MotherPDG = theMoth->pdg_id();
603 MothOriVert = theMoth->production_vertex();
604 if (MotherPDG == partPDG) break;
605 }
606 itr++;
607 if (itr > 100) {
608 break;
609 }
610 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
611 MothOriVert != partOriVert);
612 return theMoth;
613 }
614
616
617 template <class C, class T> T findMatching(C TruthContainer, T p) {
618 T ptrPart = nullptr;
619 if (!p) return ptrPart;
620 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
621 for (T truthParticle : *TruthContainer) {
622 if (HepMC::is_sim_descendant(p,truthParticle)) {
623 ptrPart = truthParticle;
624 break;
625 }
626 }
627 }
628 else {
629 for (T truthParticle : TruthContainer) {
630 if (HepMC::is_sim_descendant(p,truthParticle)) {
631 ptrPart = truthParticle;
632 break;
633 }
634 }
635 }
636 return ptrPart;
637 }
639
640 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
641 auto prodVtx = thePart->production_vertex();
642 if (!prodVtx) return;
643 for (const auto& theMother: prodVtx->particles_in()) {
644 if (!theMother) continue;
645 allancestors.insert(theMother);
646 findParticleAncestors(theMother, allancestors);
647 }
648 }
649
651
652 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
653 auto endVtx = thePart->end_vertex();
654 if (!endVtx) return;
655 for (const auto& theDaughter: endVtx->particles_out()) {
656 if (!theDaughter) continue;
657 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
658 allstabledescendants.insert(theDaughter);
659 }
660 findParticleStableDescendants(theDaughter, allstabledescendants);
661 }
662 }
663
667
668 template <class T> bool isHardScatteringVertex(T pVert) {
669 if (pVert == nullptr) return false;
670 T pV = pVert;
671 int numOfPartIn(0);
672 int pdg(0);
673
674 do {
675 pVert = pV;
676 auto incoming = pVert->particles_in();
677 numOfPartIn = incoming.size();
678 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
679 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
680
681 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
682
683 if (numOfPartIn == 2) {
684 auto incoming = pVert->particles_in();
685 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
686 }
687 return false;
688}
689
693
694 template <class T, class U>
695 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
696 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
697 auto vtx = p->production_vertex();
698 if (!vtx) return false;
699 bool fromHad = false;
700 for ( const auto& parent : particles_in(vtx) ) {
701 if (!parent) continue;
702 // should this really go into parton-level territory?
703 // probably depends where BSM particles are being decayed
704 fromBSM |= isBSM(parent);
705 if (!isPhysical(parent)) return false;
706 fromTau |= isTau(parent);
707 if (isHadron(parent)&&!isBeam(parent)) {
708 if (!hadron) hadron = parent; // assumes linear hadron parentage
709 return true;
710 }
711 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
712 }
713 return fromHad;
714 }
715
718
719 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
720 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
721 decltype(thePart->end_vertex()) pVert(nullptr);
722 if (EndVert != nullptr) {
723 do {
724 bool samePart = false;
725 pVert = nullptr;
726 auto outgoing = EndVert->particles_out();
727 auto incoming = EndVert->particles_in();
728 for (const auto& itrDaug: outgoing) {
729 if (!itrDaug) continue;
730 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
731 // brem on generator level for tau
732 (outgoing.size() == 1 && incoming.size() == 1 &&
734 itrDaug->pdg_id() == thePart->pdg_id()) {
735 samePart = true;
736 pVert = itrDaug->end_vertex();
737 }
738 }
739 if (samePart) EndVert = pVert;
740 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
741 }
742 return EndVert;
743 }
744
746
747 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
748 if (!theVert) return {};
749 decltype(theVert->particles_out()) finalStatePart;
750 auto outgoing = theVert->particles_out();
751 for (const auto& thePart: outgoing) {
752 if (!thePart) continue;
753 finalStatePart.push_back(thePart);
754 if (isStable(thePart)) continue;
755 V pVert = findSimulatedEndVertex(thePart);
756 if (pVert == theVert) break; // to prevent Sherpa loop
757 if (pVert != nullptr) {
758 auto vecPart = findFinalStateParticles<V>(pVert);
759 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
760 }
761 }
762 return finalStatePart;
763 }
764
765}
766#endif

◆ isSleptonLH() [1/3]

template<>
bool MC::isSleptonLH ( const DecodedPID & p)
inline

Definition at line 490 of file HepMCHelpers.h.

511 {
512inline
513auto particles_in (const HepMC::GenVertex* p) {
514 return std::ranges::subrange (p->particles_in_const_begin(),
515 p->particles_in_const_end());
516}
517}
518#endif
519
520namespace MC
521{
522 template <class VTX>
523 auto particles_in (const VTX* p) { return p->particles_in(); }
524 template <class VTX>
525 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
526
527 namespace Pythia8
528 {
530 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
531
532 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
533
534 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
535 }
536
537#include "AtlasPID.h"
538
540 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
541
543 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
544
546 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
547
549 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
550
552 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
553
555 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
556
558 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
559
561 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
562
564 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
565
567 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
568
572 template <class T> inline bool isStableOrSimDecayed(const T& p) {
573 const auto vertex = p->end_vertex();
574 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
575 }
576
578 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
579
581 template <class T> inline bool isSpecialNonInteracting(const T& p) {
582 const int apid = std::abs(p->pdg_id());
583 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
584 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
585 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
586 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
587 return false;
588 }
589
591
592 template <class T> T findMother(T thePart) {
593 auto partOriVert = thePart->production_vertex();
594 if (!partOriVert) return nullptr;
595
596 long partPDG = thePart->pdg_id();
597 long MotherPDG(0);
598
599 auto MothOriVert = partOriVert;
600 MothOriVert = nullptr;
601 T theMoth(nullptr);
602
603 size_t itr = 0;
604 do {
605 if (itr != 0) partOriVert = MothOriVert;
606 for ( const auto& p : particles_in(partOriVert) ) {
607 theMoth = p;
608 if (!theMoth) continue;
609 MotherPDG = theMoth->pdg_id();
610 MothOriVert = theMoth->production_vertex();
611 if (MotherPDG == partPDG) break;
612 }
613 itr++;
614 if (itr > 100) {
615 break;
616 }
617 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
618 MothOriVert != partOriVert);
619 return theMoth;
620 }
621
623
624 template <class C, class T> T findMatching(C TruthContainer, T p) {
625 T ptrPart = nullptr;
626 if (!p) return ptrPart;
627 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
628 for (T truthParticle : *TruthContainer) {
629 if (HepMC::is_sim_descendant(p,truthParticle)) {
630 ptrPart = truthParticle;
631 break;
632 }
633 }
634 }
635 else {
636 for (T truthParticle : TruthContainer) {
637 if (HepMC::is_sim_descendant(p,truthParticle)) {
638 ptrPart = truthParticle;
639 break;
640 }
641 }
642 }
643 return ptrPart;
644 }
646
647 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
648 auto prodVtx = thePart->production_vertex();
649 if (!prodVtx) return;
650 for (const auto& theMother: prodVtx->particles_in()) {
651 if (!theMother) continue;
652 allancestors.insert(theMother);
653 findParticleAncestors(theMother, allancestors);
654 }
655 }
656
658
659 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
660 auto endVtx = thePart->end_vertex();
661 if (!endVtx) return;
662 for (const auto& theDaughter: endVtx->particles_out()) {
663 if (!theDaughter) continue;
664 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
665 allstabledescendants.insert(theDaughter);
666 }
667 findParticleStableDescendants(theDaughter, allstabledescendants);
668 }
669 }
670
674
675 template <class T> bool isHardScatteringVertex(T pVert) {
676 if (pVert == nullptr) return false;
677 T pV = pVert;
678 int numOfPartIn(0);
679 int pdg(0);
680
681 do {
682 pVert = pV;
683 auto incoming = pVert->particles_in();
684 numOfPartIn = incoming.size();
685 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
686 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
687
688 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
689
690 if (numOfPartIn == 2) {
691 auto incoming = pVert->particles_in();
692 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
693 }
694 return false;
695}
696
700
701 template <class T, class U>
702 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
703 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
704 auto vtx = p->production_vertex();
705 if (!vtx) return false;
706 bool fromHad = false;
707 for ( const auto& parent : particles_in(vtx) ) {
708 if (!parent) continue;
709 // should this really go into parton-level territory?
710 // probably depends where BSM particles are being decayed
711 fromBSM |= isBSM(parent);
712 if (!isPhysical(parent)) return false;
713 fromTau |= isTau(parent);
714 if (isHadron(parent)&&!isBeam(parent)) {
715 if (!hadron) hadron = parent; // assumes linear hadron parentage
716 return true;
717 }
718 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
719 }
720 return fromHad;
721 }
722
725
726 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
727 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
728 decltype(thePart->end_vertex()) pVert(nullptr);
729 if (EndVert != nullptr) {
730 do {
731 bool samePart = false;
732 pVert = nullptr;
733 auto outgoing = EndVert->particles_out();
734 auto incoming = EndVert->particles_in();
735 for (const auto& itrDaug: outgoing) {
736 if (!itrDaug) continue;
737 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
738 // brem on generator level for tau
739 (outgoing.size() == 1 && incoming.size() == 1 &&
741 itrDaug->pdg_id() == thePart->pdg_id()) {
742 samePart = true;
743 pVert = itrDaug->end_vertex();
744 }
745 }
746 if (samePart) EndVert = pVert;
747 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
748 }
749 return EndVert;
750 }
751
753
754 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
755 if (!theVert) return {};
756 decltype(theVert->particles_out()) finalStatePart;
757 auto outgoing = theVert->particles_out();
758 for (const auto& thePart: outgoing) {
759 if (!thePart) continue;
760 finalStatePart.push_back(thePart);
761 if (isStable(thePart)) continue;
762 V pVert = findSimulatedEndVertex(thePart);
763 if (pVert == theVert) break; // to prevent Sherpa loop
764 if (pVert != nullptr) {
765 auto vecPart = findFinalStateParticles<V>(pVert);
766 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
767 }
768 }
769 return finalStatePart;
770 }
771
772}
773#endif

◆ isSleptonLH() [2/3]

template<>
bool MC::isSleptonLH ( const int & p)
inline

Definition at line 493 of file HepMCHelpers.h.

514{
515inline
516auto particles_in (const HepMC::GenVertex* p) {
517 return std::ranges::subrange (p->particles_in_const_begin(),
518 p->particles_in_const_end());
519}
520}
521#endif
522
523namespace MC
524{
525 template <class VTX>
526 auto particles_in (const VTX* p) { return p->particles_in(); }
527 template <class VTX>
528 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
529
530 namespace Pythia8
531 {
533 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
534
535 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
536
537 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
538 }
539
540#include "AtlasPID.h"
541
543 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
544
546 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
547
549 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
550
552 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
553
555 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
556
558 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
559
561 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
562
564 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
565
567 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
568
570 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
571
575 template <class T> inline bool isStableOrSimDecayed(const T& p) {
576 const auto vertex = p->end_vertex();
577 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
578 }
579
581 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
582
584 template <class T> inline bool isSpecialNonInteracting(const T& p) {
585 const int apid = std::abs(p->pdg_id());
586 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
587 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
588 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
589 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
590 return false;
591 }
592
594
595 template <class T> T findMother(T thePart) {
596 auto partOriVert = thePart->production_vertex();
597 if (!partOriVert) return nullptr;
598
599 long partPDG = thePart->pdg_id();
600 long MotherPDG(0);
601
602 auto MothOriVert = partOriVert;
603 MothOriVert = nullptr;
604 T theMoth(nullptr);
605
606 size_t itr = 0;
607 do {
608 if (itr != 0) partOriVert = MothOriVert;
609 for ( const auto& p : particles_in(partOriVert) ) {
610 theMoth = p;
611 if (!theMoth) continue;
612 MotherPDG = theMoth->pdg_id();
613 MothOriVert = theMoth->production_vertex();
614 if (MotherPDG == partPDG) break;
615 }
616 itr++;
617 if (itr > 100) {
618 break;
619 }
620 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
621 MothOriVert != partOriVert);
622 return theMoth;
623 }
624
626
627 template <class C, class T> T findMatching(C TruthContainer, T p) {
628 T ptrPart = nullptr;
629 if (!p) return ptrPart;
630 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
631 for (T truthParticle : *TruthContainer) {
632 if (HepMC::is_sim_descendant(p,truthParticle)) {
633 ptrPart = truthParticle;
634 break;
635 }
636 }
637 }
638 else {
639 for (T truthParticle : TruthContainer) {
640 if (HepMC::is_sim_descendant(p,truthParticle)) {
641 ptrPart = truthParticle;
642 break;
643 }
644 }
645 }
646 return ptrPart;
647 }
649
650 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
651 auto prodVtx = thePart->production_vertex();
652 if (!prodVtx) return;
653 for (const auto& theMother: prodVtx->particles_in()) {
654 if (!theMother) continue;
655 allancestors.insert(theMother);
656 findParticleAncestors(theMother, allancestors);
657 }
658 }
659
661
662 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
663 auto endVtx = thePart->end_vertex();
664 if (!endVtx) return;
665 for (const auto& theDaughter: endVtx->particles_out()) {
666 if (!theDaughter) continue;
667 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
668 allstabledescendants.insert(theDaughter);
669 }
670 findParticleStableDescendants(theDaughter, allstabledescendants);
671 }
672 }
673
677
678 template <class T> bool isHardScatteringVertex(T pVert) {
679 if (pVert == nullptr) return false;
680 T pV = pVert;
681 int numOfPartIn(0);
682 int pdg(0);
683
684 do {
685 pVert = pV;
686 auto incoming = pVert->particles_in();
687 numOfPartIn = incoming.size();
688 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
689 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
690
691 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
692
693 if (numOfPartIn == 2) {
694 auto incoming = pVert->particles_in();
695 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
696 }
697 return false;
698}
699
703
704 template <class T, class U>
705 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
706 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
707 auto vtx = p->production_vertex();
708 if (!vtx) return false;
709 bool fromHad = false;
710 for ( const auto& parent : particles_in(vtx) ) {
711 if (!parent) continue;
712 // should this really go into parton-level territory?
713 // probably depends where BSM particles are being decayed
714 fromBSM |= isBSM(parent);
715 if (!isPhysical(parent)) return false;
716 fromTau |= isTau(parent);
717 if (isHadron(parent)&&!isBeam(parent)) {
718 if (!hadron) hadron = parent; // assumes linear hadron parentage
719 return true;
720 }
721 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
722 }
723 return fromHad;
724 }
725
728
729 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
730 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
731 decltype(thePart->end_vertex()) pVert(nullptr);
732 if (EndVert != nullptr) {
733 do {
734 bool samePart = false;
735 pVert = nullptr;
736 auto outgoing = EndVert->particles_out();
737 auto incoming = EndVert->particles_in();
738 for (const auto& itrDaug: outgoing) {
739 if (!itrDaug) continue;
740 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
741 // brem on generator level for tau
742 (outgoing.size() == 1 && incoming.size() == 1 &&
744 itrDaug->pdg_id() == thePart->pdg_id()) {
745 samePart = true;
746 pVert = itrDaug->end_vertex();
747 }
748 }
749 if (samePart) EndVert = pVert;
750 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
751 }
752 return EndVert;
753 }
754
756
757 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
758 if (!theVert) return {};
759 decltype(theVert->particles_out()) finalStatePart;
760 auto outgoing = theVert->particles_out();
761 for (const auto& thePart: outgoing) {
762 if (!thePart) continue;
763 finalStatePart.push_back(thePart);
764 if (isStable(thePart)) continue;
765 V pVert = findSimulatedEndVertex(thePart);
766 if (pVert == theVert) break; // to prevent Sherpa loop
767 if (pVert != nullptr) {
768 auto vecPart = findFinalStateParticles<V>(pVert);
769 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
770 }
771 }
772 return finalStatePart;
773 }
774
775}
776#endif

◆ isSleptonLH() [3/3]

template<class T>
bool MC::isSleptonLH ( const T & p)
inline

Definition at line 489 of file HepMCHelpers.h.

510{
511inline
512auto particles_in (const HepMC::GenVertex* p) {
513 return std::ranges::subrange (p->particles_in_const_begin(),
514 p->particles_in_const_end());
515}
516}
517#endif
518
519namespace MC
520{
521 template <class VTX>
522 auto particles_in (const VTX* p) { return p->particles_in(); }
523 template <class VTX>
524 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
525
526 namespace Pythia8
527 {
529 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
530
531 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
532
533 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
534 }
535
536#include "AtlasPID.h"
537
539 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
540
542 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
543
545 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
546
548 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
549
551 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
552
554 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
555
557 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
558
560 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
561
563 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
564
566 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
567
571 template <class T> inline bool isStableOrSimDecayed(const T& p) {
572 const auto vertex = p->end_vertex();
573 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
574 }
575
577 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
578
580 template <class T> inline bool isSpecialNonInteracting(const T& p) {
581 const int apid = std::abs(p->pdg_id());
582 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
583 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
584 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
585 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
586 return false;
587 }
588
590
591 template <class T> T findMother(T thePart) {
592 auto partOriVert = thePart->production_vertex();
593 if (!partOriVert) return nullptr;
594
595 long partPDG = thePart->pdg_id();
596 long MotherPDG(0);
597
598 auto MothOriVert = partOriVert;
599 MothOriVert = nullptr;
600 T theMoth(nullptr);
601
602 size_t itr = 0;
603 do {
604 if (itr != 0) partOriVert = MothOriVert;
605 for ( const auto& p : particles_in(partOriVert) ) {
606 theMoth = p;
607 if (!theMoth) continue;
608 MotherPDG = theMoth->pdg_id();
609 MothOriVert = theMoth->production_vertex();
610 if (MotherPDG == partPDG) break;
611 }
612 itr++;
613 if (itr > 100) {
614 break;
615 }
616 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
617 MothOriVert != partOriVert);
618 return theMoth;
619 }
620
622
623 template <class C, class T> T findMatching(C TruthContainer, T p) {
624 T ptrPart = nullptr;
625 if (!p) return ptrPart;
626 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
627 for (T truthParticle : *TruthContainer) {
628 if (HepMC::is_sim_descendant(p,truthParticle)) {
629 ptrPart = truthParticle;
630 break;
631 }
632 }
633 }
634 else {
635 for (T truthParticle : TruthContainer) {
636 if (HepMC::is_sim_descendant(p,truthParticle)) {
637 ptrPart = truthParticle;
638 break;
639 }
640 }
641 }
642 return ptrPart;
643 }
645
646 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
647 auto prodVtx = thePart->production_vertex();
648 if (!prodVtx) return;
649 for (const auto& theMother: prodVtx->particles_in()) {
650 if (!theMother) continue;
651 allancestors.insert(theMother);
652 findParticleAncestors(theMother, allancestors);
653 }
654 }
655
657
658 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
659 auto endVtx = thePart->end_vertex();
660 if (!endVtx) return;
661 for (const auto& theDaughter: endVtx->particles_out()) {
662 if (!theDaughter) continue;
663 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
664 allstabledescendants.insert(theDaughter);
665 }
666 findParticleStableDescendants(theDaughter, allstabledescendants);
667 }
668 }
669
673
674 template <class T> bool isHardScatteringVertex(T pVert) {
675 if (pVert == nullptr) return false;
676 T pV = pVert;
677 int numOfPartIn(0);
678 int pdg(0);
679
680 do {
681 pVert = pV;
682 auto incoming = pVert->particles_in();
683 numOfPartIn = incoming.size();
684 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
685 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
686
687 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
688
689 if (numOfPartIn == 2) {
690 auto incoming = pVert->particles_in();
691 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
692 }
693 return false;
694}
695
699
700 template <class T, class U>
701 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
702 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
703 auto vtx = p->production_vertex();
704 if (!vtx) return false;
705 bool fromHad = false;
706 for ( const auto& parent : particles_in(vtx) ) {
707 if (!parent) continue;
708 // should this really go into parton-level territory?
709 // probably depends where BSM particles are being decayed
710 fromBSM |= isBSM(parent);
711 if (!isPhysical(parent)) return false;
712 fromTau |= isTau(parent);
713 if (isHadron(parent)&&!isBeam(parent)) {
714 if (!hadron) hadron = parent; // assumes linear hadron parentage
715 return true;
716 }
717 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
718 }
719 return fromHad;
720 }
721
724
725 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
726 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
727 decltype(thePart->end_vertex()) pVert(nullptr);
728 if (EndVert != nullptr) {
729 do {
730 bool samePart = false;
731 pVert = nullptr;
732 auto outgoing = EndVert->particles_out();
733 auto incoming = EndVert->particles_in();
734 for (const auto& itrDaug: outgoing) {
735 if (!itrDaug) continue;
736 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
737 // brem on generator level for tau
738 (outgoing.size() == 1 && incoming.size() == 1 &&
740 itrDaug->pdg_id() == thePart->pdg_id()) {
741 samePart = true;
742 pVert = itrDaug->end_vertex();
743 }
744 }
745 if (samePart) EndVert = pVert;
746 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
747 }
748 return EndVert;
749 }
750
752
753 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
754 if (!theVert) return {};
755 decltype(theVert->particles_out()) finalStatePart;
756 auto outgoing = theVert->particles_out();
757 for (const auto& thePart: outgoing) {
758 if (!thePart) continue;
759 finalStatePart.push_back(thePart);
760 if (isStable(thePart)) continue;
761 V pVert = findSimulatedEndVertex(thePart);
762 if (pVert == theVert) break; // to prevent Sherpa loop
763 if (pVert != nullptr) {
764 auto vecPart = findFinalStateParticles<V>(pVert);
765 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
766 }
767 }
768 return finalStatePart;
769 }
770
771}
772#endif

◆ isSleptonRH() [1/3]

template<>
bool MC::isSleptonRH ( const DecodedPID & p)
inline

Definition at line 498 of file HepMCHelpers.h.

519 {
520inline
521auto particles_in (const HepMC::GenVertex* p) {
522 return std::ranges::subrange (p->particles_in_const_begin(),
523 p->particles_in_const_end());
524}
525}
526#endif
527
528namespace MC
529{
530 template <class VTX>
531 auto particles_in (const VTX* p) { return p->particles_in(); }
532 template <class VTX>
533 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
534
535 namespace Pythia8
536 {
538 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
539
540 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
541
542 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
543 }
544
545#include "AtlasPID.h"
546
548 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
549
551 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
552
554 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
555
557 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
558
560 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
561
563 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
564
566 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
567
569 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
570
572 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
573
575 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
576
580 template <class T> inline bool isStableOrSimDecayed(const T& p) {
581 const auto vertex = p->end_vertex();
582 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
583 }
584
586 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
587
589 template <class T> inline bool isSpecialNonInteracting(const T& p) {
590 const int apid = std::abs(p->pdg_id());
591 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
592 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
593 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
594 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
595 return false;
596 }
597
599
600 template <class T> T findMother(T thePart) {
601 auto partOriVert = thePart->production_vertex();
602 if (!partOriVert) return nullptr;
603
604 long partPDG = thePart->pdg_id();
605 long MotherPDG(0);
606
607 auto MothOriVert = partOriVert;
608 MothOriVert = nullptr;
609 T theMoth(nullptr);
610
611 size_t itr = 0;
612 do {
613 if (itr != 0) partOriVert = MothOriVert;
614 for ( const auto& p : particles_in(partOriVert) ) {
615 theMoth = p;
616 if (!theMoth) continue;
617 MotherPDG = theMoth->pdg_id();
618 MothOriVert = theMoth->production_vertex();
619 if (MotherPDG == partPDG) break;
620 }
621 itr++;
622 if (itr > 100) {
623 break;
624 }
625 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
626 MothOriVert != partOriVert);
627 return theMoth;
628 }
629
631
632 template <class C, class T> T findMatching(C TruthContainer, T p) {
633 T ptrPart = nullptr;
634 if (!p) return ptrPart;
635 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
636 for (T truthParticle : *TruthContainer) {
637 if (HepMC::is_sim_descendant(p,truthParticle)) {
638 ptrPart = truthParticle;
639 break;
640 }
641 }
642 }
643 else {
644 for (T truthParticle : TruthContainer) {
645 if (HepMC::is_sim_descendant(p,truthParticle)) {
646 ptrPart = truthParticle;
647 break;
648 }
649 }
650 }
651 return ptrPart;
652 }
654
655 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
656 auto prodVtx = thePart->production_vertex();
657 if (!prodVtx) return;
658 for (const auto& theMother: prodVtx->particles_in()) {
659 if (!theMother) continue;
660 allancestors.insert(theMother);
661 findParticleAncestors(theMother, allancestors);
662 }
663 }
664
666
667 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
668 auto endVtx = thePart->end_vertex();
669 if (!endVtx) return;
670 for (const auto& theDaughter: endVtx->particles_out()) {
671 if (!theDaughter) continue;
672 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
673 allstabledescendants.insert(theDaughter);
674 }
675 findParticleStableDescendants(theDaughter, allstabledescendants);
676 }
677 }
678
682
683 template <class T> bool isHardScatteringVertex(T pVert) {
684 if (pVert == nullptr) return false;
685 T pV = pVert;
686 int numOfPartIn(0);
687 int pdg(0);
688
689 do {
690 pVert = pV;
691 auto incoming = pVert->particles_in();
692 numOfPartIn = incoming.size();
693 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
694 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
695
696 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
697
698 if (numOfPartIn == 2) {
699 auto incoming = pVert->particles_in();
700 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
701 }
702 return false;
703}
704
708
709 template <class T, class U>
710 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
711 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
712 auto vtx = p->production_vertex();
713 if (!vtx) return false;
714 bool fromHad = false;
715 for ( const auto& parent : particles_in(vtx) ) {
716 if (!parent) continue;
717 // should this really go into parton-level territory?
718 // probably depends where BSM particles are being decayed
719 fromBSM |= isBSM(parent);
720 if (!isPhysical(parent)) return false;
721 fromTau |= isTau(parent);
722 if (isHadron(parent)&&!isBeam(parent)) {
723 if (!hadron) hadron = parent; // assumes linear hadron parentage
724 return true;
725 }
726 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
727 }
728 return fromHad;
729 }
730
733
734 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
735 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
736 decltype(thePart->end_vertex()) pVert(nullptr);
737 if (EndVert != nullptr) {
738 do {
739 bool samePart = false;
740 pVert = nullptr;
741 auto outgoing = EndVert->particles_out();
742 auto incoming = EndVert->particles_in();
743 for (const auto& itrDaug: outgoing) {
744 if (!itrDaug) continue;
745 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
746 // brem on generator level for tau
747 (outgoing.size() == 1 && incoming.size() == 1 &&
749 itrDaug->pdg_id() == thePart->pdg_id()) {
750 samePart = true;
751 pVert = itrDaug->end_vertex();
752 }
753 }
754 if (samePart) EndVert = pVert;
755 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
756 }
757 return EndVert;
758 }
759
761
762 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
763 if (!theVert) return {};
764 decltype(theVert->particles_out()) finalStatePart;
765 auto outgoing = theVert->particles_out();
766 for (const auto& thePart: outgoing) {
767 if (!thePart) continue;
768 finalStatePart.push_back(thePart);
769 if (isStable(thePart)) continue;
770 V pVert = findSimulatedEndVertex(thePart);
771 if (pVert == theVert) break; // to prevent Sherpa loop
772 if (pVert != nullptr) {
773 auto vecPart = findFinalStateParticles<V>(pVert);
774 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
775 }
776 }
777 return finalStatePart;
778 }
779
780}
781#endif

◆ isSleptonRH() [2/3]

template<>
bool MC::isSleptonRH ( const int & p)
inline

Definition at line 501 of file HepMCHelpers.h.

522{
523inline
524auto particles_in (const HepMC::GenVertex* p) {
525 return std::ranges::subrange (p->particles_in_const_begin(),
526 p->particles_in_const_end());
527}
528}
529#endif
530
531namespace MC
532{
533 template <class VTX>
534 auto particles_in (const VTX* p) { return p->particles_in(); }
535 template <class VTX>
536 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
537
538 namespace Pythia8
539 {
541 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
542
543 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
544
545 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
546 }
547
548#include "AtlasPID.h"
549
551 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
552
554 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
555
557 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
558
560 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
561
563 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
564
566 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
567
569 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
570
572 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
573
575 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
576
578 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
579
583 template <class T> inline bool isStableOrSimDecayed(const T& p) {
584 const auto vertex = p->end_vertex();
585 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
586 }
587
589 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
590
592 template <class T> inline bool isSpecialNonInteracting(const T& p) {
593 const int apid = std::abs(p->pdg_id());
594 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
595 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
596 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
597 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
598 return false;
599 }
600
602
603 template <class T> T findMother(T thePart) {
604 auto partOriVert = thePart->production_vertex();
605 if (!partOriVert) return nullptr;
606
607 long partPDG = thePart->pdg_id();
608 long MotherPDG(0);
609
610 auto MothOriVert = partOriVert;
611 MothOriVert = nullptr;
612 T theMoth(nullptr);
613
614 size_t itr = 0;
615 do {
616 if (itr != 0) partOriVert = MothOriVert;
617 for ( const auto& p : particles_in(partOriVert) ) {
618 theMoth = p;
619 if (!theMoth) continue;
620 MotherPDG = theMoth->pdg_id();
621 MothOriVert = theMoth->production_vertex();
622 if (MotherPDG == partPDG) break;
623 }
624 itr++;
625 if (itr > 100) {
626 break;
627 }
628 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
629 MothOriVert != partOriVert);
630 return theMoth;
631 }
632
634
635 template <class C, class T> T findMatching(C TruthContainer, T p) {
636 T ptrPart = nullptr;
637 if (!p) return ptrPart;
638 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
639 for (T truthParticle : *TruthContainer) {
640 if (HepMC::is_sim_descendant(p,truthParticle)) {
641 ptrPart = truthParticle;
642 break;
643 }
644 }
645 }
646 else {
647 for (T truthParticle : TruthContainer) {
648 if (HepMC::is_sim_descendant(p,truthParticle)) {
649 ptrPart = truthParticle;
650 break;
651 }
652 }
653 }
654 return ptrPart;
655 }
657
658 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
659 auto prodVtx = thePart->production_vertex();
660 if (!prodVtx) return;
661 for (const auto& theMother: prodVtx->particles_in()) {
662 if (!theMother) continue;
663 allancestors.insert(theMother);
664 findParticleAncestors(theMother, allancestors);
665 }
666 }
667
669
670 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
671 auto endVtx = thePart->end_vertex();
672 if (!endVtx) return;
673 for (const auto& theDaughter: endVtx->particles_out()) {
674 if (!theDaughter) continue;
675 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
676 allstabledescendants.insert(theDaughter);
677 }
678 findParticleStableDescendants(theDaughter, allstabledescendants);
679 }
680 }
681
685
686 template <class T> bool isHardScatteringVertex(T pVert) {
687 if (pVert == nullptr) return false;
688 T pV = pVert;
689 int numOfPartIn(0);
690 int pdg(0);
691
692 do {
693 pVert = pV;
694 auto incoming = pVert->particles_in();
695 numOfPartIn = incoming.size();
696 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
697 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
698
699 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
700
701 if (numOfPartIn == 2) {
702 auto incoming = pVert->particles_in();
703 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
704 }
705 return false;
706}
707
711
712 template <class T, class U>
713 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
714 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
715 auto vtx = p->production_vertex();
716 if (!vtx) return false;
717 bool fromHad = false;
718 for ( const auto& parent : particles_in(vtx) ) {
719 if (!parent) continue;
720 // should this really go into parton-level territory?
721 // probably depends where BSM particles are being decayed
722 fromBSM |= isBSM(parent);
723 if (!isPhysical(parent)) return false;
724 fromTau |= isTau(parent);
725 if (isHadron(parent)&&!isBeam(parent)) {
726 if (!hadron) hadron = parent; // assumes linear hadron parentage
727 return true;
728 }
729 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
730 }
731 return fromHad;
732 }
733
736
737 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
738 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
739 decltype(thePart->end_vertex()) pVert(nullptr);
740 if (EndVert != nullptr) {
741 do {
742 bool samePart = false;
743 pVert = nullptr;
744 auto outgoing = EndVert->particles_out();
745 auto incoming = EndVert->particles_in();
746 for (const auto& itrDaug: outgoing) {
747 if (!itrDaug) continue;
748 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
749 // brem on generator level for tau
750 (outgoing.size() == 1 && incoming.size() == 1 &&
752 itrDaug->pdg_id() == thePart->pdg_id()) {
753 samePart = true;
754 pVert = itrDaug->end_vertex();
755 }
756 }
757 if (samePart) EndVert = pVert;
758 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
759 }
760 return EndVert;
761 }
762
764
765 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
766 if (!theVert) return {};
767 decltype(theVert->particles_out()) finalStatePart;
768 auto outgoing = theVert->particles_out();
769 for (const auto& thePart: outgoing) {
770 if (!thePart) continue;
771 finalStatePart.push_back(thePart);
772 if (isStable(thePart)) continue;
773 V pVert = findSimulatedEndVertex(thePart);
774 if (pVert == theVert) break; // to prevent Sherpa loop
775 if (pVert != nullptr) {
776 auto vecPart = findFinalStateParticles<V>(pVert);
777 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
778 }
779 }
780 return finalStatePart;
781 }
782
783}
784#endif

◆ isSleptonRH() [3/3]

template<class T>
bool MC::isSleptonRH ( const T & p)
inline

Definition at line 497 of file HepMCHelpers.h.

518{
519inline
520auto particles_in (const HepMC::GenVertex* p) {
521 return std::ranges::subrange (p->particles_in_const_begin(),
522 p->particles_in_const_end());
523}
524}
525#endif
526
527namespace MC
528{
529 template <class VTX>
530 auto particles_in (const VTX* p) { return p->particles_in(); }
531 template <class VTX>
532 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
533
534 namespace Pythia8
535 {
537 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
538
539 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
540
541 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
542 }
543
544#include "AtlasPID.h"
545
547 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
548
550 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
551
553 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
554
556 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
557
559 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
560
562 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
563
565 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
566
568 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
569
571 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
572
574 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
575
579 template <class T> inline bool isStableOrSimDecayed(const T& p) {
580 const auto vertex = p->end_vertex();
581 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
582 }
583
585 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
586
588 template <class T> inline bool isSpecialNonInteracting(const T& p) {
589 const int apid = std::abs(p->pdg_id());
590 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
591 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
592 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
593 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
594 return false;
595 }
596
598
599 template <class T> T findMother(T thePart) {
600 auto partOriVert = thePart->production_vertex();
601 if (!partOriVert) return nullptr;
602
603 long partPDG = thePart->pdg_id();
604 long MotherPDG(0);
605
606 auto MothOriVert = partOriVert;
607 MothOriVert = nullptr;
608 T theMoth(nullptr);
609
610 size_t itr = 0;
611 do {
612 if (itr != 0) partOriVert = MothOriVert;
613 for ( const auto& p : particles_in(partOriVert) ) {
614 theMoth = p;
615 if (!theMoth) continue;
616 MotherPDG = theMoth->pdg_id();
617 MothOriVert = theMoth->production_vertex();
618 if (MotherPDG == partPDG) break;
619 }
620 itr++;
621 if (itr > 100) {
622 break;
623 }
624 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
625 MothOriVert != partOriVert);
626 return theMoth;
627 }
628
630
631 template <class C, class T> T findMatching(C TruthContainer, T p) {
632 T ptrPart = nullptr;
633 if (!p) return ptrPart;
634 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
635 for (T truthParticle : *TruthContainer) {
636 if (HepMC::is_sim_descendant(p,truthParticle)) {
637 ptrPart = truthParticle;
638 break;
639 }
640 }
641 }
642 else {
643 for (T truthParticle : TruthContainer) {
644 if (HepMC::is_sim_descendant(p,truthParticle)) {
645 ptrPart = truthParticle;
646 break;
647 }
648 }
649 }
650 return ptrPart;
651 }
653
654 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
655 auto prodVtx = thePart->production_vertex();
656 if (!prodVtx) return;
657 for (const auto& theMother: prodVtx->particles_in()) {
658 if (!theMother) continue;
659 allancestors.insert(theMother);
660 findParticleAncestors(theMother, allancestors);
661 }
662 }
663
665
666 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
667 auto endVtx = thePart->end_vertex();
668 if (!endVtx) return;
669 for (const auto& theDaughter: endVtx->particles_out()) {
670 if (!theDaughter) continue;
671 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
672 allstabledescendants.insert(theDaughter);
673 }
674 findParticleStableDescendants(theDaughter, allstabledescendants);
675 }
676 }
677
681
682 template <class T> bool isHardScatteringVertex(T pVert) {
683 if (pVert == nullptr) return false;
684 T pV = pVert;
685 int numOfPartIn(0);
686 int pdg(0);
687
688 do {
689 pVert = pV;
690 auto incoming = pVert->particles_in();
691 numOfPartIn = incoming.size();
692 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
693 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
694
695 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
696
697 if (numOfPartIn == 2) {
698 auto incoming = pVert->particles_in();
699 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
700 }
701 return false;
702}
703
707
708 template <class T, class U>
709 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
710 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
711 auto vtx = p->production_vertex();
712 if (!vtx) return false;
713 bool fromHad = false;
714 for ( const auto& parent : particles_in(vtx) ) {
715 if (!parent) continue;
716 // should this really go into parton-level territory?
717 // probably depends where BSM particles are being decayed
718 fromBSM |= isBSM(parent);
719 if (!isPhysical(parent)) return false;
720 fromTau |= isTau(parent);
721 if (isHadron(parent)&&!isBeam(parent)) {
722 if (!hadron) hadron = parent; // assumes linear hadron parentage
723 return true;
724 }
725 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
726 }
727 return fromHad;
728 }
729
732
733 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
734 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
735 decltype(thePart->end_vertex()) pVert(nullptr);
736 if (EndVert != nullptr) {
737 do {
738 bool samePart = false;
739 pVert = nullptr;
740 auto outgoing = EndVert->particles_out();
741 auto incoming = EndVert->particles_in();
742 for (const auto& itrDaug: outgoing) {
743 if (!itrDaug) continue;
744 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
745 // brem on generator level for tau
746 (outgoing.size() == 1 && incoming.size() == 1 &&
748 itrDaug->pdg_id() == thePart->pdg_id()) {
749 samePart = true;
750 pVert = itrDaug->end_vertex();
751 }
752 }
753 if (samePart) EndVert = pVert;
754 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
755 }
756 return EndVert;
757 }
758
760
761 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
762 if (!theVert) return {};
763 decltype(theVert->particles_out()) finalStatePart;
764 auto outgoing = theVert->particles_out();
765 for (const auto& thePart: outgoing) {
766 if (!thePart) continue;
767 finalStatePart.push_back(thePart);
768 if (isStable(thePart)) continue;
769 V pVert = findSimulatedEndVertex(thePart);
770 if (pVert == theVert) break; // to prevent Sherpa loop
771 if (pVert != nullptr) {
772 auto vecPart = findFinalStateParticles<V>(pVert);
773 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
774 }
775 }
776 return finalStatePart;
777 }
778
779}
780#endif

◆ isSMLepton() [1/3]

template<>
bool MC::isSMLepton ( const DecodedPID & p)
inline

Definition at line 197 of file HepMCHelpers.h.

197: nullptr;

◆ isSMLepton() [2/3]

template<>
bool MC::isSMLepton ( const int & p)
inline

Definition at line 196 of file HepMCHelpers.h.

196: 0;

◆ isSMLepton() [3/3]

template<class T>
bool MC::isSMLepton ( const T & p)
inline

APID: the fourth generation leptons are not standard model leptons.

Definition at line 195 of file HepMCHelpers.h.

◆ isSMNeutrino() [1/2]

template<>
bool MC::isSMNeutrino ( const int & p)
inline

Definition at line 217 of file HepMCHelpers.h.

◆ isSMNeutrino() [2/2]

template<class T>
bool MC::isSMNeutrino ( const T & p)
inline

Definition at line 216 of file HepMCHelpers.h.

◆ isSMQuark() [1/3]

template<>
bool MC::isSMQuark ( const DecodedPID & p)
inline

Definition at line 175 of file HepMCHelpers.h.

175{

◆ isSMQuark() [2/3]

template<>
bool MC::isSMQuark ( const int & p)
inline

Definition at line 174 of file HepMCHelpers.h.

◆ isSMQuark() [3/3]

template<class T>
bool MC::isSMQuark ( const T & p)
inline

Definition at line 173 of file HepMCHelpers.h.

173: endVtx->particles_out()) {

◆ isSpecialNonInteracting()

template<class T>
bool MC::isSpecialNonInteracting ( const T & p)
inline

Identify a special non-interacting particles.

Definition at line 92 of file HepMCHelpers.h.

92 {
93 const int apid = std::abs(p->pdg_id());
94 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
95 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
96 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
97 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
98 return false;
99 }

◆ isSquark() [1/3]

template<>
bool MC::isSquark ( const DecodedPID & p)
inline

Definition at line 460 of file HepMCHelpers.h.

481 {
482inline
483auto particles_in (const HepMC::GenVertex* p) {
484 return std::ranges::subrange (p->particles_in_const_begin(),
485 p->particles_in_const_end());
486}
487}
488#endif
489
490namespace MC
491{
492 template <class VTX>
493 auto particles_in (const VTX* p) { return p->particles_in(); }
494 template <class VTX>
495 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
496
497 namespace Pythia8
498 {
500 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
501
502 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
503
504 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
505 }
506
507#include "AtlasPID.h"
508
510 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
511
513 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
514
516 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
517
519 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
520
522 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
523
525 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
526
528 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
529
531 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
532
534 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
535
537 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
538
542 template <class T> inline bool isStableOrSimDecayed(const T& p) {
543 const auto vertex = p->end_vertex();
544 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
545 }
546
548 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
549
551 template <class T> inline bool isSpecialNonInteracting(const T& p) {
552 const int apid = std::abs(p->pdg_id());
553 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
554 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
555 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
556 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
557 return false;
558 }
559
561
562 template <class T> T findMother(T thePart) {
563 auto partOriVert = thePart->production_vertex();
564 if (!partOriVert) return nullptr;
565
566 long partPDG = thePart->pdg_id();
567 long MotherPDG(0);
568
569 auto MothOriVert = partOriVert;
570 MothOriVert = nullptr;
571 T theMoth(nullptr);
572
573 size_t itr = 0;
574 do {
575 if (itr != 0) partOriVert = MothOriVert;
576 for ( const auto& p : particles_in(partOriVert) ) {
577 theMoth = p;
578 if (!theMoth) continue;
579 MotherPDG = theMoth->pdg_id();
580 MothOriVert = theMoth->production_vertex();
581 if (MotherPDG == partPDG) break;
582 }
583 itr++;
584 if (itr > 100) {
585 break;
586 }
587 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
588 MothOriVert != partOriVert);
589 return theMoth;
590 }
591
593
594 template <class C, class T> T findMatching(C TruthContainer, T p) {
595 T ptrPart = nullptr;
596 if (!p) return ptrPart;
597 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
598 for (T truthParticle : *TruthContainer) {
599 if (HepMC::is_sim_descendant(p,truthParticle)) {
600 ptrPart = truthParticle;
601 break;
602 }
603 }
604 }
605 else {
606 for (T truthParticle : TruthContainer) {
607 if (HepMC::is_sim_descendant(p,truthParticle)) {
608 ptrPart = truthParticle;
609 break;
610 }
611 }
612 }
613 return ptrPart;
614 }
616
617 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
618 auto prodVtx = thePart->production_vertex();
619 if (!prodVtx) return;
620 for (const auto& theMother: prodVtx->particles_in()) {
621 if (!theMother) continue;
622 allancestors.insert(theMother);
623 findParticleAncestors(theMother, allancestors);
624 }
625 }
626
628
629 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
630 auto endVtx = thePart->end_vertex();
631 if (!endVtx) return;
632 for (const auto& theDaughter: endVtx->particles_out()) {
633 if (!theDaughter) continue;
634 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
635 allstabledescendants.insert(theDaughter);
636 }
637 findParticleStableDescendants(theDaughter, allstabledescendants);
638 }
639 }
640
644
645 template <class T> bool isHardScatteringVertex(T pVert) {
646 if (pVert == nullptr) return false;
647 T pV = pVert;
648 int numOfPartIn(0);
649 int pdg(0);
650
651 do {
652 pVert = pV;
653 auto incoming = pVert->particles_in();
654 numOfPartIn = incoming.size();
655 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
656 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
657
658 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
659
660 if (numOfPartIn == 2) {
661 auto incoming = pVert->particles_in();
662 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
663 }
664 return false;
665}
666
670
671 template <class T, class U>
672 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
673 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
674 auto vtx = p->production_vertex();
675 if (!vtx) return false;
676 bool fromHad = false;
677 for ( const auto& parent : particles_in(vtx) ) {
678 if (!parent) continue;
679 // should this really go into parton-level territory?
680 // probably depends where BSM particles are being decayed
681 fromBSM |= isBSM(parent);
682 if (!isPhysical(parent)) return false;
683 fromTau |= isTau(parent);
684 if (isHadron(parent)&&!isBeam(parent)) {
685 if (!hadron) hadron = parent; // assumes linear hadron parentage
686 return true;
687 }
688 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
689 }
690 return fromHad;
691 }
692
695
696 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
697 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
698 decltype(thePart->end_vertex()) pVert(nullptr);
699 if (EndVert != nullptr) {
700 do {
701 bool samePart = false;
702 pVert = nullptr;
703 auto outgoing = EndVert->particles_out();
704 auto incoming = EndVert->particles_in();
705 for (const auto& itrDaug: outgoing) {
706 if (!itrDaug) continue;
707 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
708 // brem on generator level for tau
709 (outgoing.size() == 1 && incoming.size() == 1 &&
711 itrDaug->pdg_id() == thePart->pdg_id()) {
712 samePart = true;
713 pVert = itrDaug->end_vertex();
714 }
715 }
716 if (samePart) EndVert = pVert;
717 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
718 }
719 return EndVert;
720 }
721
723
724 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
725 if (!theVert) return {};
726 decltype(theVert->particles_out()) finalStatePart;
727 auto outgoing = theVert->particles_out();
728 for (const auto& thePart: outgoing) {
729 if (!thePart) continue;
730 finalStatePart.push_back(thePart);
731 if (isStable(thePart)) continue;
732 V pVert = findSimulatedEndVertex(thePart);
733 if (pVert == theVert) break; // to prevent Sherpa loop
734 if (pVert != nullptr) {
735 auto vecPart = findFinalStateParticles<V>(pVert);
736 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
737 }
738 }
739 return finalStatePart;
740 }
741
742}
743#endif

◆ isSquark() [2/3]

template<>
bool MC::isSquark ( const int & p)
inline

Definition at line 463 of file HepMCHelpers.h.

484{
485inline
486auto particles_in (const HepMC::GenVertex* p) {
487 return std::ranges::subrange (p->particles_in_const_begin(),
488 p->particles_in_const_end());
489}
490}
491#endif
492
493namespace MC
494{
495 template <class VTX>
496 auto particles_in (const VTX* p) { return p->particles_in(); }
497 template <class VTX>
498 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
499
500 namespace Pythia8
501 {
503 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
504
505 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
506
507 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
508 }
509
510#include "AtlasPID.h"
511
513 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
514
516 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
517
519 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
520
522 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
523
525 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
526
528 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
529
531 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
532
534 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
535
537 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
538
540 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
541
545 template <class T> inline bool isStableOrSimDecayed(const T& p) {
546 const auto vertex = p->end_vertex();
547 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
548 }
549
551 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
552
554 template <class T> inline bool isSpecialNonInteracting(const T& p) {
555 const int apid = std::abs(p->pdg_id());
556 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
557 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
558 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
559 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
560 return false;
561 }
562
564
565 template <class T> T findMother(T thePart) {
566 auto partOriVert = thePart->production_vertex();
567 if (!partOriVert) return nullptr;
568
569 long partPDG = thePart->pdg_id();
570 long MotherPDG(0);
571
572 auto MothOriVert = partOriVert;
573 MothOriVert = nullptr;
574 T theMoth(nullptr);
575
576 size_t itr = 0;
577 do {
578 if (itr != 0) partOriVert = MothOriVert;
579 for ( const auto& p : particles_in(partOriVert) ) {
580 theMoth = p;
581 if (!theMoth) continue;
582 MotherPDG = theMoth->pdg_id();
583 MothOriVert = theMoth->production_vertex();
584 if (MotherPDG == partPDG) break;
585 }
586 itr++;
587 if (itr > 100) {
588 break;
589 }
590 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
591 MothOriVert != partOriVert);
592 return theMoth;
593 }
594
596
597 template <class C, class T> T findMatching(C TruthContainer, T p) {
598 T ptrPart = nullptr;
599 if (!p) return ptrPart;
600 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
601 for (T truthParticle : *TruthContainer) {
602 if (HepMC::is_sim_descendant(p,truthParticle)) {
603 ptrPart = truthParticle;
604 break;
605 }
606 }
607 }
608 else {
609 for (T truthParticle : TruthContainer) {
610 if (HepMC::is_sim_descendant(p,truthParticle)) {
611 ptrPart = truthParticle;
612 break;
613 }
614 }
615 }
616 return ptrPart;
617 }
619
620 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
621 auto prodVtx = thePart->production_vertex();
622 if (!prodVtx) return;
623 for (const auto& theMother: prodVtx->particles_in()) {
624 if (!theMother) continue;
625 allancestors.insert(theMother);
626 findParticleAncestors(theMother, allancestors);
627 }
628 }
629
631
632 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
633 auto endVtx = thePart->end_vertex();
634 if (!endVtx) return;
635 for (const auto& theDaughter: endVtx->particles_out()) {
636 if (!theDaughter) continue;
637 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
638 allstabledescendants.insert(theDaughter);
639 }
640 findParticleStableDescendants(theDaughter, allstabledescendants);
641 }
642 }
643
647
648 template <class T> bool isHardScatteringVertex(T pVert) {
649 if (pVert == nullptr) return false;
650 T pV = pVert;
651 int numOfPartIn(0);
652 int pdg(0);
653
654 do {
655 pVert = pV;
656 auto incoming = pVert->particles_in();
657 numOfPartIn = incoming.size();
658 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
659 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
660
661 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
662
663 if (numOfPartIn == 2) {
664 auto incoming = pVert->particles_in();
665 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
666 }
667 return false;
668}
669
673
674 template <class T, class U>
675 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
676 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
677 auto vtx = p->production_vertex();
678 if (!vtx) return false;
679 bool fromHad = false;
680 for ( const auto& parent : particles_in(vtx) ) {
681 if (!parent) continue;
682 // should this really go into parton-level territory?
683 // probably depends where BSM particles are being decayed
684 fromBSM |= isBSM(parent);
685 if (!isPhysical(parent)) return false;
686 fromTau |= isTau(parent);
687 if (isHadron(parent)&&!isBeam(parent)) {
688 if (!hadron) hadron = parent; // assumes linear hadron parentage
689 return true;
690 }
691 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
692 }
693 return fromHad;
694 }
695
698
699 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
700 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
701 decltype(thePart->end_vertex()) pVert(nullptr);
702 if (EndVert != nullptr) {
703 do {
704 bool samePart = false;
705 pVert = nullptr;
706 auto outgoing = EndVert->particles_out();
707 auto incoming = EndVert->particles_in();
708 for (const auto& itrDaug: outgoing) {
709 if (!itrDaug) continue;
710 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
711 // brem on generator level for tau
712 (outgoing.size() == 1 && incoming.size() == 1 &&
714 itrDaug->pdg_id() == thePart->pdg_id()) {
715 samePart = true;
716 pVert = itrDaug->end_vertex();
717 }
718 }
719 if (samePart) EndVert = pVert;
720 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
721 }
722 return EndVert;
723 }
724
726
727 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
728 if (!theVert) return {};
729 decltype(theVert->particles_out()) finalStatePart;
730 auto outgoing = theVert->particles_out();
731 for (const auto& thePart: outgoing) {
732 if (!thePart) continue;
733 finalStatePart.push_back(thePart);
734 if (isStable(thePart)) continue;
735 V pVert = findSimulatedEndVertex(thePart);
736 if (pVert == theVert) break; // to prevent Sherpa loop
737 if (pVert != nullptr) {
738 auto vecPart = findFinalStateParticles<V>(pVert);
739 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
740 }
741 }
742 return finalStatePart;
743 }
744
745}
746#endif

◆ isSquark() [3/3]

template<class T>
bool MC::isSquark ( const T & p)
inline

PDG rule 11d Fundamental supersymmetric particles are identified by adding a nonzero n to the particle number.

The superpartner of a boson or a left-handed fermion has n = 1 while the superpartner of a right-handed fermion has n = 2. When mixing occurs, such as between the winos and charged Higgsinos to give charginos, or between left and right sfermions, the lighter physical state is given the smaller basis state number.

Definition at line 459 of file HepMCHelpers.h.

480{
481inline
482auto particles_in (const HepMC::GenVertex* p) {
483 return std::ranges::subrange (p->particles_in_const_begin(),
484 p->particles_in_const_end());
485}
486}
487#endif
488
489namespace MC
490{
491 template <class VTX>
492 auto particles_in (const VTX* p) { return p->particles_in(); }
493 template <class VTX>
494 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
495
496 namespace Pythia8
497 {
499 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
500
501 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
502
503 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
504 }
505
506#include "AtlasPID.h"
507
509 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
510
512 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
513
515 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
516
518 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
519
521 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
522
524 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
525
527 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
528
530 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
531
533 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
534
536 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
537
541 template <class T> inline bool isStableOrSimDecayed(const T& p) {
542 const auto vertex = p->end_vertex();
543 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
544 }
545
547 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
548
550 template <class T> inline bool isSpecialNonInteracting(const T& p) {
551 const int apid = std::abs(p->pdg_id());
552 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
553 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
554 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
555 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
556 return false;
557 }
558
560
561 template <class T> T findMother(T thePart) {
562 auto partOriVert = thePart->production_vertex();
563 if (!partOriVert) return nullptr;
564
565 long partPDG = thePart->pdg_id();
566 long MotherPDG(0);
567
568 auto MothOriVert = partOriVert;
569 MothOriVert = nullptr;
570 T theMoth(nullptr);
571
572 size_t itr = 0;
573 do {
574 if (itr != 0) partOriVert = MothOriVert;
575 for ( const auto& p : particles_in(partOriVert) ) {
576 theMoth = p;
577 if (!theMoth) continue;
578 MotherPDG = theMoth->pdg_id();
579 MothOriVert = theMoth->production_vertex();
580 if (MotherPDG == partPDG) break;
581 }
582 itr++;
583 if (itr > 100) {
584 break;
585 }
586 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
587 MothOriVert != partOriVert);
588 return theMoth;
589 }
590
592
593 template <class C, class T> T findMatching(C TruthContainer, T p) {
594 T ptrPart = nullptr;
595 if (!p) return ptrPart;
596 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
597 for (T truthParticle : *TruthContainer) {
598 if (HepMC::is_sim_descendant(p,truthParticle)) {
599 ptrPart = truthParticle;
600 break;
601 }
602 }
603 }
604 else {
605 for (T truthParticle : TruthContainer) {
606 if (HepMC::is_sim_descendant(p,truthParticle)) {
607 ptrPart = truthParticle;
608 break;
609 }
610 }
611 }
612 return ptrPart;
613 }
615
616 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
617 auto prodVtx = thePart->production_vertex();
618 if (!prodVtx) return;
619 for (const auto& theMother: prodVtx->particles_in()) {
620 if (!theMother) continue;
621 allancestors.insert(theMother);
622 findParticleAncestors(theMother, allancestors);
623 }
624 }
625
627
628 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
629 auto endVtx = thePart->end_vertex();
630 if (!endVtx) return;
631 for (const auto& theDaughter: endVtx->particles_out()) {
632 if (!theDaughter) continue;
633 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
634 allstabledescendants.insert(theDaughter);
635 }
636 findParticleStableDescendants(theDaughter, allstabledescendants);
637 }
638 }
639
643
644 template <class T> bool isHardScatteringVertex(T pVert) {
645 if (pVert == nullptr) return false;
646 T pV = pVert;
647 int numOfPartIn(0);
648 int pdg(0);
649
650 do {
651 pVert = pV;
652 auto incoming = pVert->particles_in();
653 numOfPartIn = incoming.size();
654 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
655 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
656
657 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
658
659 if (numOfPartIn == 2) {
660 auto incoming = pVert->particles_in();
661 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
662 }
663 return false;
664}
665
669
670 template <class T, class U>
671 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
672 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
673 auto vtx = p->production_vertex();
674 if (!vtx) return false;
675 bool fromHad = false;
676 for ( const auto& parent : particles_in(vtx) ) {
677 if (!parent) continue;
678 // should this really go into parton-level territory?
679 // probably depends where BSM particles are being decayed
680 fromBSM |= isBSM(parent);
681 if (!isPhysical(parent)) return false;
682 fromTau |= isTau(parent);
683 if (isHadron(parent)&&!isBeam(parent)) {
684 if (!hadron) hadron = parent; // assumes linear hadron parentage
685 return true;
686 }
687 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
688 }
689 return fromHad;
690 }
691
694
695 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
696 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
697 decltype(thePart->end_vertex()) pVert(nullptr);
698 if (EndVert != nullptr) {
699 do {
700 bool samePart = false;
701 pVert = nullptr;
702 auto outgoing = EndVert->particles_out();
703 auto incoming = EndVert->particles_in();
704 for (const auto& itrDaug: outgoing) {
705 if (!itrDaug) continue;
706 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
707 // brem on generator level for tau
708 (outgoing.size() == 1 && incoming.size() == 1 &&
710 itrDaug->pdg_id() == thePart->pdg_id()) {
711 samePart = true;
712 pVert = itrDaug->end_vertex();
713 }
714 }
715 if (samePart) EndVert = pVert;
716 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
717 }
718 return EndVert;
719 }
720
722
723 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
724 if (!theVert) return {};
725 decltype(theVert->particles_out()) finalStatePart;
726 auto outgoing = theVert->particles_out();
727 for (const auto& thePart: outgoing) {
728 if (!thePart) continue;
729 finalStatePart.push_back(thePart);
730 if (isStable(thePart)) continue;
731 V pVert = findSimulatedEndVertex(thePart);
732 if (pVert == theVert) break; // to prevent Sherpa loop
733 if (pVert != nullptr) {
734 auto vecPart = findFinalStateParticles<V>(pVert);
735 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
736 }
737 }
738 return finalStatePart;
739 }
740
741}
742#endif

◆ isSquarkLH() [1/3]

template<>
bool MC::isSquarkLH ( const DecodedPID & p)
inline

Definition at line 468 of file HepMCHelpers.h.

489 {
490inline
491auto particles_in (const HepMC::GenVertex* p) {
492 return std::ranges::subrange (p->particles_in_const_begin(),
493 p->particles_in_const_end());
494}
495}
496#endif
497
498namespace MC
499{
500 template <class VTX>
501 auto particles_in (const VTX* p) { return p->particles_in(); }
502 template <class VTX>
503 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
504
505 namespace Pythia8
506 {
508 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
509
510 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
511
512 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
513 }
514
515#include "AtlasPID.h"
516
518 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
519
521 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
522
524 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
525
527 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
528
530 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
531
533 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
534
536 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
537
539 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
540
542 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
543
545 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
546
550 template <class T> inline bool isStableOrSimDecayed(const T& p) {
551 const auto vertex = p->end_vertex();
552 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
553 }
554
556 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
557
559 template <class T> inline bool isSpecialNonInteracting(const T& p) {
560 const int apid = std::abs(p->pdg_id());
561 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
562 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
563 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
564 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
565 return false;
566 }
567
569
570 template <class T> T findMother(T thePart) {
571 auto partOriVert = thePart->production_vertex();
572 if (!partOriVert) return nullptr;
573
574 long partPDG = thePart->pdg_id();
575 long MotherPDG(0);
576
577 auto MothOriVert = partOriVert;
578 MothOriVert = nullptr;
579 T theMoth(nullptr);
580
581 size_t itr = 0;
582 do {
583 if (itr != 0) partOriVert = MothOriVert;
584 for ( const auto& p : particles_in(partOriVert) ) {
585 theMoth = p;
586 if (!theMoth) continue;
587 MotherPDG = theMoth->pdg_id();
588 MothOriVert = theMoth->production_vertex();
589 if (MotherPDG == partPDG) break;
590 }
591 itr++;
592 if (itr > 100) {
593 break;
594 }
595 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
596 MothOriVert != partOriVert);
597 return theMoth;
598 }
599
601
602 template <class C, class T> T findMatching(C TruthContainer, T p) {
603 T ptrPart = nullptr;
604 if (!p) return ptrPart;
605 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
606 for (T truthParticle : *TruthContainer) {
607 if (HepMC::is_sim_descendant(p,truthParticle)) {
608 ptrPart = truthParticle;
609 break;
610 }
611 }
612 }
613 else {
614 for (T truthParticle : TruthContainer) {
615 if (HepMC::is_sim_descendant(p,truthParticle)) {
616 ptrPart = truthParticle;
617 break;
618 }
619 }
620 }
621 return ptrPart;
622 }
624
625 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
626 auto prodVtx = thePart->production_vertex();
627 if (!prodVtx) return;
628 for (const auto& theMother: prodVtx->particles_in()) {
629 if (!theMother) continue;
630 allancestors.insert(theMother);
631 findParticleAncestors(theMother, allancestors);
632 }
633 }
634
636
637 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
638 auto endVtx = thePart->end_vertex();
639 if (!endVtx) return;
640 for (const auto& theDaughter: endVtx->particles_out()) {
641 if (!theDaughter) continue;
642 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
643 allstabledescendants.insert(theDaughter);
644 }
645 findParticleStableDescendants(theDaughter, allstabledescendants);
646 }
647 }
648
652
653 template <class T> bool isHardScatteringVertex(T pVert) {
654 if (pVert == nullptr) return false;
655 T pV = pVert;
656 int numOfPartIn(0);
657 int pdg(0);
658
659 do {
660 pVert = pV;
661 auto incoming = pVert->particles_in();
662 numOfPartIn = incoming.size();
663 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
664 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
665
666 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
667
668 if (numOfPartIn == 2) {
669 auto incoming = pVert->particles_in();
670 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
671 }
672 return false;
673}
674
678
679 template <class T, class U>
680 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
681 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
682 auto vtx = p->production_vertex();
683 if (!vtx) return false;
684 bool fromHad = false;
685 for ( const auto& parent : particles_in(vtx) ) {
686 if (!parent) continue;
687 // should this really go into parton-level territory?
688 // probably depends where BSM particles are being decayed
689 fromBSM |= isBSM(parent);
690 if (!isPhysical(parent)) return false;
691 fromTau |= isTau(parent);
692 if (isHadron(parent)&&!isBeam(parent)) {
693 if (!hadron) hadron = parent; // assumes linear hadron parentage
694 return true;
695 }
696 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
697 }
698 return fromHad;
699 }
700
703
704 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
705 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
706 decltype(thePart->end_vertex()) pVert(nullptr);
707 if (EndVert != nullptr) {
708 do {
709 bool samePart = false;
710 pVert = nullptr;
711 auto outgoing = EndVert->particles_out();
712 auto incoming = EndVert->particles_in();
713 for (const auto& itrDaug: outgoing) {
714 if (!itrDaug) continue;
715 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
716 // brem on generator level for tau
717 (outgoing.size() == 1 && incoming.size() == 1 &&
719 itrDaug->pdg_id() == thePart->pdg_id()) {
720 samePart = true;
721 pVert = itrDaug->end_vertex();
722 }
723 }
724 if (samePart) EndVert = pVert;
725 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
726 }
727 return EndVert;
728 }
729
731
732 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
733 if (!theVert) return {};
734 decltype(theVert->particles_out()) finalStatePart;
735 auto outgoing = theVert->particles_out();
736 for (const auto& thePart: outgoing) {
737 if (!thePart) continue;
738 finalStatePart.push_back(thePart);
739 if (isStable(thePart)) continue;
740 V pVert = findSimulatedEndVertex(thePart);
741 if (pVert == theVert) break; // to prevent Sherpa loop
742 if (pVert != nullptr) {
743 auto vecPart = findFinalStateParticles<V>(pVert);
744 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
745 }
746 }
747 return finalStatePart;
748 }
749
750}
751#endif

◆ isSquarkLH() [2/3]

template<>
bool MC::isSquarkLH ( const int & p)
inline

Definition at line 471 of file HepMCHelpers.h.

492{
493inline
494auto particles_in (const HepMC::GenVertex* p) {
495 return std::ranges::subrange (p->particles_in_const_begin(),
496 p->particles_in_const_end());
497}
498}
499#endif
500
501namespace MC
502{
503 template <class VTX>
504 auto particles_in (const VTX* p) { return p->particles_in(); }
505 template <class VTX>
506 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
507
508 namespace Pythia8
509 {
511 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
512
513 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
514
515 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
516 }
517
518#include "AtlasPID.h"
519
521 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
522
524 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
525
527 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
528
530 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
531
533 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
534
536 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
537
539 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
540
542 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
543
545 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
546
548 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
549
553 template <class T> inline bool isStableOrSimDecayed(const T& p) {
554 const auto vertex = p->end_vertex();
555 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
556 }
557
559 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
560
562 template <class T> inline bool isSpecialNonInteracting(const T& p) {
563 const int apid = std::abs(p->pdg_id());
564 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
565 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
566 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
567 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
568 return false;
569 }
570
572
573 template <class T> T findMother(T thePart) {
574 auto partOriVert = thePart->production_vertex();
575 if (!partOriVert) return nullptr;
576
577 long partPDG = thePart->pdg_id();
578 long MotherPDG(0);
579
580 auto MothOriVert = partOriVert;
581 MothOriVert = nullptr;
582 T theMoth(nullptr);
583
584 size_t itr = 0;
585 do {
586 if (itr != 0) partOriVert = MothOriVert;
587 for ( const auto& p : particles_in(partOriVert) ) {
588 theMoth = p;
589 if (!theMoth) continue;
590 MotherPDG = theMoth->pdg_id();
591 MothOriVert = theMoth->production_vertex();
592 if (MotherPDG == partPDG) break;
593 }
594 itr++;
595 if (itr > 100) {
596 break;
597 }
598 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
599 MothOriVert != partOriVert);
600 return theMoth;
601 }
602
604
605 template <class C, class T> T findMatching(C TruthContainer, T p) {
606 T ptrPart = nullptr;
607 if (!p) return ptrPart;
608 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
609 for (T truthParticle : *TruthContainer) {
610 if (HepMC::is_sim_descendant(p,truthParticle)) {
611 ptrPart = truthParticle;
612 break;
613 }
614 }
615 }
616 else {
617 for (T truthParticle : TruthContainer) {
618 if (HepMC::is_sim_descendant(p,truthParticle)) {
619 ptrPart = truthParticle;
620 break;
621 }
622 }
623 }
624 return ptrPart;
625 }
627
628 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
629 auto prodVtx = thePart->production_vertex();
630 if (!prodVtx) return;
631 for (const auto& theMother: prodVtx->particles_in()) {
632 if (!theMother) continue;
633 allancestors.insert(theMother);
634 findParticleAncestors(theMother, allancestors);
635 }
636 }
637
639
640 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
641 auto endVtx = thePart->end_vertex();
642 if (!endVtx) return;
643 for (const auto& theDaughter: endVtx->particles_out()) {
644 if (!theDaughter) continue;
645 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
646 allstabledescendants.insert(theDaughter);
647 }
648 findParticleStableDescendants(theDaughter, allstabledescendants);
649 }
650 }
651
655
656 template <class T> bool isHardScatteringVertex(T pVert) {
657 if (pVert == nullptr) return false;
658 T pV = pVert;
659 int numOfPartIn(0);
660 int pdg(0);
661
662 do {
663 pVert = pV;
664 auto incoming = pVert->particles_in();
665 numOfPartIn = incoming.size();
666 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
667 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
668
669 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
670
671 if (numOfPartIn == 2) {
672 auto incoming = pVert->particles_in();
673 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
674 }
675 return false;
676}
677
681
682 template <class T, class U>
683 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
684 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
685 auto vtx = p->production_vertex();
686 if (!vtx) return false;
687 bool fromHad = false;
688 for ( const auto& parent : particles_in(vtx) ) {
689 if (!parent) continue;
690 // should this really go into parton-level territory?
691 // probably depends where BSM particles are being decayed
692 fromBSM |= isBSM(parent);
693 if (!isPhysical(parent)) return false;
694 fromTau |= isTau(parent);
695 if (isHadron(parent)&&!isBeam(parent)) {
696 if (!hadron) hadron = parent; // assumes linear hadron parentage
697 return true;
698 }
699 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
700 }
701 return fromHad;
702 }
703
706
707 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
708 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
709 decltype(thePart->end_vertex()) pVert(nullptr);
710 if (EndVert != nullptr) {
711 do {
712 bool samePart = false;
713 pVert = nullptr;
714 auto outgoing = EndVert->particles_out();
715 auto incoming = EndVert->particles_in();
716 for (const auto& itrDaug: outgoing) {
717 if (!itrDaug) continue;
718 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
719 // brem on generator level for tau
720 (outgoing.size() == 1 && incoming.size() == 1 &&
722 itrDaug->pdg_id() == thePart->pdg_id()) {
723 samePart = true;
724 pVert = itrDaug->end_vertex();
725 }
726 }
727 if (samePart) EndVert = pVert;
728 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
729 }
730 return EndVert;
731 }
732
734
735 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
736 if (!theVert) return {};
737 decltype(theVert->particles_out()) finalStatePart;
738 auto outgoing = theVert->particles_out();
739 for (const auto& thePart: outgoing) {
740 if (!thePart) continue;
741 finalStatePart.push_back(thePart);
742 if (isStable(thePart)) continue;
743 V pVert = findSimulatedEndVertex(thePart);
744 if (pVert == theVert) break; // to prevent Sherpa loop
745 if (pVert != nullptr) {
746 auto vecPart = findFinalStateParticles<V>(pVert);
747 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
748 }
749 }
750 return finalStatePart;
751 }
752
753}
754#endif

◆ isSquarkLH() [3/3]

template<class T>
bool MC::isSquarkLH ( const T & p)
inline

Definition at line 467 of file HepMCHelpers.h.

488{
489inline
490auto particles_in (const HepMC::GenVertex* p) {
491 return std::ranges::subrange (p->particles_in_const_begin(),
492 p->particles_in_const_end());
493}
494}
495#endif
496
497namespace MC
498{
499 template <class VTX>
500 auto particles_in (const VTX* p) { return p->particles_in(); }
501 template <class VTX>
502 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
503
504 namespace Pythia8
505 {
507 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
508
509 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
510
511 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
512 }
513
514#include "AtlasPID.h"
515
517 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
518
520 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
521
523 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
524
526 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
527
529 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
530
532 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
533
535 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
536
538 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
539
541 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
542
544 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
545
549 template <class T> inline bool isStableOrSimDecayed(const T& p) {
550 const auto vertex = p->end_vertex();
551 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
552 }
553
555 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
556
558 template <class T> inline bool isSpecialNonInteracting(const T& p) {
559 const int apid = std::abs(p->pdg_id());
560 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
561 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
562 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
563 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
564 return false;
565 }
566
568
569 template <class T> T findMother(T thePart) {
570 auto partOriVert = thePart->production_vertex();
571 if (!partOriVert) return nullptr;
572
573 long partPDG = thePart->pdg_id();
574 long MotherPDG(0);
575
576 auto MothOriVert = partOriVert;
577 MothOriVert = nullptr;
578 T theMoth(nullptr);
579
580 size_t itr = 0;
581 do {
582 if (itr != 0) partOriVert = MothOriVert;
583 for ( const auto& p : particles_in(partOriVert) ) {
584 theMoth = p;
585 if (!theMoth) continue;
586 MotherPDG = theMoth->pdg_id();
587 MothOriVert = theMoth->production_vertex();
588 if (MotherPDG == partPDG) break;
589 }
590 itr++;
591 if (itr > 100) {
592 break;
593 }
594 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
595 MothOriVert != partOriVert);
596 return theMoth;
597 }
598
600
601 template <class C, class T> T findMatching(C TruthContainer, T p) {
602 T ptrPart = nullptr;
603 if (!p) return ptrPart;
604 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
605 for (T truthParticle : *TruthContainer) {
606 if (HepMC::is_sim_descendant(p,truthParticle)) {
607 ptrPart = truthParticle;
608 break;
609 }
610 }
611 }
612 else {
613 for (T truthParticle : TruthContainer) {
614 if (HepMC::is_sim_descendant(p,truthParticle)) {
615 ptrPart = truthParticle;
616 break;
617 }
618 }
619 }
620 return ptrPart;
621 }
623
624 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
625 auto prodVtx = thePart->production_vertex();
626 if (!prodVtx) return;
627 for (const auto& theMother: prodVtx->particles_in()) {
628 if (!theMother) continue;
629 allancestors.insert(theMother);
630 findParticleAncestors(theMother, allancestors);
631 }
632 }
633
635
636 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
637 auto endVtx = thePart->end_vertex();
638 if (!endVtx) return;
639 for (const auto& theDaughter: endVtx->particles_out()) {
640 if (!theDaughter) continue;
641 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
642 allstabledescendants.insert(theDaughter);
643 }
644 findParticleStableDescendants(theDaughter, allstabledescendants);
645 }
646 }
647
651
652 template <class T> bool isHardScatteringVertex(T pVert) {
653 if (pVert == nullptr) return false;
654 T pV = pVert;
655 int numOfPartIn(0);
656 int pdg(0);
657
658 do {
659 pVert = pV;
660 auto incoming = pVert->particles_in();
661 numOfPartIn = incoming.size();
662 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
663 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
664
665 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
666
667 if (numOfPartIn == 2) {
668 auto incoming = pVert->particles_in();
669 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
670 }
671 return false;
672}
673
677
678 template <class T, class U>
679 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
680 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
681 auto vtx = p->production_vertex();
682 if (!vtx) return false;
683 bool fromHad = false;
684 for ( const auto& parent : particles_in(vtx) ) {
685 if (!parent) continue;
686 // should this really go into parton-level territory?
687 // probably depends where BSM particles are being decayed
688 fromBSM |= isBSM(parent);
689 if (!isPhysical(parent)) return false;
690 fromTau |= isTau(parent);
691 if (isHadron(parent)&&!isBeam(parent)) {
692 if (!hadron) hadron = parent; // assumes linear hadron parentage
693 return true;
694 }
695 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
696 }
697 return fromHad;
698 }
699
702
703 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
704 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
705 decltype(thePart->end_vertex()) pVert(nullptr);
706 if (EndVert != nullptr) {
707 do {
708 bool samePart = false;
709 pVert = nullptr;
710 auto outgoing = EndVert->particles_out();
711 auto incoming = EndVert->particles_in();
712 for (const auto& itrDaug: outgoing) {
713 if (!itrDaug) continue;
714 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
715 // brem on generator level for tau
716 (outgoing.size() == 1 && incoming.size() == 1 &&
718 itrDaug->pdg_id() == thePart->pdg_id()) {
719 samePart = true;
720 pVert = itrDaug->end_vertex();
721 }
722 }
723 if (samePart) EndVert = pVert;
724 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
725 }
726 return EndVert;
727 }
728
730
731 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
732 if (!theVert) return {};
733 decltype(theVert->particles_out()) finalStatePart;
734 auto outgoing = theVert->particles_out();
735 for (const auto& thePart: outgoing) {
736 if (!thePart) continue;
737 finalStatePart.push_back(thePart);
738 if (isStable(thePart)) continue;
739 V pVert = findSimulatedEndVertex(thePart);
740 if (pVert == theVert) break; // to prevent Sherpa loop
741 if (pVert != nullptr) {
742 auto vecPart = findFinalStateParticles<V>(pVert);
743 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
744 }
745 }
746 return finalStatePart;
747 }
748
749}
750#endif

◆ isSquarkRH() [1/3]

template<>
bool MC::isSquarkRH ( const DecodedPID & p)
inline

Definition at line 476 of file HepMCHelpers.h.

497 {
498inline
499auto particles_in (const HepMC::GenVertex* p) {
500 return std::ranges::subrange (p->particles_in_const_begin(),
501 p->particles_in_const_end());
502}
503}
504#endif
505
506namespace MC
507{
508 template <class VTX>
509 auto particles_in (const VTX* p) { return p->particles_in(); }
510 template <class VTX>
511 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
512
513 namespace Pythia8
514 {
516 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
517
518 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
519
520 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
521 }
522
523#include "AtlasPID.h"
524
526 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
527
529 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
530
532 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
533
535 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
536
538 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
539
541 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
542
544 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
545
547 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
548
550 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
551
553 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
554
558 template <class T> inline bool isStableOrSimDecayed(const T& p) {
559 const auto vertex = p->end_vertex();
560 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
561 }
562
564 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
565
567 template <class T> inline bool isSpecialNonInteracting(const T& p) {
568 const int apid = std::abs(p->pdg_id());
569 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
570 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
571 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
572 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
573 return false;
574 }
575
577
578 template <class T> T findMother(T thePart) {
579 auto partOriVert = thePart->production_vertex();
580 if (!partOriVert) return nullptr;
581
582 long partPDG = thePart->pdg_id();
583 long MotherPDG(0);
584
585 auto MothOriVert = partOriVert;
586 MothOriVert = nullptr;
587 T theMoth(nullptr);
588
589 size_t itr = 0;
590 do {
591 if (itr != 0) partOriVert = MothOriVert;
592 for ( const auto& p : particles_in(partOriVert) ) {
593 theMoth = p;
594 if (!theMoth) continue;
595 MotherPDG = theMoth->pdg_id();
596 MothOriVert = theMoth->production_vertex();
597 if (MotherPDG == partPDG) break;
598 }
599 itr++;
600 if (itr > 100) {
601 break;
602 }
603 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
604 MothOriVert != partOriVert);
605 return theMoth;
606 }
607
609
610 template <class C, class T> T findMatching(C TruthContainer, T p) {
611 T ptrPart = nullptr;
612 if (!p) return ptrPart;
613 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
614 for (T truthParticle : *TruthContainer) {
615 if (HepMC::is_sim_descendant(p,truthParticle)) {
616 ptrPart = truthParticle;
617 break;
618 }
619 }
620 }
621 else {
622 for (T truthParticle : TruthContainer) {
623 if (HepMC::is_sim_descendant(p,truthParticle)) {
624 ptrPart = truthParticle;
625 break;
626 }
627 }
628 }
629 return ptrPart;
630 }
632
633 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
634 auto prodVtx = thePart->production_vertex();
635 if (!prodVtx) return;
636 for (const auto& theMother: prodVtx->particles_in()) {
637 if (!theMother) continue;
638 allancestors.insert(theMother);
639 findParticleAncestors(theMother, allancestors);
640 }
641 }
642
644
645 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
646 auto endVtx = thePart->end_vertex();
647 if (!endVtx) return;
648 for (const auto& theDaughter: endVtx->particles_out()) {
649 if (!theDaughter) continue;
650 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
651 allstabledescendants.insert(theDaughter);
652 }
653 findParticleStableDescendants(theDaughter, allstabledescendants);
654 }
655 }
656
660
661 template <class T> bool isHardScatteringVertex(T pVert) {
662 if (pVert == nullptr) return false;
663 T pV = pVert;
664 int numOfPartIn(0);
665 int pdg(0);
666
667 do {
668 pVert = pV;
669 auto incoming = pVert->particles_in();
670 numOfPartIn = incoming.size();
671 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
672 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
673
674 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
675
676 if (numOfPartIn == 2) {
677 auto incoming = pVert->particles_in();
678 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
679 }
680 return false;
681}
682
686
687 template <class T, class U>
688 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
689 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
690 auto vtx = p->production_vertex();
691 if (!vtx) return false;
692 bool fromHad = false;
693 for ( const auto& parent : particles_in(vtx) ) {
694 if (!parent) continue;
695 // should this really go into parton-level territory?
696 // probably depends where BSM particles are being decayed
697 fromBSM |= isBSM(parent);
698 if (!isPhysical(parent)) return false;
699 fromTau |= isTau(parent);
700 if (isHadron(parent)&&!isBeam(parent)) {
701 if (!hadron) hadron = parent; // assumes linear hadron parentage
702 return true;
703 }
704 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
705 }
706 return fromHad;
707 }
708
711
712 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
713 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
714 decltype(thePart->end_vertex()) pVert(nullptr);
715 if (EndVert != nullptr) {
716 do {
717 bool samePart = false;
718 pVert = nullptr;
719 auto outgoing = EndVert->particles_out();
720 auto incoming = EndVert->particles_in();
721 for (const auto& itrDaug: outgoing) {
722 if (!itrDaug) continue;
723 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
724 // brem on generator level for tau
725 (outgoing.size() == 1 && incoming.size() == 1 &&
727 itrDaug->pdg_id() == thePart->pdg_id()) {
728 samePart = true;
729 pVert = itrDaug->end_vertex();
730 }
731 }
732 if (samePart) EndVert = pVert;
733 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
734 }
735 return EndVert;
736 }
737
739
740 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
741 if (!theVert) return {};
742 decltype(theVert->particles_out()) finalStatePart;
743 auto outgoing = theVert->particles_out();
744 for (const auto& thePart: outgoing) {
745 if (!thePart) continue;
746 finalStatePart.push_back(thePart);
747 if (isStable(thePart)) continue;
748 V pVert = findSimulatedEndVertex(thePart);
749 if (pVert == theVert) break; // to prevent Sherpa loop
750 if (pVert != nullptr) {
751 auto vecPart = findFinalStateParticles<V>(pVert);
752 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
753 }
754 }
755 return finalStatePart;
756 }
757
758}
759#endif

◆ isSquarkRH() [2/3]

template<>
bool MC::isSquarkRH ( const int & p)
inline

Definition at line 479 of file HepMCHelpers.h.

500{
501inline
502auto particles_in (const HepMC::GenVertex* p) {
503 return std::ranges::subrange (p->particles_in_const_begin(),
504 p->particles_in_const_end());
505}
506}
507#endif
508
509namespace MC
510{
511 template <class VTX>
512 auto particles_in (const VTX* p) { return p->particles_in(); }
513 template <class VTX>
514 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
515
516 namespace Pythia8
517 {
519 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
520
521 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
522
523 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
524 }
525
526#include "AtlasPID.h"
527
529 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
530
532 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
533
535 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
536
538 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
539
541 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
542
544 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
545
547 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
548
550 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
551
553 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
554
556 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
557
561 template <class T> inline bool isStableOrSimDecayed(const T& p) {
562 const auto vertex = p->end_vertex();
563 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
564 }
565
567 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
568
570 template <class T> inline bool isSpecialNonInteracting(const T& p) {
571 const int apid = std::abs(p->pdg_id());
572 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
573 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
574 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
575 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
576 return false;
577 }
578
580
581 template <class T> T findMother(T thePart) {
582 auto partOriVert = thePart->production_vertex();
583 if (!partOriVert) return nullptr;
584
585 long partPDG = thePart->pdg_id();
586 long MotherPDG(0);
587
588 auto MothOriVert = partOriVert;
589 MothOriVert = nullptr;
590 T theMoth(nullptr);
591
592 size_t itr = 0;
593 do {
594 if (itr != 0) partOriVert = MothOriVert;
595 for ( const auto& p : particles_in(partOriVert) ) {
596 theMoth = p;
597 if (!theMoth) continue;
598 MotherPDG = theMoth->pdg_id();
599 MothOriVert = theMoth->production_vertex();
600 if (MotherPDG == partPDG) break;
601 }
602 itr++;
603 if (itr > 100) {
604 break;
605 }
606 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
607 MothOriVert != partOriVert);
608 return theMoth;
609 }
610
612
613 template <class C, class T> T findMatching(C TruthContainer, T p) {
614 T ptrPart = nullptr;
615 if (!p) return ptrPart;
616 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
617 for (T truthParticle : *TruthContainer) {
618 if (HepMC::is_sim_descendant(p,truthParticle)) {
619 ptrPart = truthParticle;
620 break;
621 }
622 }
623 }
624 else {
625 for (T truthParticle : TruthContainer) {
626 if (HepMC::is_sim_descendant(p,truthParticle)) {
627 ptrPart = truthParticle;
628 break;
629 }
630 }
631 }
632 return ptrPart;
633 }
635
636 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
637 auto prodVtx = thePart->production_vertex();
638 if (!prodVtx) return;
639 for (const auto& theMother: prodVtx->particles_in()) {
640 if (!theMother) continue;
641 allancestors.insert(theMother);
642 findParticleAncestors(theMother, allancestors);
643 }
644 }
645
647
648 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
649 auto endVtx = thePart->end_vertex();
650 if (!endVtx) return;
651 for (const auto& theDaughter: endVtx->particles_out()) {
652 if (!theDaughter) continue;
653 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
654 allstabledescendants.insert(theDaughter);
655 }
656 findParticleStableDescendants(theDaughter, allstabledescendants);
657 }
658 }
659
663
664 template <class T> bool isHardScatteringVertex(T pVert) {
665 if (pVert == nullptr) return false;
666 T pV = pVert;
667 int numOfPartIn(0);
668 int pdg(0);
669
670 do {
671 pVert = pV;
672 auto incoming = pVert->particles_in();
673 numOfPartIn = incoming.size();
674 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
675 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
676
677 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
678
679 if (numOfPartIn == 2) {
680 auto incoming = pVert->particles_in();
681 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
682 }
683 return false;
684}
685
689
690 template <class T, class U>
691 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
692 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
693 auto vtx = p->production_vertex();
694 if (!vtx) return false;
695 bool fromHad = false;
696 for ( const auto& parent : particles_in(vtx) ) {
697 if (!parent) continue;
698 // should this really go into parton-level territory?
699 // probably depends where BSM particles are being decayed
700 fromBSM |= isBSM(parent);
701 if (!isPhysical(parent)) return false;
702 fromTau |= isTau(parent);
703 if (isHadron(parent)&&!isBeam(parent)) {
704 if (!hadron) hadron = parent; // assumes linear hadron parentage
705 return true;
706 }
707 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
708 }
709 return fromHad;
710 }
711
714
715 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
716 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
717 decltype(thePart->end_vertex()) pVert(nullptr);
718 if (EndVert != nullptr) {
719 do {
720 bool samePart = false;
721 pVert = nullptr;
722 auto outgoing = EndVert->particles_out();
723 auto incoming = EndVert->particles_in();
724 for (const auto& itrDaug: outgoing) {
725 if (!itrDaug) continue;
726 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
727 // brem on generator level for tau
728 (outgoing.size() == 1 && incoming.size() == 1 &&
730 itrDaug->pdg_id() == thePart->pdg_id()) {
731 samePart = true;
732 pVert = itrDaug->end_vertex();
733 }
734 }
735 if (samePart) EndVert = pVert;
736 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
737 }
738 return EndVert;
739 }
740
742
743 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
744 if (!theVert) return {};
745 decltype(theVert->particles_out()) finalStatePart;
746 auto outgoing = theVert->particles_out();
747 for (const auto& thePart: outgoing) {
748 if (!thePart) continue;
749 finalStatePart.push_back(thePart);
750 if (isStable(thePart)) continue;
751 V pVert = findSimulatedEndVertex(thePart);
752 if (pVert == theVert) break; // to prevent Sherpa loop
753 if (pVert != nullptr) {
754 auto vecPart = findFinalStateParticles<V>(pVert);
755 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
756 }
757 }
758 return finalStatePart;
759 }
760
761}
762#endif

◆ isSquarkRH() [3/3]

template<class T>
bool MC::isSquarkRH ( const T & p)
inline

Definition at line 475 of file HepMCHelpers.h.

496{
497inline
498auto particles_in (const HepMC::GenVertex* p) {
499 return std::ranges::subrange (p->particles_in_const_begin(),
500 p->particles_in_const_end());
501}
502}
503#endif
504
505namespace MC
506{
507 template <class VTX>
508 auto particles_in (const VTX* p) { return p->particles_in(); }
509 template <class VTX>
510 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
511
512 namespace Pythia8
513 {
515 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
516
517 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
518
519 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
520 }
521
522#include "AtlasPID.h"
523
525 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
526
528 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
529
531 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
532
534 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
535
537 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
538
540 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
541
543 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
544
546 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
547
549 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
550
552 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
553
557 template <class T> inline bool isStableOrSimDecayed(const T& p) {
558 const auto vertex = p->end_vertex();
559 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
560 }
561
563 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
564
566 template <class T> inline bool isSpecialNonInteracting(const T& p) {
567 const int apid = std::abs(p->pdg_id());
568 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
569 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
570 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
571 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
572 return false;
573 }
574
576
577 template <class T> T findMother(T thePart) {
578 auto partOriVert = thePart->production_vertex();
579 if (!partOriVert) return nullptr;
580
581 long partPDG = thePart->pdg_id();
582 long MotherPDG(0);
583
584 auto MothOriVert = partOriVert;
585 MothOriVert = nullptr;
586 T theMoth(nullptr);
587
588 size_t itr = 0;
589 do {
590 if (itr != 0) partOriVert = MothOriVert;
591 for ( const auto& p : particles_in(partOriVert) ) {
592 theMoth = p;
593 if (!theMoth) continue;
594 MotherPDG = theMoth->pdg_id();
595 MothOriVert = theMoth->production_vertex();
596 if (MotherPDG == partPDG) break;
597 }
598 itr++;
599 if (itr > 100) {
600 break;
601 }
602 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
603 MothOriVert != partOriVert);
604 return theMoth;
605 }
606
608
609 template <class C, class T> T findMatching(C TruthContainer, T p) {
610 T ptrPart = nullptr;
611 if (!p) return ptrPart;
612 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
613 for (T truthParticle : *TruthContainer) {
614 if (HepMC::is_sim_descendant(p,truthParticle)) {
615 ptrPart = truthParticle;
616 break;
617 }
618 }
619 }
620 else {
621 for (T truthParticle : TruthContainer) {
622 if (HepMC::is_sim_descendant(p,truthParticle)) {
623 ptrPart = truthParticle;
624 break;
625 }
626 }
627 }
628 return ptrPart;
629 }
631
632 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
633 auto prodVtx = thePart->production_vertex();
634 if (!prodVtx) return;
635 for (const auto& theMother: prodVtx->particles_in()) {
636 if (!theMother) continue;
637 allancestors.insert(theMother);
638 findParticleAncestors(theMother, allancestors);
639 }
640 }
641
643
644 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
645 auto endVtx = thePart->end_vertex();
646 if (!endVtx) return;
647 for (const auto& theDaughter: endVtx->particles_out()) {
648 if (!theDaughter) continue;
649 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
650 allstabledescendants.insert(theDaughter);
651 }
652 findParticleStableDescendants(theDaughter, allstabledescendants);
653 }
654 }
655
659
660 template <class T> bool isHardScatteringVertex(T pVert) {
661 if (pVert == nullptr) return false;
662 T pV = pVert;
663 int numOfPartIn(0);
664 int pdg(0);
665
666 do {
667 pVert = pV;
668 auto incoming = pVert->particles_in();
669 numOfPartIn = incoming.size();
670 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
671 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
672
673 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
674
675 if (numOfPartIn == 2) {
676 auto incoming = pVert->particles_in();
677 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
678 }
679 return false;
680}
681
685
686 template <class T, class U>
687 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
688 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
689 auto vtx = p->production_vertex();
690 if (!vtx) return false;
691 bool fromHad = false;
692 for ( const auto& parent : particles_in(vtx) ) {
693 if (!parent) continue;
694 // should this really go into parton-level territory?
695 // probably depends where BSM particles are being decayed
696 fromBSM |= isBSM(parent);
697 if (!isPhysical(parent)) return false;
698 fromTau |= isTau(parent);
699 if (isHadron(parent)&&!isBeam(parent)) {
700 if (!hadron) hadron = parent; // assumes linear hadron parentage
701 return true;
702 }
703 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
704 }
705 return fromHad;
706 }
707
710
711 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
712 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
713 decltype(thePart->end_vertex()) pVert(nullptr);
714 if (EndVert != nullptr) {
715 do {
716 bool samePart = false;
717 pVert = nullptr;
718 auto outgoing = EndVert->particles_out();
719 auto incoming = EndVert->particles_in();
720 for (const auto& itrDaug: outgoing) {
721 if (!itrDaug) continue;
722 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
723 // brem on generator level for tau
724 (outgoing.size() == 1 && incoming.size() == 1 &&
726 itrDaug->pdg_id() == thePart->pdg_id()) {
727 samePart = true;
728 pVert = itrDaug->end_vertex();
729 }
730 }
731 if (samePart) EndVert = pVert;
732 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
733 }
734 return EndVert;
735 }
736
738
739 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
740 if (!theVert) return {};
741 decltype(theVert->particles_out()) finalStatePart;
742 auto outgoing = theVert->particles_out();
743 for (const auto& thePart: outgoing) {
744 if (!thePart) continue;
745 finalStatePart.push_back(thePart);
746 if (isStable(thePart)) continue;
747 V pVert = findSimulatedEndVertex(thePart);
748 if (pVert == theVert) break; // to prevent Sherpa loop
749 if (pVert != nullptr) {
750 auto vecPart = findFinalStateParticles<V>(pVert);
751 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
752 }
753 }
754 return finalStatePart;
755 }
756
757}
758#endif

◆ isStable()

template<class T>
bool MC::isStable ( const T & p)
inline

Identify if the particle is stable, i.e. has not decayed.

Definition at line 63 of file HepMCHelpers.h.

◆ isStableOrSimDecayed()

template<class T>
bool MC::isStableOrSimDecayed ( const T & p)
inline

Identify if particle is satble or decayed in simulation.

  • a pathological case of decayed particle w/o end vertex. The decayed particles w/o end vertex might occur in case of simulation of long lived particles in Geant stripped off the decay products. I.e. those particles should be re-decayed later.

Definition at line 83 of file HepMCHelpers.h.

83 {
84 const auto vertex = p->end_vertex();
85 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
86 }

◆ isStrange() [1/2]

template<>
bool MC::isStrange ( const int & p)
inline

Definition at line 178 of file HepMCHelpers.h.

◆ isStrange() [2/2]

template<class T>
bool MC::isStrange ( const T & p)
inline

Definition at line 177 of file HepMCHelpers.h.

◆ isStrangeBaryon()

template<class T>
bool MC::isStrangeBaryon ( const T & p)
inline

Definition at line 934 of file HepMCHelpers.h.

955{
956inline
957auto particles_in (const HepMC::GenVertex* p) {
958 return std::ranges::subrange (p->particles_in_const_begin(),
959 p->particles_in_const_end());
960}
961}
962#endif
963
964namespace MC
965{
966 template <class VTX>
967 auto particles_in (const VTX* p) { return p->particles_in(); }
968 template <class VTX>
969 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
970
971 namespace Pythia8
972 {
974 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
975
976 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
977
978 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
979 }
980
981#include "AtlasPID.h"
982
984 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
985
987 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
988
990 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
991
993 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
994
996 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
997
999 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1000
1002 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1003
1005 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1006
1008 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1009
1011 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1012
1016 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1017 const auto vertex = p->end_vertex();
1018 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1019 }
1020
1022 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1023
1025 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1026 const int apid = std::abs(p->pdg_id());
1027 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1028 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1029 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1030 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1031 return false;
1032 }
1033
1035
1036 template <class T> T findMother(T thePart) {
1037 auto partOriVert = thePart->production_vertex();
1038 if (!partOriVert) return nullptr;
1039
1040 long partPDG = thePart->pdg_id();
1041 long MotherPDG(0);
1042
1043 auto MothOriVert = partOriVert;
1044 MothOriVert = nullptr;
1045 T theMoth(nullptr);
1046
1047 size_t itr = 0;
1048 do {
1049 if (itr != 0) partOriVert = MothOriVert;
1050 for ( const auto& p : particles_in(partOriVert) ) {
1051 theMoth = p;
1052 if (!theMoth) continue;
1053 MotherPDG = theMoth->pdg_id();
1054 MothOriVert = theMoth->production_vertex();
1055 if (MotherPDG == partPDG) break;
1056 }
1057 itr++;
1058 if (itr > 100) {
1059 break;
1060 }
1061 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1062 MothOriVert != partOriVert);
1063 return theMoth;
1064 }
1065
1067
1068 template <class C, class T> T findMatching(C TruthContainer, T p) {
1069 T ptrPart = nullptr;
1070 if (!p) return ptrPart;
1071 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1072 for (T truthParticle : *TruthContainer) {
1073 if (HepMC::is_sim_descendant(p,truthParticle)) {
1074 ptrPart = truthParticle;
1075 break;
1076 }
1077 }
1078 }
1079 else {
1080 for (T truthParticle : TruthContainer) {
1081 if (HepMC::is_sim_descendant(p,truthParticle)) {
1082 ptrPart = truthParticle;
1083 break;
1084 }
1085 }
1086 }
1087 return ptrPart;
1088 }
1090
1091 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1092 auto prodVtx = thePart->production_vertex();
1093 if (!prodVtx) return;
1094 for (const auto& theMother: prodVtx->particles_in()) {
1095 if (!theMother) continue;
1096 allancestors.insert(theMother);
1097 findParticleAncestors(theMother, allancestors);
1098 }
1099 }
1100
1102
1103 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1104 auto endVtx = thePart->end_vertex();
1105 if (!endVtx) return;
1106 for (const auto& theDaughter: endVtx->particles_out()) {
1107 if (!theDaughter) continue;
1108 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1109 allstabledescendants.insert(theDaughter);
1110 }
1111 findParticleStableDescendants(theDaughter, allstabledescendants);
1112 }
1113 }
1114
1118
1119 template <class T> bool isHardScatteringVertex(T pVert) {
1120 if (pVert == nullptr) return false;
1121 T pV = pVert;
1122 int numOfPartIn(0);
1123 int pdg(0);
1124
1125 do {
1126 pVert = pV;
1127 auto incoming = pVert->particles_in();
1128 numOfPartIn = incoming.size();
1129 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1130 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1131
1132 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1133
1134 if (numOfPartIn == 2) {
1135 auto incoming = pVert->particles_in();
1136 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1137 }
1138 return false;
1139}
1140
1144
1145 template <class T, class U>
1146 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1147 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1148 auto vtx = p->production_vertex();
1149 if (!vtx) return false;
1150 bool fromHad = false;
1151 for ( const auto& parent : particles_in(vtx) ) {
1152 if (!parent) continue;
1153 // should this really go into parton-level territory?
1154 // probably depends where BSM particles are being decayed
1155 fromBSM |= isBSM(parent);
1156 if (!isPhysical(parent)) return false;
1157 fromTau |= isTau(parent);
1158 if (isHadron(parent)&&!isBeam(parent)) {
1159 if (!hadron) hadron = parent; // assumes linear hadron parentage
1160 return true;
1161 }
1162 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1163 }
1164 return fromHad;
1165 }
1166
1169
1170 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1171 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1172 decltype(thePart->end_vertex()) pVert(nullptr);
1173 if (EndVert != nullptr) {
1174 do {
1175 bool samePart = false;
1176 pVert = nullptr;
1177 auto outgoing = EndVert->particles_out();
1178 auto incoming = EndVert->particles_in();
1179 for (const auto& itrDaug: outgoing) {
1180 if (!itrDaug) continue;
1181 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1182 // brem on generator level for tau
1183 (outgoing.size() == 1 && incoming.size() == 1 &&
1185 itrDaug->pdg_id() == thePart->pdg_id()) {
1186 samePart = true;
1187 pVert = itrDaug->end_vertex();
1188 }
1189 }
1190 if (samePart) EndVert = pVert;
1191 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1192 }
1193 return EndVert;
1194 }
1195
1197
1198 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1199 if (!theVert) return {};
1200 decltype(theVert->particles_out()) finalStatePart;
1201 auto outgoing = theVert->particles_out();
1202 for (const auto& thePart: outgoing) {
1203 if (!thePart) continue;
1204 finalStatePart.push_back(thePart);
1205 if (isStable(thePart)) continue;
1206 V pVert = findSimulatedEndVertex(thePart);
1207 if (pVert == theVert) break; // to prevent Sherpa loop
1208 if (pVert != nullptr) {
1209 auto vecPart = findFinalStateParticles<V>(pVert);
1210 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1211 }
1212 }
1213 return finalStatePart;
1214 }
1215
1216}
1217#endif

◆ isStrangeHadron()

template<class T>
bool MC::isStrangeHadron ( const T & p)
inline

Definition at line 911 of file HepMCHelpers.h.

932{
933inline
934auto particles_in (const HepMC::GenVertex* p) {
935 return std::ranges::subrange (p->particles_in_const_begin(),
936 p->particles_in_const_end());
937}
938}
939#endif
940
941namespace MC
942{
943 template <class VTX>
944 auto particles_in (const VTX* p) { return p->particles_in(); }
945 template <class VTX>
946 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
947
948 namespace Pythia8
949 {
951 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
952
953 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
954
955 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
956 }
957
958#include "AtlasPID.h"
959
961 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
962
964 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
965
967 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
968
970 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
971
973 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
974
976 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
977
979 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
980
982 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
983
985 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
986
988 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
989
993 template <class T> inline bool isStableOrSimDecayed(const T& p) {
994 const auto vertex = p->end_vertex();
995 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
996 }
997
999 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1000
1002 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1003 const int apid = std::abs(p->pdg_id());
1004 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1005 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1006 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1007 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1008 return false;
1009 }
1010
1012
1013 template <class T> T findMother(T thePart) {
1014 auto partOriVert = thePart->production_vertex();
1015 if (!partOriVert) return nullptr;
1016
1017 long partPDG = thePart->pdg_id();
1018 long MotherPDG(0);
1019
1020 auto MothOriVert = partOriVert;
1021 MothOriVert = nullptr;
1022 T theMoth(nullptr);
1023
1024 size_t itr = 0;
1025 do {
1026 if (itr != 0) partOriVert = MothOriVert;
1027 for ( const auto& p : particles_in(partOriVert) ) {
1028 theMoth = p;
1029 if (!theMoth) continue;
1030 MotherPDG = theMoth->pdg_id();
1031 MothOriVert = theMoth->production_vertex();
1032 if (MotherPDG == partPDG) break;
1033 }
1034 itr++;
1035 if (itr > 100) {
1036 break;
1037 }
1038 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1039 MothOriVert != partOriVert);
1040 return theMoth;
1041 }
1042
1044
1045 template <class C, class T> T findMatching(C TruthContainer, T p) {
1046 T ptrPart = nullptr;
1047 if (!p) return ptrPart;
1048 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1049 for (T truthParticle : *TruthContainer) {
1050 if (HepMC::is_sim_descendant(p,truthParticle)) {
1051 ptrPart = truthParticle;
1052 break;
1053 }
1054 }
1055 }
1056 else {
1057 for (T truthParticle : TruthContainer) {
1058 if (HepMC::is_sim_descendant(p,truthParticle)) {
1059 ptrPart = truthParticle;
1060 break;
1061 }
1062 }
1063 }
1064 return ptrPart;
1065 }
1067
1068 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1069 auto prodVtx = thePart->production_vertex();
1070 if (!prodVtx) return;
1071 for (const auto& theMother: prodVtx->particles_in()) {
1072 if (!theMother) continue;
1073 allancestors.insert(theMother);
1074 findParticleAncestors(theMother, allancestors);
1075 }
1076 }
1077
1079
1080 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1081 auto endVtx = thePart->end_vertex();
1082 if (!endVtx) return;
1083 for (const auto& theDaughter: endVtx->particles_out()) {
1084 if (!theDaughter) continue;
1085 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1086 allstabledescendants.insert(theDaughter);
1087 }
1088 findParticleStableDescendants(theDaughter, allstabledescendants);
1089 }
1090 }
1091
1095
1096 template <class T> bool isHardScatteringVertex(T pVert) {
1097 if (pVert == nullptr) return false;
1098 T pV = pVert;
1099 int numOfPartIn(0);
1100 int pdg(0);
1101
1102 do {
1103 pVert = pV;
1104 auto incoming = pVert->particles_in();
1105 numOfPartIn = incoming.size();
1106 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1107 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1108
1109 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1110
1111 if (numOfPartIn == 2) {
1112 auto incoming = pVert->particles_in();
1113 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1114 }
1115 return false;
1116}
1117
1121
1122 template <class T, class U>
1123 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1124 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1125 auto vtx = p->production_vertex();
1126 if (!vtx) return false;
1127 bool fromHad = false;
1128 for ( const auto& parent : particles_in(vtx) ) {
1129 if (!parent) continue;
1130 // should this really go into parton-level territory?
1131 // probably depends where BSM particles are being decayed
1132 fromBSM |= isBSM(parent);
1133 if (!isPhysical(parent)) return false;
1134 fromTau |= isTau(parent);
1135 if (isHadron(parent)&&!isBeam(parent)) {
1136 if (!hadron) hadron = parent; // assumes linear hadron parentage
1137 return true;
1138 }
1139 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1140 }
1141 return fromHad;
1142 }
1143
1146
1147 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1148 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1149 decltype(thePart->end_vertex()) pVert(nullptr);
1150 if (EndVert != nullptr) {
1151 do {
1152 bool samePart = false;
1153 pVert = nullptr;
1154 auto outgoing = EndVert->particles_out();
1155 auto incoming = EndVert->particles_in();
1156 for (const auto& itrDaug: outgoing) {
1157 if (!itrDaug) continue;
1158 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1159 // brem on generator level for tau
1160 (outgoing.size() == 1 && incoming.size() == 1 &&
1162 itrDaug->pdg_id() == thePart->pdg_id()) {
1163 samePart = true;
1164 pVert = itrDaug->end_vertex();
1165 }
1166 }
1167 if (samePart) EndVert = pVert;
1168 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1169 }
1170 return EndVert;
1171 }
1172
1174
1175 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1176 if (!theVert) return {};
1177 decltype(theVert->particles_out()) finalStatePart;
1178 auto outgoing = theVert->particles_out();
1179 for (const auto& thePart: outgoing) {
1180 if (!thePart) continue;
1181 finalStatePart.push_back(thePart);
1182 if (isStable(thePart)) continue;
1183 V pVert = findSimulatedEndVertex(thePart);
1184 if (pVert == theVert) break; // to prevent Sherpa loop
1185 if (pVert != nullptr) {
1186 auto vecPart = findFinalStateParticles<V>(pVert);
1187 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1188 }
1189 }
1190 return finalStatePart;
1191 }
1192
1193}
1194#endif

◆ isStrangeMeson()

template<class T>
bool MC::isStrangeMeson ( const T & p)
inline

Definition at line 918 of file HepMCHelpers.h.

939{
940inline
941auto particles_in (const HepMC::GenVertex* p) {
942 return std::ranges::subrange (p->particles_in_const_begin(),
943 p->particles_in_const_end());
944}
945}
946#endif
947
948namespace MC
949{
950 template <class VTX>
951 auto particles_in (const VTX* p) { return p->particles_in(); }
952 template <class VTX>
953 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
954
955 namespace Pythia8
956 {
958 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
959
960 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
961
962 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
963 }
964
965#include "AtlasPID.h"
966
968 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
969
971 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
972
974 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
975
977 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
978
980 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
981
983 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
984
986 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
987
989 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
990
992 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
993
995 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
996
1000 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1001 const auto vertex = p->end_vertex();
1002 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1003 }
1004
1006 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1007
1009 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1010 const int apid = std::abs(p->pdg_id());
1011 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1012 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1013 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1014 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1015 return false;
1016 }
1017
1019
1020 template <class T> T findMother(T thePart) {
1021 auto partOriVert = thePart->production_vertex();
1022 if (!partOriVert) return nullptr;
1023
1024 long partPDG = thePart->pdg_id();
1025 long MotherPDG(0);
1026
1027 auto MothOriVert = partOriVert;
1028 MothOriVert = nullptr;
1029 T theMoth(nullptr);
1030
1031 size_t itr = 0;
1032 do {
1033 if (itr != 0) partOriVert = MothOriVert;
1034 for ( const auto& p : particles_in(partOriVert) ) {
1035 theMoth = p;
1036 if (!theMoth) continue;
1037 MotherPDG = theMoth->pdg_id();
1038 MothOriVert = theMoth->production_vertex();
1039 if (MotherPDG == partPDG) break;
1040 }
1041 itr++;
1042 if (itr > 100) {
1043 break;
1044 }
1045 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1046 MothOriVert != partOriVert);
1047 return theMoth;
1048 }
1049
1051
1052 template <class C, class T> T findMatching(C TruthContainer, T p) {
1053 T ptrPart = nullptr;
1054 if (!p) return ptrPart;
1055 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1056 for (T truthParticle : *TruthContainer) {
1057 if (HepMC::is_sim_descendant(p,truthParticle)) {
1058 ptrPart = truthParticle;
1059 break;
1060 }
1061 }
1062 }
1063 else {
1064 for (T truthParticle : TruthContainer) {
1065 if (HepMC::is_sim_descendant(p,truthParticle)) {
1066 ptrPart = truthParticle;
1067 break;
1068 }
1069 }
1070 }
1071 return ptrPart;
1072 }
1074
1075 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1076 auto prodVtx = thePart->production_vertex();
1077 if (!prodVtx) return;
1078 for (const auto& theMother: prodVtx->particles_in()) {
1079 if (!theMother) continue;
1080 allancestors.insert(theMother);
1081 findParticleAncestors(theMother, allancestors);
1082 }
1083 }
1084
1086
1087 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1088 auto endVtx = thePart->end_vertex();
1089 if (!endVtx) return;
1090 for (const auto& theDaughter: endVtx->particles_out()) {
1091 if (!theDaughter) continue;
1092 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1093 allstabledescendants.insert(theDaughter);
1094 }
1095 findParticleStableDescendants(theDaughter, allstabledescendants);
1096 }
1097 }
1098
1102
1103 template <class T> bool isHardScatteringVertex(T pVert) {
1104 if (pVert == nullptr) return false;
1105 T pV = pVert;
1106 int numOfPartIn(0);
1107 int pdg(0);
1108
1109 do {
1110 pVert = pV;
1111 auto incoming = pVert->particles_in();
1112 numOfPartIn = incoming.size();
1113 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1114 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1115
1116 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1117
1118 if (numOfPartIn == 2) {
1119 auto incoming = pVert->particles_in();
1120 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1121 }
1122 return false;
1123}
1124
1128
1129 template <class T, class U>
1130 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1131 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1132 auto vtx = p->production_vertex();
1133 if (!vtx) return false;
1134 bool fromHad = false;
1135 for ( const auto& parent : particles_in(vtx) ) {
1136 if (!parent) continue;
1137 // should this really go into parton-level territory?
1138 // probably depends where BSM particles are being decayed
1139 fromBSM |= isBSM(parent);
1140 if (!isPhysical(parent)) return false;
1141 fromTau |= isTau(parent);
1142 if (isHadron(parent)&&!isBeam(parent)) {
1143 if (!hadron) hadron = parent; // assumes linear hadron parentage
1144 return true;
1145 }
1146 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1147 }
1148 return fromHad;
1149 }
1150
1153
1154 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1155 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1156 decltype(thePart->end_vertex()) pVert(nullptr);
1157 if (EndVert != nullptr) {
1158 do {
1159 bool samePart = false;
1160 pVert = nullptr;
1161 auto outgoing = EndVert->particles_out();
1162 auto incoming = EndVert->particles_in();
1163 for (const auto& itrDaug: outgoing) {
1164 if (!itrDaug) continue;
1165 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1166 // brem on generator level for tau
1167 (outgoing.size() == 1 && incoming.size() == 1 &&
1169 itrDaug->pdg_id() == thePart->pdg_id()) {
1170 samePart = true;
1171 pVert = itrDaug->end_vertex();
1172 }
1173 }
1174 if (samePart) EndVert = pVert;
1175 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1176 }
1177 return EndVert;
1178 }
1179
1181
1182 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1183 if (!theVert) return {};
1184 decltype(theVert->particles_out()) finalStatePart;
1185 auto outgoing = theVert->particles_out();
1186 for (const auto& thePart: outgoing) {
1187 if (!thePart) continue;
1188 finalStatePart.push_back(thePart);
1189 if (isStable(thePart)) continue;
1190 V pVert = findSimulatedEndVertex(thePart);
1191 if (pVert == theVert) break; // to prevent Sherpa loop
1192 if (pVert != nullptr) {
1193 auto vecPart = findFinalStateParticles<V>(pVert);
1194 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1195 }
1196 }
1197 return finalStatePart;
1198 }
1199
1200}
1201#endif

◆ isStrongInteracting() [1/2]

template<>
bool MC::isStrongInteracting ( const int & p)
inline

Definition at line 1180 of file HepMCHelpers.h.

1201{
1202inline
1203auto particles_in (const HepMC::GenVertex* p) {
1204 return std::ranges::subrange (p->particles_in_const_begin(),
1205 p->particles_in_const_end());
1206}
1207}
1208#endif
1209
1210namespace MC
1211{
1212 template <class VTX>
1213 auto particles_in (const VTX* p) { return p->particles_in(); }
1214 template <class VTX>
1215 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1216
1217 namespace Pythia8
1218 {
1220 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1221
1222 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1223
1224 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1225 }
1226
1227#include "AtlasPID.h"
1228
1230 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1231
1233 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1234
1236 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1237
1239 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1240
1242 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1243
1245 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1246
1248 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1249
1251 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1252
1254 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1255
1257 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1258
1262 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1263 const auto vertex = p->end_vertex();
1264 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1265 }
1266
1268 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1269
1271 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1272 const int apid = std::abs(p->pdg_id());
1273 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1274 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1275 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1276 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1277 return false;
1278 }
1279
1281
1282 template <class T> T findMother(T thePart) {
1283 auto partOriVert = thePart->production_vertex();
1284 if (!partOriVert) return nullptr;
1285
1286 long partPDG = thePart->pdg_id();
1287 long MotherPDG(0);
1288
1289 auto MothOriVert = partOriVert;
1290 MothOriVert = nullptr;
1291 T theMoth(nullptr);
1292
1293 size_t itr = 0;
1294 do {
1295 if (itr != 0) partOriVert = MothOriVert;
1296 for ( const auto& p : particles_in(partOriVert) ) {
1297 theMoth = p;
1298 if (!theMoth) continue;
1299 MotherPDG = theMoth->pdg_id();
1300 MothOriVert = theMoth->production_vertex();
1301 if (MotherPDG == partPDG) break;
1302 }
1303 itr++;
1304 if (itr > 100) {
1305 break;
1306 }
1307 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1308 MothOriVert != partOriVert);
1309 return theMoth;
1310 }
1311
1313
1314 template <class C, class T> T findMatching(C TruthContainer, T p) {
1315 T ptrPart = nullptr;
1316 if (!p) return ptrPart;
1317 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1318 for (T truthParticle : *TruthContainer) {
1319 if (HepMC::is_sim_descendant(p,truthParticle)) {
1320 ptrPart = truthParticle;
1321 break;
1322 }
1323 }
1324 }
1325 else {
1326 for (T truthParticle : TruthContainer) {
1327 if (HepMC::is_sim_descendant(p,truthParticle)) {
1328 ptrPart = truthParticle;
1329 break;
1330 }
1331 }
1332 }
1333 return ptrPart;
1334 }
1336
1337 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1338 auto prodVtx = thePart->production_vertex();
1339 if (!prodVtx) return;
1340 for (const auto& theMother: prodVtx->particles_in()) {
1341 if (!theMother) continue;
1342 allancestors.insert(theMother);
1343 findParticleAncestors(theMother, allancestors);
1344 }
1345 }
1346
1348
1349 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1350 auto endVtx = thePart->end_vertex();
1351 if (!endVtx) return;
1352 for (const auto& theDaughter: endVtx->particles_out()) {
1353 if (!theDaughter) continue;
1354 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1355 allstabledescendants.insert(theDaughter);
1356 }
1357 findParticleStableDescendants(theDaughter, allstabledescendants);
1358 }
1359 }
1360
1364
1365 template <class T> bool isHardScatteringVertex(T pVert) {
1366 if (pVert == nullptr) return false;
1367 T pV = pVert;
1368 int numOfPartIn(0);
1369 int pdg(0);
1370
1371 do {
1372 pVert = pV;
1373 auto incoming = pVert->particles_in();
1374 numOfPartIn = incoming.size();
1375 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1376 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1377
1378 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1379
1380 if (numOfPartIn == 2) {
1381 auto incoming = pVert->particles_in();
1382 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1383 }
1384 return false;
1385}
1386
1390
1391 template <class T, class U>
1392 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1393 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1394 auto vtx = p->production_vertex();
1395 if (!vtx) return false;
1396 bool fromHad = false;
1397 for ( const auto& parent : particles_in(vtx) ) {
1398 if (!parent) continue;
1399 // should this really go into parton-level territory?
1400 // probably depends where BSM particles are being decayed
1401 fromBSM |= isBSM(parent);
1402 if (!isPhysical(parent)) return false;
1403 fromTau |= isTau(parent);
1404 if (isHadron(parent)&&!isBeam(parent)) {
1405 if (!hadron) hadron = parent; // assumes linear hadron parentage
1406 return true;
1407 }
1408 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1409 }
1410 return fromHad;
1411 }
1412
1415
1416 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1417 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1418 decltype(thePart->end_vertex()) pVert(nullptr);
1419 if (EndVert != nullptr) {
1420 do {
1421 bool samePart = false;
1422 pVert = nullptr;
1423 auto outgoing = EndVert->particles_out();
1424 auto incoming = EndVert->particles_in();
1425 for (const auto& itrDaug: outgoing) {
1426 if (!itrDaug) continue;
1427 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1428 // brem on generator level for tau
1429 (outgoing.size() == 1 && incoming.size() == 1 &&
1431 itrDaug->pdg_id() == thePart->pdg_id()) {
1432 samePart = true;
1433 pVert = itrDaug->end_vertex();
1434 }
1435 }
1436 if (samePart) EndVert = pVert;
1437 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1438 }
1439 return EndVert;
1440 }
1441
1443
1444 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1445 if (!theVert) return {};
1446 decltype(theVert->particles_out()) finalStatePart;
1447 auto outgoing = theVert->particles_out();
1448 for (const auto& thePart: outgoing) {
1449 if (!thePart) continue;
1450 finalStatePart.push_back(thePart);
1451 if (isStable(thePart)) continue;
1452 V pVert = findSimulatedEndVertex(thePart);
1453 if (pVert == theVert) break; // to prevent Sherpa loop
1454 if (pVert != nullptr) {
1455 auto vecPart = findFinalStateParticles<V>(pVert);
1456 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1457 }
1458 }
1459 return finalStatePart;
1460 }
1461
1462}
1463#endif

◆ isStrongInteracting() [2/2]

template<class T>
bool MC::isStrongInteracting ( const T & p)
inline

Definition at line 1179 of file HepMCHelpers.h.

1200{
1201inline
1202auto particles_in (const HepMC::GenVertex* p) {
1203 return std::ranges::subrange (p->particles_in_const_begin(),
1204 p->particles_in_const_end());
1205}
1206}
1207#endif
1208
1209namespace MC
1210{
1211 template <class VTX>
1212 auto particles_in (const VTX* p) { return p->particles_in(); }
1213 template <class VTX>
1214 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1215
1216 namespace Pythia8
1217 {
1219 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1220
1221 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1222
1223 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1224 }
1225
1226#include "AtlasPID.h"
1227
1229 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1230
1232 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1233
1235 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1236
1238 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1239
1241 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1242
1244 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1245
1247 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1248
1250 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1251
1253 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1254
1256 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1257
1261 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1262 const auto vertex = p->end_vertex();
1263 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1264 }
1265
1267 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1268
1270 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1271 const int apid = std::abs(p->pdg_id());
1272 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1273 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1274 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1275 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1276 return false;
1277 }
1278
1280
1281 template <class T> T findMother(T thePart) {
1282 auto partOriVert = thePart->production_vertex();
1283 if (!partOriVert) return nullptr;
1284
1285 long partPDG = thePart->pdg_id();
1286 long MotherPDG(0);
1287
1288 auto MothOriVert = partOriVert;
1289 MothOriVert = nullptr;
1290 T theMoth(nullptr);
1291
1292 size_t itr = 0;
1293 do {
1294 if (itr != 0) partOriVert = MothOriVert;
1295 for ( const auto& p : particles_in(partOriVert) ) {
1296 theMoth = p;
1297 if (!theMoth) continue;
1298 MotherPDG = theMoth->pdg_id();
1299 MothOriVert = theMoth->production_vertex();
1300 if (MotherPDG == partPDG) break;
1301 }
1302 itr++;
1303 if (itr > 100) {
1304 break;
1305 }
1306 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1307 MothOriVert != partOriVert);
1308 return theMoth;
1309 }
1310
1312
1313 template <class C, class T> T findMatching(C TruthContainer, T p) {
1314 T ptrPart = nullptr;
1315 if (!p) return ptrPart;
1316 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1317 for (T truthParticle : *TruthContainer) {
1318 if (HepMC::is_sim_descendant(p,truthParticle)) {
1319 ptrPart = truthParticle;
1320 break;
1321 }
1322 }
1323 }
1324 else {
1325 for (T truthParticle : TruthContainer) {
1326 if (HepMC::is_sim_descendant(p,truthParticle)) {
1327 ptrPart = truthParticle;
1328 break;
1329 }
1330 }
1331 }
1332 return ptrPart;
1333 }
1335
1336 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1337 auto prodVtx = thePart->production_vertex();
1338 if (!prodVtx) return;
1339 for (const auto& theMother: prodVtx->particles_in()) {
1340 if (!theMother) continue;
1341 allancestors.insert(theMother);
1342 findParticleAncestors(theMother, allancestors);
1343 }
1344 }
1345
1347
1348 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1349 auto endVtx = thePart->end_vertex();
1350 if (!endVtx) return;
1351 for (const auto& theDaughter: endVtx->particles_out()) {
1352 if (!theDaughter) continue;
1353 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1354 allstabledescendants.insert(theDaughter);
1355 }
1356 findParticleStableDescendants(theDaughter, allstabledescendants);
1357 }
1358 }
1359
1363
1364 template <class T> bool isHardScatteringVertex(T pVert) {
1365 if (pVert == nullptr) return false;
1366 T pV = pVert;
1367 int numOfPartIn(0);
1368 int pdg(0);
1369
1370 do {
1371 pVert = pV;
1372 auto incoming = pVert->particles_in();
1373 numOfPartIn = incoming.size();
1374 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1375 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1376
1377 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1378
1379 if (numOfPartIn == 2) {
1380 auto incoming = pVert->particles_in();
1381 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1382 }
1383 return false;
1384}
1385
1389
1390 template <class T, class U>
1391 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1392 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1393 auto vtx = p->production_vertex();
1394 if (!vtx) return false;
1395 bool fromHad = false;
1396 for ( const auto& parent : particles_in(vtx) ) {
1397 if (!parent) continue;
1398 // should this really go into parton-level territory?
1399 // probably depends where BSM particles are being decayed
1400 fromBSM |= isBSM(parent);
1401 if (!isPhysical(parent)) return false;
1402 fromTau |= isTau(parent);
1403 if (isHadron(parent)&&!isBeam(parent)) {
1404 if (!hadron) hadron = parent; // assumes linear hadron parentage
1405 return true;
1406 }
1407 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1408 }
1409 return fromHad;
1410 }
1411
1414
1415 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1416 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1417 decltype(thePart->end_vertex()) pVert(nullptr);
1418 if (EndVert != nullptr) {
1419 do {
1420 bool samePart = false;
1421 pVert = nullptr;
1422 auto outgoing = EndVert->particles_out();
1423 auto incoming = EndVert->particles_in();
1424 for (const auto& itrDaug: outgoing) {
1425 if (!itrDaug) continue;
1426 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1427 // brem on generator level for tau
1428 (outgoing.size() == 1 && incoming.size() == 1 &&
1430 itrDaug->pdg_id() == thePart->pdg_id()) {
1431 samePart = true;
1432 pVert = itrDaug->end_vertex();
1433 }
1434 }
1435 if (samePart) EndVert = pVert;
1436 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1437 }
1438 return EndVert;
1439 }
1440
1442
1443 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1444 if (!theVert) return {};
1445 decltype(theVert->particles_out()) finalStatePart;
1446 auto outgoing = theVert->particles_out();
1447 for (const auto& thePart: outgoing) {
1448 if (!thePart) continue;
1449 finalStatePart.push_back(thePart);
1450 if (isStable(thePart)) continue;
1451 V pVert = findSimulatedEndVertex(thePart);
1452 if (pVert == theVert) break; // to prevent Sherpa loop
1453 if (pVert != nullptr) {
1454 auto vecPart = findFinalStateParticles<V>(pVert);
1455 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1456 }
1457 }
1458 return finalStatePart;
1459 }
1460
1461}
1462#endif

◆ isSuperpartner() [1/3]

template<>
bool MC::isSuperpartner ( const DecodedPID & p)
inline

Definition at line 514 of file HepMCHelpers.h.

535 {
536inline
537auto particles_in (const HepMC::GenVertex* p) {
538 return std::ranges::subrange (p->particles_in_const_begin(),
539 p->particles_in_const_end());
540}
541}
542#endif
543
544namespace MC
545{
546 template <class VTX>
547 auto particles_in (const VTX* p) { return p->particles_in(); }
548 template <class VTX>
549 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
550
551 namespace Pythia8
552 {
554 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
555
556 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
557
558 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
559 }
560
561#include "AtlasPID.h"
562
564 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
565
567 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
568
570 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
571
573 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
574
576 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
577
579 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
580
582 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
583
585 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
586
588 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
589
591 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
592
596 template <class T> inline bool isStableOrSimDecayed(const T& p) {
597 const auto vertex = p->end_vertex();
598 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
599 }
600
602 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
603
605 template <class T> inline bool isSpecialNonInteracting(const T& p) {
606 const int apid = std::abs(p->pdg_id());
607 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
608 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
609 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
610 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
611 return false;
612 }
613
615
616 template <class T> T findMother(T thePart) {
617 auto partOriVert = thePart->production_vertex();
618 if (!partOriVert) return nullptr;
619
620 long partPDG = thePart->pdg_id();
621 long MotherPDG(0);
622
623 auto MothOriVert = partOriVert;
624 MothOriVert = nullptr;
625 T theMoth(nullptr);
626
627 size_t itr = 0;
628 do {
629 if (itr != 0) partOriVert = MothOriVert;
630 for ( const auto& p : particles_in(partOriVert) ) {
631 theMoth = p;
632 if (!theMoth) continue;
633 MotherPDG = theMoth->pdg_id();
634 MothOriVert = theMoth->production_vertex();
635 if (MotherPDG == partPDG) break;
636 }
637 itr++;
638 if (itr > 100) {
639 break;
640 }
641 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
642 MothOriVert != partOriVert);
643 return theMoth;
644 }
645
647
648 template <class C, class T> T findMatching(C TruthContainer, T p) {
649 T ptrPart = nullptr;
650 if (!p) return ptrPart;
651 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
652 for (T truthParticle : *TruthContainer) {
653 if (HepMC::is_sim_descendant(p,truthParticle)) {
654 ptrPart = truthParticle;
655 break;
656 }
657 }
658 }
659 else {
660 for (T truthParticle : TruthContainer) {
661 if (HepMC::is_sim_descendant(p,truthParticle)) {
662 ptrPart = truthParticle;
663 break;
664 }
665 }
666 }
667 return ptrPart;
668 }
670
671 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
672 auto prodVtx = thePart->production_vertex();
673 if (!prodVtx) return;
674 for (const auto& theMother: prodVtx->particles_in()) {
675 if (!theMother) continue;
676 allancestors.insert(theMother);
677 findParticleAncestors(theMother, allancestors);
678 }
679 }
680
682
683 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
684 auto endVtx = thePart->end_vertex();
685 if (!endVtx) return;
686 for (const auto& theDaughter: endVtx->particles_out()) {
687 if (!theDaughter) continue;
688 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
689 allstabledescendants.insert(theDaughter);
690 }
691 findParticleStableDescendants(theDaughter, allstabledescendants);
692 }
693 }
694
698
699 template <class T> bool isHardScatteringVertex(T pVert) {
700 if (pVert == nullptr) return false;
701 T pV = pVert;
702 int numOfPartIn(0);
703 int pdg(0);
704
705 do {
706 pVert = pV;
707 auto incoming = pVert->particles_in();
708 numOfPartIn = incoming.size();
709 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
710 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
711
712 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
713
714 if (numOfPartIn == 2) {
715 auto incoming = pVert->particles_in();
716 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
717 }
718 return false;
719}
720
724
725 template <class T, class U>
726 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
727 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
728 auto vtx = p->production_vertex();
729 if (!vtx) return false;
730 bool fromHad = false;
731 for ( const auto& parent : particles_in(vtx) ) {
732 if (!parent) continue;
733 // should this really go into parton-level territory?
734 // probably depends where BSM particles are being decayed
735 fromBSM |= isBSM(parent);
736 if (!isPhysical(parent)) return false;
737 fromTau |= isTau(parent);
738 if (isHadron(parent)&&!isBeam(parent)) {
739 if (!hadron) hadron = parent; // assumes linear hadron parentage
740 return true;
741 }
742 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
743 }
744 return fromHad;
745 }
746
749
750 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
751 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
752 decltype(thePart->end_vertex()) pVert(nullptr);
753 if (EndVert != nullptr) {
754 do {
755 bool samePart = false;
756 pVert = nullptr;
757 auto outgoing = EndVert->particles_out();
758 auto incoming = EndVert->particles_in();
759 for (const auto& itrDaug: outgoing) {
760 if (!itrDaug) continue;
761 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
762 // brem on generator level for tau
763 (outgoing.size() == 1 && incoming.size() == 1 &&
765 itrDaug->pdg_id() == thePart->pdg_id()) {
766 samePart = true;
767 pVert = itrDaug->end_vertex();
768 }
769 }
770 if (samePart) EndVert = pVert;
771 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
772 }
773 return EndVert;
774 }
775
777
778 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
779 if (!theVert) return {};
780 decltype(theVert->particles_out()) finalStatePart;
781 auto outgoing = theVert->particles_out();
782 for (const auto& thePart: outgoing) {
783 if (!thePart) continue;
784 finalStatePart.push_back(thePart);
785 if (isStable(thePart)) continue;
786 V pVert = findSimulatedEndVertex(thePart);
787 if (pVert == theVert) break; // to prevent Sherpa loop
788 if (pVert != nullptr) {
789 auto vecPart = findFinalStateParticles<V>(pVert);
790 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
791 }
792 }
793 return finalStatePart;
794 }
795
796}
797#endif

◆ isSuperpartner() [2/3]

template<>
bool MC::isSuperpartner ( const int & p)
inline

Definition at line 517 of file HepMCHelpers.h.

538{
539inline
540auto particles_in (const HepMC::GenVertex* p) {
541 return std::ranges::subrange (p->particles_in_const_begin(),
542 p->particles_in_const_end());
543}
544}
545#endif
546
547namespace MC
548{
549 template <class VTX>
550 auto particles_in (const VTX* p) { return p->particles_in(); }
551 template <class VTX>
552 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
553
554 namespace Pythia8
555 {
557 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
558
559 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
560
561 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
562 }
563
564#include "AtlasPID.h"
565
567 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
568
570 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
571
573 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
574
576 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
577
579 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
580
582 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
583
585 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
586
588 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
589
591 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
592
594 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
595
599 template <class T> inline bool isStableOrSimDecayed(const T& p) {
600 const auto vertex = p->end_vertex();
601 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
602 }
603
605 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
606
608 template <class T> inline bool isSpecialNonInteracting(const T& p) {
609 const int apid = std::abs(p->pdg_id());
610 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
611 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
612 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
613 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
614 return false;
615 }
616
618
619 template <class T> T findMother(T thePart) {
620 auto partOriVert = thePart->production_vertex();
621 if (!partOriVert) return nullptr;
622
623 long partPDG = thePart->pdg_id();
624 long MotherPDG(0);
625
626 auto MothOriVert = partOriVert;
627 MothOriVert = nullptr;
628 T theMoth(nullptr);
629
630 size_t itr = 0;
631 do {
632 if (itr != 0) partOriVert = MothOriVert;
633 for ( const auto& p : particles_in(partOriVert) ) {
634 theMoth = p;
635 if (!theMoth) continue;
636 MotherPDG = theMoth->pdg_id();
637 MothOriVert = theMoth->production_vertex();
638 if (MotherPDG == partPDG) break;
639 }
640 itr++;
641 if (itr > 100) {
642 break;
643 }
644 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
645 MothOriVert != partOriVert);
646 return theMoth;
647 }
648
650
651 template <class C, class T> T findMatching(C TruthContainer, T p) {
652 T ptrPart = nullptr;
653 if (!p) return ptrPart;
654 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
655 for (T truthParticle : *TruthContainer) {
656 if (HepMC::is_sim_descendant(p,truthParticle)) {
657 ptrPart = truthParticle;
658 break;
659 }
660 }
661 }
662 else {
663 for (T truthParticle : TruthContainer) {
664 if (HepMC::is_sim_descendant(p,truthParticle)) {
665 ptrPart = truthParticle;
666 break;
667 }
668 }
669 }
670 return ptrPart;
671 }
673
674 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
675 auto prodVtx = thePart->production_vertex();
676 if (!prodVtx) return;
677 for (const auto& theMother: prodVtx->particles_in()) {
678 if (!theMother) continue;
679 allancestors.insert(theMother);
680 findParticleAncestors(theMother, allancestors);
681 }
682 }
683
685
686 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
687 auto endVtx = thePart->end_vertex();
688 if (!endVtx) return;
689 for (const auto& theDaughter: endVtx->particles_out()) {
690 if (!theDaughter) continue;
691 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
692 allstabledescendants.insert(theDaughter);
693 }
694 findParticleStableDescendants(theDaughter, allstabledescendants);
695 }
696 }
697
701
702 template <class T> bool isHardScatteringVertex(T pVert) {
703 if (pVert == nullptr) return false;
704 T pV = pVert;
705 int numOfPartIn(0);
706 int pdg(0);
707
708 do {
709 pVert = pV;
710 auto incoming = pVert->particles_in();
711 numOfPartIn = incoming.size();
712 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
713 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
714
715 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
716
717 if (numOfPartIn == 2) {
718 auto incoming = pVert->particles_in();
719 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
720 }
721 return false;
722}
723
727
728 template <class T, class U>
729 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
730 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
731 auto vtx = p->production_vertex();
732 if (!vtx) return false;
733 bool fromHad = false;
734 for ( const auto& parent : particles_in(vtx) ) {
735 if (!parent) continue;
736 // should this really go into parton-level territory?
737 // probably depends where BSM particles are being decayed
738 fromBSM |= isBSM(parent);
739 if (!isPhysical(parent)) return false;
740 fromTau |= isTau(parent);
741 if (isHadron(parent)&&!isBeam(parent)) {
742 if (!hadron) hadron = parent; // assumes linear hadron parentage
743 return true;
744 }
745 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
746 }
747 return fromHad;
748 }
749
752
753 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
754 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
755 decltype(thePart->end_vertex()) pVert(nullptr);
756 if (EndVert != nullptr) {
757 do {
758 bool samePart = false;
759 pVert = nullptr;
760 auto outgoing = EndVert->particles_out();
761 auto incoming = EndVert->particles_in();
762 for (const auto& itrDaug: outgoing) {
763 if (!itrDaug) continue;
764 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
765 // brem on generator level for tau
766 (outgoing.size() == 1 && incoming.size() == 1 &&
768 itrDaug->pdg_id() == thePart->pdg_id()) {
769 samePart = true;
770 pVert = itrDaug->end_vertex();
771 }
772 }
773 if (samePart) EndVert = pVert;
774 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
775 }
776 return EndVert;
777 }
778
780
781 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
782 if (!theVert) return {};
783 decltype(theVert->particles_out()) finalStatePart;
784 auto outgoing = theVert->particles_out();
785 for (const auto& thePart: outgoing) {
786 if (!thePart) continue;
787 finalStatePart.push_back(thePart);
788 if (isStable(thePart)) continue;
789 V pVert = findSimulatedEndVertex(thePart);
790 if (pVert == theVert) break; // to prevent Sherpa loop
791 if (pVert != nullptr) {
792 auto vecPart = findFinalStateParticles<V>(pVert);
793 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
794 }
795 }
796 return finalStatePart;
797 }
798
799}
800#endif

◆ isSuperpartner() [3/3]

template<class T>
bool MC::isSuperpartner ( const T & p)
inline

Definition at line 513 of file HepMCHelpers.h.

534{
535inline
536auto particles_in (const HepMC::GenVertex* p) {
537 return std::ranges::subrange (p->particles_in_const_begin(),
538 p->particles_in_const_end());
539}
540}
541#endif
542
543namespace MC
544{
545 template <class VTX>
546 auto particles_in (const VTX* p) { return p->particles_in(); }
547 template <class VTX>
548 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
549
550 namespace Pythia8
551 {
553 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
554
555 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
556
557 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
558 }
559
560#include "AtlasPID.h"
561
563 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
564
566 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
567
569 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
570
572 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
573
575 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
576
578 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
579
581 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
582
584 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
585
587 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
588
590 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
591
595 template <class T> inline bool isStableOrSimDecayed(const T& p) {
596 const auto vertex = p->end_vertex();
597 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
598 }
599
601 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
602
604 template <class T> inline bool isSpecialNonInteracting(const T& p) {
605 const int apid = std::abs(p->pdg_id());
606 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
607 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
608 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
609 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
610 return false;
611 }
612
614
615 template <class T> T findMother(T thePart) {
616 auto partOriVert = thePart->production_vertex();
617 if (!partOriVert) return nullptr;
618
619 long partPDG = thePart->pdg_id();
620 long MotherPDG(0);
621
622 auto MothOriVert = partOriVert;
623 MothOriVert = nullptr;
624 T theMoth(nullptr);
625
626 size_t itr = 0;
627 do {
628 if (itr != 0) partOriVert = MothOriVert;
629 for ( const auto& p : particles_in(partOriVert) ) {
630 theMoth = p;
631 if (!theMoth) continue;
632 MotherPDG = theMoth->pdg_id();
633 MothOriVert = theMoth->production_vertex();
634 if (MotherPDG == partPDG) break;
635 }
636 itr++;
637 if (itr > 100) {
638 break;
639 }
640 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
641 MothOriVert != partOriVert);
642 return theMoth;
643 }
644
646
647 template <class C, class T> T findMatching(C TruthContainer, T p) {
648 T ptrPart = nullptr;
649 if (!p) return ptrPart;
650 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
651 for (T truthParticle : *TruthContainer) {
652 if (HepMC::is_sim_descendant(p,truthParticle)) {
653 ptrPart = truthParticle;
654 break;
655 }
656 }
657 }
658 else {
659 for (T truthParticle : TruthContainer) {
660 if (HepMC::is_sim_descendant(p,truthParticle)) {
661 ptrPart = truthParticle;
662 break;
663 }
664 }
665 }
666 return ptrPart;
667 }
669
670 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
671 auto prodVtx = thePart->production_vertex();
672 if (!prodVtx) return;
673 for (const auto& theMother: prodVtx->particles_in()) {
674 if (!theMother) continue;
675 allancestors.insert(theMother);
676 findParticleAncestors(theMother, allancestors);
677 }
678 }
679
681
682 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
683 auto endVtx = thePart->end_vertex();
684 if (!endVtx) return;
685 for (const auto& theDaughter: endVtx->particles_out()) {
686 if (!theDaughter) continue;
687 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
688 allstabledescendants.insert(theDaughter);
689 }
690 findParticleStableDescendants(theDaughter, allstabledescendants);
691 }
692 }
693
697
698 template <class T> bool isHardScatteringVertex(T pVert) {
699 if (pVert == nullptr) return false;
700 T pV = pVert;
701 int numOfPartIn(0);
702 int pdg(0);
703
704 do {
705 pVert = pV;
706 auto incoming = pVert->particles_in();
707 numOfPartIn = incoming.size();
708 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
709 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
710
711 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
712
713 if (numOfPartIn == 2) {
714 auto incoming = pVert->particles_in();
715 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
716 }
717 return false;
718}
719
723
724 template <class T, class U>
725 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
726 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
727 auto vtx = p->production_vertex();
728 if (!vtx) return false;
729 bool fromHad = false;
730 for ( const auto& parent : particles_in(vtx) ) {
731 if (!parent) continue;
732 // should this really go into parton-level territory?
733 // probably depends where BSM particles are being decayed
734 fromBSM |= isBSM(parent);
735 if (!isPhysical(parent)) return false;
736 fromTau |= isTau(parent);
737 if (isHadron(parent)&&!isBeam(parent)) {
738 if (!hadron) hadron = parent; // assumes linear hadron parentage
739 return true;
740 }
741 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
742 }
743 return fromHad;
744 }
745
748
749 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
750 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
751 decltype(thePart->end_vertex()) pVert(nullptr);
752 if (EndVert != nullptr) {
753 do {
754 bool samePart = false;
755 pVert = nullptr;
756 auto outgoing = EndVert->particles_out();
757 auto incoming = EndVert->particles_in();
758 for (const auto& itrDaug: outgoing) {
759 if (!itrDaug) continue;
760 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
761 // brem on generator level for tau
762 (outgoing.size() == 1 && incoming.size() == 1 &&
764 itrDaug->pdg_id() == thePart->pdg_id()) {
765 samePart = true;
766 pVert = itrDaug->end_vertex();
767 }
768 }
769 if (samePart) EndVert = pVert;
770 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
771 }
772 return EndVert;
773 }
774
776
777 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
778 if (!theVert) return {};
779 decltype(theVert->particles_out()) finalStatePart;
780 auto outgoing = theVert->particles_out();
781 for (const auto& thePart: outgoing) {
782 if (!thePart) continue;
783 finalStatePart.push_back(thePart);
784 if (isStable(thePart)) continue;
785 V pVert = findSimulatedEndVertex(thePart);
786 if (pVert == theVert) break; // to prevent Sherpa loop
787 if (pVert != nullptr) {
788 auto vecPart = findFinalStateParticles<V>(pVert);
789 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
790 }
791 }
792 return finalStatePart;
793 }
794
795}
796#endif

◆ isSUSY() [1/3]

template<>
bool MC::isSUSY ( const DecodedPID & p)
inline

Definition at line 625 of file HepMCHelpers.h.

646{
647inline
648auto particles_in (const HepMC::GenVertex* p) {
649 return std::ranges::subrange (p->particles_in_const_begin(),
650 p->particles_in_const_end());
651}
652}
653#endif
654
655namespace MC
656{
657 template <class VTX>
658 auto particles_in (const VTX* p) { return p->particles_in(); }
659 template <class VTX>
660 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
661
662 namespace Pythia8
663 {
665 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
666
667 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
668
669 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
670 }
671
672#include "AtlasPID.h"
673
675 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
676
678 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
679
681 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
682
684 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
685
687 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
688
690 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
691
693 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
694
696 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
697
699 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
700
702 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
703
707 template <class T> inline bool isStableOrSimDecayed(const T& p) {
708 const auto vertex = p->end_vertex();
709 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
710 }
711
713 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
714
716 template <class T> inline bool isSpecialNonInteracting(const T& p) {
717 const int apid = std::abs(p->pdg_id());
718 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
719 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
720 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
721 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
722 return false;
723 }
724
726
727 template <class T> T findMother(T thePart) {
728 auto partOriVert = thePart->production_vertex();
729 if (!partOriVert) return nullptr;
730
731 long partPDG = thePart->pdg_id();
732 long MotherPDG(0);
733
734 auto MothOriVert = partOriVert;
735 MothOriVert = nullptr;
736 T theMoth(nullptr);
737
738 size_t itr = 0;
739 do {
740 if (itr != 0) partOriVert = MothOriVert;
741 for ( const auto& p : particles_in(partOriVert) ) {
742 theMoth = p;
743 if (!theMoth) continue;
744 MotherPDG = theMoth->pdg_id();
745 MothOriVert = theMoth->production_vertex();
746 if (MotherPDG == partPDG) break;
747 }
748 itr++;
749 if (itr > 100) {
750 break;
751 }
752 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
753 MothOriVert != partOriVert);
754 return theMoth;
755 }
756
758
759 template <class C, class T> T findMatching(C TruthContainer, T p) {
760 T ptrPart = nullptr;
761 if (!p) return ptrPart;
762 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
763 for (T truthParticle : *TruthContainer) {
764 if (HepMC::is_sim_descendant(p,truthParticle)) {
765 ptrPart = truthParticle;
766 break;
767 }
768 }
769 }
770 else {
771 for (T truthParticle : TruthContainer) {
772 if (HepMC::is_sim_descendant(p,truthParticle)) {
773 ptrPart = truthParticle;
774 break;
775 }
776 }
777 }
778 return ptrPart;
779 }
781
782 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
783 auto prodVtx = thePart->production_vertex();
784 if (!prodVtx) return;
785 for (const auto& theMother: prodVtx->particles_in()) {
786 if (!theMother) continue;
787 allancestors.insert(theMother);
788 findParticleAncestors(theMother, allancestors);
789 }
790 }
791
793
794 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
795 auto endVtx = thePart->end_vertex();
796 if (!endVtx) return;
797 for (const auto& theDaughter: endVtx->particles_out()) {
798 if (!theDaughter) continue;
799 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
800 allstabledescendants.insert(theDaughter);
801 }
802 findParticleStableDescendants(theDaughter, allstabledescendants);
803 }
804 }
805
809
810 template <class T> bool isHardScatteringVertex(T pVert) {
811 if (pVert == nullptr) return false;
812 T pV = pVert;
813 int numOfPartIn(0);
814 int pdg(0);
815
816 do {
817 pVert = pV;
818 auto incoming = pVert->particles_in();
819 numOfPartIn = incoming.size();
820 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
821 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
822
823 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
824
825 if (numOfPartIn == 2) {
826 auto incoming = pVert->particles_in();
827 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
828 }
829 return false;
830}
831
835
836 template <class T, class U>
837 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
838 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
839 auto vtx = p->production_vertex();
840 if (!vtx) return false;
841 bool fromHad = false;
842 for ( const auto& parent : particles_in(vtx) ) {
843 if (!parent) continue;
844 // should this really go into parton-level territory?
845 // probably depends where BSM particles are being decayed
846 fromBSM |= isBSM(parent);
847 if (!isPhysical(parent)) return false;
848 fromTau |= isTau(parent);
849 if (isHadron(parent)&&!isBeam(parent)) {
850 if (!hadron) hadron = parent; // assumes linear hadron parentage
851 return true;
852 }
853 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
854 }
855 return fromHad;
856 }
857
860
861 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
862 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
863 decltype(thePart->end_vertex()) pVert(nullptr);
864 if (EndVert != nullptr) {
865 do {
866 bool samePart = false;
867 pVert = nullptr;
868 auto outgoing = EndVert->particles_out();
869 auto incoming = EndVert->particles_in();
870 for (const auto& itrDaug: outgoing) {
871 if (!itrDaug) continue;
872 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
873 // brem on generator level for tau
874 (outgoing.size() == 1 && incoming.size() == 1 &&
876 itrDaug->pdg_id() == thePart->pdg_id()) {
877 samePart = true;
878 pVert = itrDaug->end_vertex();
879 }
880 }
881 if (samePart) EndVert = pVert;
882 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
883 }
884 return EndVert;
885 }
886
888
889 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
890 if (!theVert) return {};
891 decltype(theVert->particles_out()) finalStatePart;
892 auto outgoing = theVert->particles_out();
893 for (const auto& thePart: outgoing) {
894 if (!thePart) continue;
895 finalStatePart.push_back(thePart);
896 if (isStable(thePart)) continue;
897 V pVert = findSimulatedEndVertex(thePart);
898 if (pVert == theVert) break; // to prevent Sherpa loop
899 if (pVert != nullptr) {
900 auto vecPart = findFinalStateParticles<V>(pVert);
901 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
902 }
903 }
904 return finalStatePart;
905 }
906
907}
908#endif

◆ isSUSY() [2/3]

template<>
bool MC::isSUSY ( const int & p)
inline

Definition at line 626 of file HepMCHelpers.h.

647{
648inline
649auto particles_in (const HepMC::GenVertex* p) {
650 return std::ranges::subrange (p->particles_in_const_begin(),
651 p->particles_in_const_end());
652}
653}
654#endif
655
656namespace MC
657{
658 template <class VTX>
659 auto particles_in (const VTX* p) { return p->particles_in(); }
660 template <class VTX>
661 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
662
663 namespace Pythia8
664 {
666 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
667
668 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
669
670 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
671 }
672
673#include "AtlasPID.h"
674
676 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
677
679 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
680
682 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
683
685 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
686
688 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
689
691 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
692
694 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
695
697 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
698
700 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
701
703 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
704
708 template <class T> inline bool isStableOrSimDecayed(const T& p) {
709 const auto vertex = p->end_vertex();
710 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
711 }
712
714 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
715
717 template <class T> inline bool isSpecialNonInteracting(const T& p) {
718 const int apid = std::abs(p->pdg_id());
719 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
720 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
721 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
722 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
723 return false;
724 }
725
727
728 template <class T> T findMother(T thePart) {
729 auto partOriVert = thePart->production_vertex();
730 if (!partOriVert) return nullptr;
731
732 long partPDG = thePart->pdg_id();
733 long MotherPDG(0);
734
735 auto MothOriVert = partOriVert;
736 MothOriVert = nullptr;
737 T theMoth(nullptr);
738
739 size_t itr = 0;
740 do {
741 if (itr != 0) partOriVert = MothOriVert;
742 for ( const auto& p : particles_in(partOriVert) ) {
743 theMoth = p;
744 if (!theMoth) continue;
745 MotherPDG = theMoth->pdg_id();
746 MothOriVert = theMoth->production_vertex();
747 if (MotherPDG == partPDG) break;
748 }
749 itr++;
750 if (itr > 100) {
751 break;
752 }
753 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
754 MothOriVert != partOriVert);
755 return theMoth;
756 }
757
759
760 template <class C, class T> T findMatching(C TruthContainer, T p) {
761 T ptrPart = nullptr;
762 if (!p) return ptrPart;
763 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
764 for (T truthParticle : *TruthContainer) {
765 if (HepMC::is_sim_descendant(p,truthParticle)) {
766 ptrPart = truthParticle;
767 break;
768 }
769 }
770 }
771 else {
772 for (T truthParticle : TruthContainer) {
773 if (HepMC::is_sim_descendant(p,truthParticle)) {
774 ptrPart = truthParticle;
775 break;
776 }
777 }
778 }
779 return ptrPart;
780 }
782
783 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
784 auto prodVtx = thePart->production_vertex();
785 if (!prodVtx) return;
786 for (const auto& theMother: prodVtx->particles_in()) {
787 if (!theMother) continue;
788 allancestors.insert(theMother);
789 findParticleAncestors(theMother, allancestors);
790 }
791 }
792
794
795 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
796 auto endVtx = thePart->end_vertex();
797 if (!endVtx) return;
798 for (const auto& theDaughter: endVtx->particles_out()) {
799 if (!theDaughter) continue;
800 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
801 allstabledescendants.insert(theDaughter);
802 }
803 findParticleStableDescendants(theDaughter, allstabledescendants);
804 }
805 }
806
810
811 template <class T> bool isHardScatteringVertex(T pVert) {
812 if (pVert == nullptr) return false;
813 T pV = pVert;
814 int numOfPartIn(0);
815 int pdg(0);
816
817 do {
818 pVert = pV;
819 auto incoming = pVert->particles_in();
820 numOfPartIn = incoming.size();
821 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
822 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
823
824 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
825
826 if (numOfPartIn == 2) {
827 auto incoming = pVert->particles_in();
828 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
829 }
830 return false;
831}
832
836
837 template <class T, class U>
838 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
839 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
840 auto vtx = p->production_vertex();
841 if (!vtx) return false;
842 bool fromHad = false;
843 for ( const auto& parent : particles_in(vtx) ) {
844 if (!parent) continue;
845 // should this really go into parton-level territory?
846 // probably depends where BSM particles are being decayed
847 fromBSM |= isBSM(parent);
848 if (!isPhysical(parent)) return false;
849 fromTau |= isTau(parent);
850 if (isHadron(parent)&&!isBeam(parent)) {
851 if (!hadron) hadron = parent; // assumes linear hadron parentage
852 return true;
853 }
854 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
855 }
856 return fromHad;
857 }
858
861
862 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
863 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
864 decltype(thePart->end_vertex()) pVert(nullptr);
865 if (EndVert != nullptr) {
866 do {
867 bool samePart = false;
868 pVert = nullptr;
869 auto outgoing = EndVert->particles_out();
870 auto incoming = EndVert->particles_in();
871 for (const auto& itrDaug: outgoing) {
872 if (!itrDaug) continue;
873 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
874 // brem on generator level for tau
875 (outgoing.size() == 1 && incoming.size() == 1 &&
877 itrDaug->pdg_id() == thePart->pdg_id()) {
878 samePart = true;
879 pVert = itrDaug->end_vertex();
880 }
881 }
882 if (samePart) EndVert = pVert;
883 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
884 }
885 return EndVert;
886 }
887
889
890 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
891 if (!theVert) return {};
892 decltype(theVert->particles_out()) finalStatePart;
893 auto outgoing = theVert->particles_out();
894 for (const auto& thePart: outgoing) {
895 if (!thePart) continue;
896 finalStatePart.push_back(thePart);
897 if (isStable(thePart)) continue;
898 V pVert = findSimulatedEndVertex(thePart);
899 if (pVert == theVert) break; // to prevent Sherpa loop
900 if (pVert != nullptr) {
901 auto vecPart = findFinalStateParticles<V>(pVert);
902 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
903 }
904 }
905 return finalStatePart;
906 }
907
908}
909#endif

◆ isSUSY() [3/3]

template<class T>
bool MC::isSUSY ( const T & p)
inline

Definition at line 624 of file HepMCHelpers.h.

645{
646inline
647auto particles_in (const HepMC::GenVertex* p) {
648 return std::ranges::subrange (p->particles_in_const_begin(),
649 p->particles_in_const_end());
650}
651}
652#endif
653
654namespace MC
655{
656 template <class VTX>
657 auto particles_in (const VTX* p) { return p->particles_in(); }
658 template <class VTX>
659 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
660
661 namespace Pythia8
662 {
664 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
665
666 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
667
668 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
669 }
670
671#include "AtlasPID.h"
672
674 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
675
677 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
678
680 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
681
683 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
684
686 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
687
689 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
690
692 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
693
695 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
696
698 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
699
701 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
702
706 template <class T> inline bool isStableOrSimDecayed(const T& p) {
707 const auto vertex = p->end_vertex();
708 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
709 }
710
712 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
713
715 template <class T> inline bool isSpecialNonInteracting(const T& p) {
716 const int apid = std::abs(p->pdg_id());
717 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
718 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
719 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
720 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
721 return false;
722 }
723
725
726 template <class T> T findMother(T thePart) {
727 auto partOriVert = thePart->production_vertex();
728 if (!partOriVert) return nullptr;
729
730 long partPDG = thePart->pdg_id();
731 long MotherPDG(0);
732
733 auto MothOriVert = partOriVert;
734 MothOriVert = nullptr;
735 T theMoth(nullptr);
736
737 size_t itr = 0;
738 do {
739 if (itr != 0) partOriVert = MothOriVert;
740 for ( const auto& p : particles_in(partOriVert) ) {
741 theMoth = p;
742 if (!theMoth) continue;
743 MotherPDG = theMoth->pdg_id();
744 MothOriVert = theMoth->production_vertex();
745 if (MotherPDG == partPDG) break;
746 }
747 itr++;
748 if (itr > 100) {
749 break;
750 }
751 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
752 MothOriVert != partOriVert);
753 return theMoth;
754 }
755
757
758 template <class C, class T> T findMatching(C TruthContainer, T p) {
759 T ptrPart = nullptr;
760 if (!p) return ptrPart;
761 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
762 for (T truthParticle : *TruthContainer) {
763 if (HepMC::is_sim_descendant(p,truthParticle)) {
764 ptrPart = truthParticle;
765 break;
766 }
767 }
768 }
769 else {
770 for (T truthParticle : TruthContainer) {
771 if (HepMC::is_sim_descendant(p,truthParticle)) {
772 ptrPart = truthParticle;
773 break;
774 }
775 }
776 }
777 return ptrPart;
778 }
780
781 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
782 auto prodVtx = thePart->production_vertex();
783 if (!prodVtx) return;
784 for (const auto& theMother: prodVtx->particles_in()) {
785 if (!theMother) continue;
786 allancestors.insert(theMother);
787 findParticleAncestors(theMother, allancestors);
788 }
789 }
790
792
793 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
794 auto endVtx = thePart->end_vertex();
795 if (!endVtx) return;
796 for (const auto& theDaughter: endVtx->particles_out()) {
797 if (!theDaughter) continue;
798 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
799 allstabledescendants.insert(theDaughter);
800 }
801 findParticleStableDescendants(theDaughter, allstabledescendants);
802 }
803 }
804
808
809 template <class T> bool isHardScatteringVertex(T pVert) {
810 if (pVert == nullptr) return false;
811 T pV = pVert;
812 int numOfPartIn(0);
813 int pdg(0);
814
815 do {
816 pVert = pV;
817 auto incoming = pVert->particles_in();
818 numOfPartIn = incoming.size();
819 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
820 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
821
822 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
823
824 if (numOfPartIn == 2) {
825 auto incoming = pVert->particles_in();
826 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
827 }
828 return false;
829}
830
834
835 template <class T, class U>
836 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
837 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
838 auto vtx = p->production_vertex();
839 if (!vtx) return false;
840 bool fromHad = false;
841 for ( const auto& parent : particles_in(vtx) ) {
842 if (!parent) continue;
843 // should this really go into parton-level territory?
844 // probably depends where BSM particles are being decayed
845 fromBSM |= isBSM(parent);
846 if (!isPhysical(parent)) return false;
847 fromTau |= isTau(parent);
848 if (isHadron(parent)&&!isBeam(parent)) {
849 if (!hadron) hadron = parent; // assumes linear hadron parentage
850 return true;
851 }
852 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
853 }
854 return fromHad;
855 }
856
859
860 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
861 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
862 decltype(thePart->end_vertex()) pVert(nullptr);
863 if (EndVert != nullptr) {
864 do {
865 bool samePart = false;
866 pVert = nullptr;
867 auto outgoing = EndVert->particles_out();
868 auto incoming = EndVert->particles_in();
869 for (const auto& itrDaug: outgoing) {
870 if (!itrDaug) continue;
871 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
872 // brem on generator level for tau
873 (outgoing.size() == 1 && incoming.size() == 1 &&
875 itrDaug->pdg_id() == thePart->pdg_id()) {
876 samePart = true;
877 pVert = itrDaug->end_vertex();
878 }
879 }
880 if (samePart) EndVert = pVert;
881 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
882 }
883 return EndVert;
884 }
885
887
888 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
889 if (!theVert) return {};
890 decltype(theVert->particles_out()) finalStatePart;
891 auto outgoing = theVert->particles_out();
892 for (const auto& thePart: outgoing) {
893 if (!thePart) continue;
894 finalStatePart.push_back(thePart);
895 if (isStable(thePart)) continue;
896 V pVert = findSimulatedEndVertex(thePart);
897 if (pVert == theVert) break; // to prevent Sherpa loop
898 if (pVert != nullptr) {
899 auto vecPart = findFinalStateParticles<V>(pVert);
900 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
901 }
902 }
903 return finalStatePart;
904 }
905
906}
907#endif

◆ isTau() [1/2]

template<>
bool MC::isTau ( const int & p)
inline

Definition at line 210 of file HepMCHelpers.h.

◆ isTau() [2/2]

template<class T>
bool MC::isTau ( const T & p)
inline

Definition at line 209 of file HepMCHelpers.h.

◆ isTechnicolor() [1/3]

template<>
bool MC::isTechnicolor ( const DecodedPID & p)
inline

Definition at line 527 of file HepMCHelpers.h.

548 {
549inline
550auto particles_in (const HepMC::GenVertex* p) {
551 return std::ranges::subrange (p->particles_in_const_begin(),
552 p->particles_in_const_end());
553}
554}
555#endif
556
557namespace MC
558{
559 template <class VTX>
560 auto particles_in (const VTX* p) { return p->particles_in(); }
561 template <class VTX>
562 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
563
564 namespace Pythia8
565 {
567 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
568
569 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
570
571 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
572 }
573
574#include "AtlasPID.h"
575
577 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
578
580 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
581
583 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
584
586 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
587
589 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
590
592 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
593
595 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
596
598 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
599
601 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
602
604 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
605
609 template <class T> inline bool isStableOrSimDecayed(const T& p) {
610 const auto vertex = p->end_vertex();
611 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
612 }
613
615 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
616
618 template <class T> inline bool isSpecialNonInteracting(const T& p) {
619 const int apid = std::abs(p->pdg_id());
620 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
621 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
622 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
623 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
624 return false;
625 }
626
628
629 template <class T> T findMother(T thePart) {
630 auto partOriVert = thePart->production_vertex();
631 if (!partOriVert) return nullptr;
632
633 long partPDG = thePart->pdg_id();
634 long MotherPDG(0);
635
636 auto MothOriVert = partOriVert;
637 MothOriVert = nullptr;
638 T theMoth(nullptr);
639
640 size_t itr = 0;
641 do {
642 if (itr != 0) partOriVert = MothOriVert;
643 for ( const auto& p : particles_in(partOriVert) ) {
644 theMoth = p;
645 if (!theMoth) continue;
646 MotherPDG = theMoth->pdg_id();
647 MothOriVert = theMoth->production_vertex();
648 if (MotherPDG == partPDG) break;
649 }
650 itr++;
651 if (itr > 100) {
652 break;
653 }
654 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
655 MothOriVert != partOriVert);
656 return theMoth;
657 }
658
660
661 template <class C, class T> T findMatching(C TruthContainer, T p) {
662 T ptrPart = nullptr;
663 if (!p) return ptrPart;
664 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
665 for (T truthParticle : *TruthContainer) {
666 if (HepMC::is_sim_descendant(p,truthParticle)) {
667 ptrPart = truthParticle;
668 break;
669 }
670 }
671 }
672 else {
673 for (T truthParticle : TruthContainer) {
674 if (HepMC::is_sim_descendant(p,truthParticle)) {
675 ptrPart = truthParticle;
676 break;
677 }
678 }
679 }
680 return ptrPart;
681 }
683
684 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
685 auto prodVtx = thePart->production_vertex();
686 if (!prodVtx) return;
687 for (const auto& theMother: prodVtx->particles_in()) {
688 if (!theMother) continue;
689 allancestors.insert(theMother);
690 findParticleAncestors(theMother, allancestors);
691 }
692 }
693
695
696 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
697 auto endVtx = thePart->end_vertex();
698 if (!endVtx) return;
699 for (const auto& theDaughter: endVtx->particles_out()) {
700 if (!theDaughter) continue;
701 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
702 allstabledescendants.insert(theDaughter);
703 }
704 findParticleStableDescendants(theDaughter, allstabledescendants);
705 }
706 }
707
711
712 template <class T> bool isHardScatteringVertex(T pVert) {
713 if (pVert == nullptr) return false;
714 T pV = pVert;
715 int numOfPartIn(0);
716 int pdg(0);
717
718 do {
719 pVert = pV;
720 auto incoming = pVert->particles_in();
721 numOfPartIn = incoming.size();
722 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
723 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
724
725 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
726
727 if (numOfPartIn == 2) {
728 auto incoming = pVert->particles_in();
729 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
730 }
731 return false;
732}
733
737
738 template <class T, class U>
739 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
740 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
741 auto vtx = p->production_vertex();
742 if (!vtx) return false;
743 bool fromHad = false;
744 for ( const auto& parent : particles_in(vtx) ) {
745 if (!parent) continue;
746 // should this really go into parton-level territory?
747 // probably depends where BSM particles are being decayed
748 fromBSM |= isBSM(parent);
749 if (!isPhysical(parent)) return false;
750 fromTau |= isTau(parent);
751 if (isHadron(parent)&&!isBeam(parent)) {
752 if (!hadron) hadron = parent; // assumes linear hadron parentage
753 return true;
754 }
755 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
756 }
757 return fromHad;
758 }
759
762
763 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
764 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
765 decltype(thePart->end_vertex()) pVert(nullptr);
766 if (EndVert != nullptr) {
767 do {
768 bool samePart = false;
769 pVert = nullptr;
770 auto outgoing = EndVert->particles_out();
771 auto incoming = EndVert->particles_in();
772 for (const auto& itrDaug: outgoing) {
773 if (!itrDaug) continue;
774 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
775 // brem on generator level for tau
776 (outgoing.size() == 1 && incoming.size() == 1 &&
778 itrDaug->pdg_id() == thePart->pdg_id()) {
779 samePart = true;
780 pVert = itrDaug->end_vertex();
781 }
782 }
783 if (samePart) EndVert = pVert;
784 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
785 }
786 return EndVert;
787 }
788
790
791 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
792 if (!theVert) return {};
793 decltype(theVert->particles_out()) finalStatePart;
794 auto outgoing = theVert->particles_out();
795 for (const auto& thePart: outgoing) {
796 if (!thePart) continue;
797 finalStatePart.push_back(thePart);
798 if (isStable(thePart)) continue;
799 V pVert = findSimulatedEndVertex(thePart);
800 if (pVert == theVert) break; // to prevent Sherpa loop
801 if (pVert != nullptr) {
802 auto vecPart = findFinalStateParticles<V>(pVert);
803 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
804 }
805 }
806 return finalStatePart;
807 }
808
809}
810#endif

◆ isTechnicolor() [2/3]

template<>
bool MC::isTechnicolor ( const int & p)
inline

Definition at line 533 of file HepMCHelpers.h.

554{
555inline
556auto particles_in (const HepMC::GenVertex* p) {
557 return std::ranges::subrange (p->particles_in_const_begin(),
558 p->particles_in_const_end());
559}
560}
561#endif
562
563namespace MC
564{
565 template <class VTX>
566 auto particles_in (const VTX* p) { return p->particles_in(); }
567 template <class VTX>
568 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
569
570 namespace Pythia8
571 {
573 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
574
575 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
576
577 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
578 }
579
580#include "AtlasPID.h"
581
583 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
584
586 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
587
589 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
590
592 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
593
595 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
596
598 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
599
601 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
602
604 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
605
607 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
608
610 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
611
615 template <class T> inline bool isStableOrSimDecayed(const T& p) {
616 const auto vertex = p->end_vertex();
617 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
618 }
619
621 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
622
624 template <class T> inline bool isSpecialNonInteracting(const T& p) {
625 const int apid = std::abs(p->pdg_id());
626 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
627 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
628 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
629 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
630 return false;
631 }
632
634
635 template <class T> T findMother(T thePart) {
636 auto partOriVert = thePart->production_vertex();
637 if (!partOriVert) return nullptr;
638
639 long partPDG = thePart->pdg_id();
640 long MotherPDG(0);
641
642 auto MothOriVert = partOriVert;
643 MothOriVert = nullptr;
644 T theMoth(nullptr);
645
646 size_t itr = 0;
647 do {
648 if (itr != 0) partOriVert = MothOriVert;
649 for ( const auto& p : particles_in(partOriVert) ) {
650 theMoth = p;
651 if (!theMoth) continue;
652 MotherPDG = theMoth->pdg_id();
653 MothOriVert = theMoth->production_vertex();
654 if (MotherPDG == partPDG) break;
655 }
656 itr++;
657 if (itr > 100) {
658 break;
659 }
660 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
661 MothOriVert != partOriVert);
662 return theMoth;
663 }
664
666
667 template <class C, class T> T findMatching(C TruthContainer, T p) {
668 T ptrPart = nullptr;
669 if (!p) return ptrPart;
670 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
671 for (T truthParticle : *TruthContainer) {
672 if (HepMC::is_sim_descendant(p,truthParticle)) {
673 ptrPart = truthParticle;
674 break;
675 }
676 }
677 }
678 else {
679 for (T truthParticle : TruthContainer) {
680 if (HepMC::is_sim_descendant(p,truthParticle)) {
681 ptrPart = truthParticle;
682 break;
683 }
684 }
685 }
686 return ptrPart;
687 }
689
690 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
691 auto prodVtx = thePart->production_vertex();
692 if (!prodVtx) return;
693 for (const auto& theMother: prodVtx->particles_in()) {
694 if (!theMother) continue;
695 allancestors.insert(theMother);
696 findParticleAncestors(theMother, allancestors);
697 }
698 }
699
701
702 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
703 auto endVtx = thePart->end_vertex();
704 if (!endVtx) return;
705 for (const auto& theDaughter: endVtx->particles_out()) {
706 if (!theDaughter) continue;
707 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
708 allstabledescendants.insert(theDaughter);
709 }
710 findParticleStableDescendants(theDaughter, allstabledescendants);
711 }
712 }
713
717
718 template <class T> bool isHardScatteringVertex(T pVert) {
719 if (pVert == nullptr) return false;
720 T pV = pVert;
721 int numOfPartIn(0);
722 int pdg(0);
723
724 do {
725 pVert = pV;
726 auto incoming = pVert->particles_in();
727 numOfPartIn = incoming.size();
728 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
729 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
730
731 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
732
733 if (numOfPartIn == 2) {
734 auto incoming = pVert->particles_in();
735 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
736 }
737 return false;
738}
739
743
744 template <class T, class U>
745 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
746 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
747 auto vtx = p->production_vertex();
748 if (!vtx) return false;
749 bool fromHad = false;
750 for ( const auto& parent : particles_in(vtx) ) {
751 if (!parent) continue;
752 // should this really go into parton-level territory?
753 // probably depends where BSM particles are being decayed
754 fromBSM |= isBSM(parent);
755 if (!isPhysical(parent)) return false;
756 fromTau |= isTau(parent);
757 if (isHadron(parent)&&!isBeam(parent)) {
758 if (!hadron) hadron = parent; // assumes linear hadron parentage
759 return true;
760 }
761 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
762 }
763 return fromHad;
764 }
765
768
769 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
770 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
771 decltype(thePart->end_vertex()) pVert(nullptr);
772 if (EndVert != nullptr) {
773 do {
774 bool samePart = false;
775 pVert = nullptr;
776 auto outgoing = EndVert->particles_out();
777 auto incoming = EndVert->particles_in();
778 for (const auto& itrDaug: outgoing) {
779 if (!itrDaug) continue;
780 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
781 // brem on generator level for tau
782 (outgoing.size() == 1 && incoming.size() == 1 &&
784 itrDaug->pdg_id() == thePart->pdg_id()) {
785 samePart = true;
786 pVert = itrDaug->end_vertex();
787 }
788 }
789 if (samePart) EndVert = pVert;
790 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
791 }
792 return EndVert;
793 }
794
796
797 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
798 if (!theVert) return {};
799 decltype(theVert->particles_out()) finalStatePart;
800 auto outgoing = theVert->particles_out();
801 for (const auto& thePart: outgoing) {
802 if (!thePart) continue;
803 finalStatePart.push_back(thePart);
804 if (isStable(thePart)) continue;
805 V pVert = findSimulatedEndVertex(thePart);
806 if (pVert == theVert) break; // to prevent Sherpa loop
807 if (pVert != nullptr) {
808 auto vecPart = findFinalStateParticles<V>(pVert);
809 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
810 }
811 }
812 return finalStatePart;
813 }
814
815}
816#endif

◆ isTechnicolor() [3/3]

template<class T>
bool MC::isTechnicolor ( const T & p)
inline

PDG rule 11e Technicolor states have n = 3, with technifermions treated like ordinary fermions.

States which are ordinary color singlets have n_r = 0. Color octets have n_r = 1. If a state has non-trivial quantum numbers under the topcolor groups SU(3)1×SU(3)2, the quantum numbers are specified by tech, ij, where i and j are 1 or 2. nLis then 2i+j. The coloron V8, is a heavy gluon color octet and thus is 3100021

Definition at line 525 of file HepMCHelpers.h.

546{
547inline
548auto particles_in (const HepMC::GenVertex* p) {
549 return std::ranges::subrange (p->particles_in_const_begin(),
550 p->particles_in_const_end());
551}
552}
553#endif
554
555namespace MC
556{
557 template <class VTX>
558 auto particles_in (const VTX* p) { return p->particles_in(); }
559 template <class VTX>
560 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
561
562 namespace Pythia8
563 {
565 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
566
567 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
568
569 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
570 }
571
572#include "AtlasPID.h"
573
575 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
576
578 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
579
581 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
582
584 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
585
587 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
588
590 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
591
593 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
594
596 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
597
599 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
600
602 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
603
607 template <class T> inline bool isStableOrSimDecayed(const T& p) {
608 const auto vertex = p->end_vertex();
609 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
610 }
611
613 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
614
616 template <class T> inline bool isSpecialNonInteracting(const T& p) {
617 const int apid = std::abs(p->pdg_id());
618 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
619 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
620 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
621 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
622 return false;
623 }
624
626
627 template <class T> T findMother(T thePart) {
628 auto partOriVert = thePart->production_vertex();
629 if (!partOriVert) return nullptr;
630
631 long partPDG = thePart->pdg_id();
632 long MotherPDG(0);
633
634 auto MothOriVert = partOriVert;
635 MothOriVert = nullptr;
636 T theMoth(nullptr);
637
638 size_t itr = 0;
639 do {
640 if (itr != 0) partOriVert = MothOriVert;
641 for ( const auto& p : particles_in(partOriVert) ) {
642 theMoth = p;
643 if (!theMoth) continue;
644 MotherPDG = theMoth->pdg_id();
645 MothOriVert = theMoth->production_vertex();
646 if (MotherPDG == partPDG) break;
647 }
648 itr++;
649 if (itr > 100) {
650 break;
651 }
652 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
653 MothOriVert != partOriVert);
654 return theMoth;
655 }
656
658
659 template <class C, class T> T findMatching(C TruthContainer, T p) {
660 T ptrPart = nullptr;
661 if (!p) return ptrPart;
662 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
663 for (T truthParticle : *TruthContainer) {
664 if (HepMC::is_sim_descendant(p,truthParticle)) {
665 ptrPart = truthParticle;
666 break;
667 }
668 }
669 }
670 else {
671 for (T truthParticle : TruthContainer) {
672 if (HepMC::is_sim_descendant(p,truthParticle)) {
673 ptrPart = truthParticle;
674 break;
675 }
676 }
677 }
678 return ptrPart;
679 }
681
682 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
683 auto prodVtx = thePart->production_vertex();
684 if (!prodVtx) return;
685 for (const auto& theMother: prodVtx->particles_in()) {
686 if (!theMother) continue;
687 allancestors.insert(theMother);
688 findParticleAncestors(theMother, allancestors);
689 }
690 }
691
693
694 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
695 auto endVtx = thePart->end_vertex();
696 if (!endVtx) return;
697 for (const auto& theDaughter: endVtx->particles_out()) {
698 if (!theDaughter) continue;
699 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
700 allstabledescendants.insert(theDaughter);
701 }
702 findParticleStableDescendants(theDaughter, allstabledescendants);
703 }
704 }
705
709
710 template <class T> bool isHardScatteringVertex(T pVert) {
711 if (pVert == nullptr) return false;
712 T pV = pVert;
713 int numOfPartIn(0);
714 int pdg(0);
715
716 do {
717 pVert = pV;
718 auto incoming = pVert->particles_in();
719 numOfPartIn = incoming.size();
720 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
721 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
722
723 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
724
725 if (numOfPartIn == 2) {
726 auto incoming = pVert->particles_in();
727 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
728 }
729 return false;
730}
731
735
736 template <class T, class U>
737 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
738 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
739 auto vtx = p->production_vertex();
740 if (!vtx) return false;
741 bool fromHad = false;
742 for ( const auto& parent : particles_in(vtx) ) {
743 if (!parent) continue;
744 // should this really go into parton-level territory?
745 // probably depends where BSM particles are being decayed
746 fromBSM |= isBSM(parent);
747 if (!isPhysical(parent)) return false;
748 fromTau |= isTau(parent);
749 if (isHadron(parent)&&!isBeam(parent)) {
750 if (!hadron) hadron = parent; // assumes linear hadron parentage
751 return true;
752 }
753 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
754 }
755 return fromHad;
756 }
757
760
761 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
762 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
763 decltype(thePart->end_vertex()) pVert(nullptr);
764 if (EndVert != nullptr) {
765 do {
766 bool samePart = false;
767 pVert = nullptr;
768 auto outgoing = EndVert->particles_out();
769 auto incoming = EndVert->particles_in();
770 for (const auto& itrDaug: outgoing) {
771 if (!itrDaug) continue;
772 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
773 // brem on generator level for tau
774 (outgoing.size() == 1 && incoming.size() == 1 &&
776 itrDaug->pdg_id() == thePart->pdg_id()) {
777 samePart = true;
778 pVert = itrDaug->end_vertex();
779 }
780 }
781 if (samePart) EndVert = pVert;
782 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
783 }
784 return EndVert;
785 }
786
788
789 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
790 if (!theVert) return {};
791 decltype(theVert->particles_out()) finalStatePart;
792 auto outgoing = theVert->particles_out();
793 for (const auto& thePart: outgoing) {
794 if (!thePart) continue;
795 finalStatePart.push_back(thePart);
796 if (isStable(thePart)) continue;
797 V pVert = findSimulatedEndVertex(thePart);
798 if (pVert == theVert) break; // to prevent Sherpa loop
799 if (pVert != nullptr) {
800 auto vecPart = findFinalStateParticles<V>(pVert);
801 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
802 }
803 }
804 return finalStatePart;
805 }
806
807}
808#endif

◆ isTetraquark() [1/3]

template<>
bool MC::isTetraquark ( const DecodedPID & p)
inline

Definition at line 327 of file HepMCHelpers.h.

348 {
349inline
350auto particles_in (const HepMC::GenVertex* p) {
351 return std::ranges::subrange (p->particles_in_const_begin(),
352 p->particles_in_const_end());
353}
354}
355#endif
356
357namespace MC
358{
359 template <class VTX>
360 auto particles_in (const VTX* p) { return p->particles_in(); }
361 template <class VTX>
362 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
363
364 namespace Pythia8
365 {
367 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
368
369 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
370
371 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
372 }
373
374#include "AtlasPID.h"
375
377 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
378
380 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
381
383 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
384
386 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
387
389 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
390
392 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
393
395 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
396
398 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
399
401 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
402
404 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
405
409 template <class T> inline bool isStableOrSimDecayed(const T& p) {
410 const auto vertex = p->end_vertex();
411 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
412 }
413
415 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
416
418 template <class T> inline bool isSpecialNonInteracting(const T& p) {
419 const int apid = std::abs(p->pdg_id());
420 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
421 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
422 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
423 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
424 return false;
425 }
426
428
429 template <class T> T findMother(T thePart) {
430 auto partOriVert = thePart->production_vertex();
431 if (!partOriVert) return nullptr;
432
433 long partPDG = thePart->pdg_id();
434 long MotherPDG(0);
435
436 auto MothOriVert = partOriVert;
437 MothOriVert = nullptr;
438 T theMoth(nullptr);
439
440 size_t itr = 0;
441 do {
442 if (itr != 0) partOriVert = MothOriVert;
443 for ( const auto& p : particles_in(partOriVert) ) {
444 theMoth = p;
445 if (!theMoth) continue;
446 MotherPDG = theMoth->pdg_id();
447 MothOriVert = theMoth->production_vertex();
448 if (MotherPDG == partPDG) break;
449 }
450 itr++;
451 if (itr > 100) {
452 break;
453 }
454 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
455 MothOriVert != partOriVert);
456 return theMoth;
457 }
458
460
461 template <class C, class T> T findMatching(C TruthContainer, T p) {
462 T ptrPart = nullptr;
463 if (!p) return ptrPart;
464 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
465 for (T truthParticle : *TruthContainer) {
466 if (HepMC::is_sim_descendant(p,truthParticle)) {
467 ptrPart = truthParticle;
468 break;
469 }
470 }
471 }
472 else {
473 for (T truthParticle : TruthContainer) {
474 if (HepMC::is_sim_descendant(p,truthParticle)) {
475 ptrPart = truthParticle;
476 break;
477 }
478 }
479 }
480 return ptrPart;
481 }
483
484 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
485 auto prodVtx = thePart->production_vertex();
486 if (!prodVtx) return;
487 for (const auto& theMother: prodVtx->particles_in()) {
488 if (!theMother) continue;
489 allancestors.insert(theMother);
490 findParticleAncestors(theMother, allancestors);
491 }
492 }
493
495
496 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
497 auto endVtx = thePart->end_vertex();
498 if (!endVtx) return;
499 for (const auto& theDaughter: endVtx->particles_out()) {
500 if (!theDaughter) continue;
501 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
502 allstabledescendants.insert(theDaughter);
503 }
504 findParticleStableDescendants(theDaughter, allstabledescendants);
505 }
506 }
507
511
512 template <class T> bool isHardScatteringVertex(T pVert) {
513 if (pVert == nullptr) return false;
514 T pV = pVert;
515 int numOfPartIn(0);
516 int pdg(0);
517
518 do {
519 pVert = pV;
520 auto incoming = pVert->particles_in();
521 numOfPartIn = incoming.size();
522 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
523 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
524
525 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
526
527 if (numOfPartIn == 2) {
528 auto incoming = pVert->particles_in();
529 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
530 }
531 return false;
532}
533
537
538 template <class T, class U>
539 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
540 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
541 auto vtx = p->production_vertex();
542 if (!vtx) return false;
543 bool fromHad = false;
544 for ( const auto& parent : particles_in(vtx) ) {
545 if (!parent) continue;
546 // should this really go into parton-level territory?
547 // probably depends where BSM particles are being decayed
548 fromBSM |= isBSM(parent);
549 if (!isPhysical(parent)) return false;
550 fromTau |= isTau(parent);
551 if (isHadron(parent)&&!isBeam(parent)) {
552 if (!hadron) hadron = parent; // assumes linear hadron parentage
553 return true;
554 }
555 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
556 }
557 return fromHad;
558 }
559
562
563 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
564 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
565 decltype(thePart->end_vertex()) pVert(nullptr);
566 if (EndVert != nullptr) {
567 do {
568 bool samePart = false;
569 pVert = nullptr;
570 auto outgoing = EndVert->particles_out();
571 auto incoming = EndVert->particles_in();
572 for (const auto& itrDaug: outgoing) {
573 if (!itrDaug) continue;
574 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
575 // brem on generator level for tau
576 (outgoing.size() == 1 && incoming.size() == 1 &&
578 itrDaug->pdg_id() == thePart->pdg_id()) {
579 samePart = true;
580 pVert = itrDaug->end_vertex();
581 }
582 }
583 if (samePart) EndVert = pVert;
584 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
585 }
586 return EndVert;
587 }
588
590
591 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
592 if (!theVert) return {};
593 decltype(theVert->particles_out()) finalStatePart;
594 auto outgoing = theVert->particles_out();
595 for (const auto& thePart: outgoing) {
596 if (!thePart) continue;
597 finalStatePart.push_back(thePart);
598 if (isStable(thePart)) continue;
599 V pVert = findSimulatedEndVertex(thePart);
600 if (pVert == theVert) break; // to prevent Sherpa loop
601 if (pVert != nullptr) {
602 auto vecPart = findFinalStateParticles<V>(pVert);
603 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
604 }
605 }
606 return finalStatePart;
607 }
608
609}
610#endif

◆ isTetraquark() [2/3]

template<>
bool MC::isTetraquark ( const int & p)
inline

Definition at line 334 of file HepMCHelpers.h.

355{
356inline
357auto particles_in (const HepMC::GenVertex* p) {
358 return std::ranges::subrange (p->particles_in_const_begin(),
359 p->particles_in_const_end());
360}
361}
362#endif
363
364namespace MC
365{
366 template <class VTX>
367 auto particles_in (const VTX* p) { return p->particles_in(); }
368 template <class VTX>
369 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
370
371 namespace Pythia8
372 {
374 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
375
376 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
377
378 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
379 }
380
381#include "AtlasPID.h"
382
384 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
385
387 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
388
390 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
391
393 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
394
396 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
397
399 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
400
402 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
403
405 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
406
408 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
409
411 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
412
416 template <class T> inline bool isStableOrSimDecayed(const T& p) {
417 const auto vertex = p->end_vertex();
418 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
419 }
420
422 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
423
425 template <class T> inline bool isSpecialNonInteracting(const T& p) {
426 const int apid = std::abs(p->pdg_id());
427 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
428 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
429 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
430 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
431 return false;
432 }
433
435
436 template <class T> T findMother(T thePart) {
437 auto partOriVert = thePart->production_vertex();
438 if (!partOriVert) return nullptr;
439
440 long partPDG = thePart->pdg_id();
441 long MotherPDG(0);
442
443 auto MothOriVert = partOriVert;
444 MothOriVert = nullptr;
445 T theMoth(nullptr);
446
447 size_t itr = 0;
448 do {
449 if (itr != 0) partOriVert = MothOriVert;
450 for ( const auto& p : particles_in(partOriVert) ) {
451 theMoth = p;
452 if (!theMoth) continue;
453 MotherPDG = theMoth->pdg_id();
454 MothOriVert = theMoth->production_vertex();
455 if (MotherPDG == partPDG) break;
456 }
457 itr++;
458 if (itr > 100) {
459 break;
460 }
461 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
462 MothOriVert != partOriVert);
463 return theMoth;
464 }
465
467
468 template <class C, class T> T findMatching(C TruthContainer, T p) {
469 T ptrPart = nullptr;
470 if (!p) return ptrPart;
471 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
472 for (T truthParticle : *TruthContainer) {
473 if (HepMC::is_sim_descendant(p,truthParticle)) {
474 ptrPart = truthParticle;
475 break;
476 }
477 }
478 }
479 else {
480 for (T truthParticle : TruthContainer) {
481 if (HepMC::is_sim_descendant(p,truthParticle)) {
482 ptrPart = truthParticle;
483 break;
484 }
485 }
486 }
487 return ptrPart;
488 }
490
491 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
492 auto prodVtx = thePart->production_vertex();
493 if (!prodVtx) return;
494 for (const auto& theMother: prodVtx->particles_in()) {
495 if (!theMother) continue;
496 allancestors.insert(theMother);
497 findParticleAncestors(theMother, allancestors);
498 }
499 }
500
502
503 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
504 auto endVtx = thePart->end_vertex();
505 if (!endVtx) return;
506 for (const auto& theDaughter: endVtx->particles_out()) {
507 if (!theDaughter) continue;
508 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
509 allstabledescendants.insert(theDaughter);
510 }
511 findParticleStableDescendants(theDaughter, allstabledescendants);
512 }
513 }
514
518
519 template <class T> bool isHardScatteringVertex(T pVert) {
520 if (pVert == nullptr) return false;
521 T pV = pVert;
522 int numOfPartIn(0);
523 int pdg(0);
524
525 do {
526 pVert = pV;
527 auto incoming = pVert->particles_in();
528 numOfPartIn = incoming.size();
529 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
530 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
531
532 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
533
534 if (numOfPartIn == 2) {
535 auto incoming = pVert->particles_in();
536 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
537 }
538 return false;
539}
540
544
545 template <class T, class U>
546 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
547 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
548 auto vtx = p->production_vertex();
549 if (!vtx) return false;
550 bool fromHad = false;
551 for ( const auto& parent : particles_in(vtx) ) {
552 if (!parent) continue;
553 // should this really go into parton-level territory?
554 // probably depends where BSM particles are being decayed
555 fromBSM |= isBSM(parent);
556 if (!isPhysical(parent)) return false;
557 fromTau |= isTau(parent);
558 if (isHadron(parent)&&!isBeam(parent)) {
559 if (!hadron) hadron = parent; // assumes linear hadron parentage
560 return true;
561 }
562 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
563 }
564 return fromHad;
565 }
566
569
570 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
571 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
572 decltype(thePart->end_vertex()) pVert(nullptr);
573 if (EndVert != nullptr) {
574 do {
575 bool samePart = false;
576 pVert = nullptr;
577 auto outgoing = EndVert->particles_out();
578 auto incoming = EndVert->particles_in();
579 for (const auto& itrDaug: outgoing) {
580 if (!itrDaug) continue;
581 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
582 // brem on generator level for tau
583 (outgoing.size() == 1 && incoming.size() == 1 &&
585 itrDaug->pdg_id() == thePart->pdg_id()) {
586 samePart = true;
587 pVert = itrDaug->end_vertex();
588 }
589 }
590 if (samePart) EndVert = pVert;
591 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
592 }
593 return EndVert;
594 }
595
597
598 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
599 if (!theVert) return {};
600 decltype(theVert->particles_out()) finalStatePart;
601 auto outgoing = theVert->particles_out();
602 for (const auto& thePart: outgoing) {
603 if (!thePart) continue;
604 finalStatePart.push_back(thePart);
605 if (isStable(thePart)) continue;
606 V pVert = findSimulatedEndVertex(thePart);
607 if (pVert == theVert) break; // to prevent Sherpa loop
608 if (pVert != nullptr) {
609 auto vecPart = findFinalStateParticles<V>(pVert);
610 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
611 }
612 }
613 return finalStatePart;
614 }
615
616}
617#endif

◆ isTetraquark() [3/3]

template<class T>
bool MC::isTetraquark ( const T & p)
inline

PDG rule 14 The 9-digit tetra-quark codes are ±1nrnLnq1nq20nq3nq4nJ.

For the particle q1q2 is a diquark and ̄q3 ̄q4 an antidiquark, sorted such that nq1≥nq2, nq3≥nq4, nq1≥nq3, and nq2≥nq4 if nq1=nq3. For the antiparticle, given with a negative sign, ̄q1 ̄q2 is an antidiquark and q3q4 a diquark, with the same sorting except that either nq1>nq3 or nq2>nq4 (so that flavour-diagonal states are particles). The nr, nL, and nJ numbers have the same meaning as for ordinary hadrons. APID: states with fourth generation quarks are not tetraquarks

Definition at line 326 of file HepMCHelpers.h.

347{
348inline
349auto particles_in (const HepMC::GenVertex* p) {
350 return std::ranges::subrange (p->particles_in_const_begin(),
351 p->particles_in_const_end());
352}
353}
354#endif
355
356namespace MC
357{
358 template <class VTX>
359 auto particles_in (const VTX* p) { return p->particles_in(); }
360 template <class VTX>
361 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
362
363 namespace Pythia8
364 {
366 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
367
368 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
369
370 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
371 }
372
373#include "AtlasPID.h"
374
376 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
377
379 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
380
382 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
383
385 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
386
388 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
389
391 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
392
394 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
395
397 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
398
400 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
401
403 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
404
408 template <class T> inline bool isStableOrSimDecayed(const T& p) {
409 const auto vertex = p->end_vertex();
410 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
411 }
412
414 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
415
417 template <class T> inline bool isSpecialNonInteracting(const T& p) {
418 const int apid = std::abs(p->pdg_id());
419 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
420 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
421 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
422 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
423 return false;
424 }
425
427
428 template <class T> T findMother(T thePart) {
429 auto partOriVert = thePart->production_vertex();
430 if (!partOriVert) return nullptr;
431
432 long partPDG = thePart->pdg_id();
433 long MotherPDG(0);
434
435 auto MothOriVert = partOriVert;
436 MothOriVert = nullptr;
437 T theMoth(nullptr);
438
439 size_t itr = 0;
440 do {
441 if (itr != 0) partOriVert = MothOriVert;
442 for ( const auto& p : particles_in(partOriVert) ) {
443 theMoth = p;
444 if (!theMoth) continue;
445 MotherPDG = theMoth->pdg_id();
446 MothOriVert = theMoth->production_vertex();
447 if (MotherPDG == partPDG) break;
448 }
449 itr++;
450 if (itr > 100) {
451 break;
452 }
453 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
454 MothOriVert != partOriVert);
455 return theMoth;
456 }
457
459
460 template <class C, class T> T findMatching(C TruthContainer, T p) {
461 T ptrPart = nullptr;
462 if (!p) return ptrPart;
463 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
464 for (T truthParticle : *TruthContainer) {
465 if (HepMC::is_sim_descendant(p,truthParticle)) {
466 ptrPart = truthParticle;
467 break;
468 }
469 }
470 }
471 else {
472 for (T truthParticle : TruthContainer) {
473 if (HepMC::is_sim_descendant(p,truthParticle)) {
474 ptrPart = truthParticle;
475 break;
476 }
477 }
478 }
479 return ptrPart;
480 }
482
483 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
484 auto prodVtx = thePart->production_vertex();
485 if (!prodVtx) return;
486 for (const auto& theMother: prodVtx->particles_in()) {
487 if (!theMother) continue;
488 allancestors.insert(theMother);
489 findParticleAncestors(theMother, allancestors);
490 }
491 }
492
494
495 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
496 auto endVtx = thePart->end_vertex();
497 if (!endVtx) return;
498 for (const auto& theDaughter: endVtx->particles_out()) {
499 if (!theDaughter) continue;
500 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
501 allstabledescendants.insert(theDaughter);
502 }
503 findParticleStableDescendants(theDaughter, allstabledescendants);
504 }
505 }
506
510
511 template <class T> bool isHardScatteringVertex(T pVert) {
512 if (pVert == nullptr) return false;
513 T pV = pVert;
514 int numOfPartIn(0);
515 int pdg(0);
516
517 do {
518 pVert = pV;
519 auto incoming = pVert->particles_in();
520 numOfPartIn = incoming.size();
521 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
522 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
523
524 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
525
526 if (numOfPartIn == 2) {
527 auto incoming = pVert->particles_in();
528 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
529 }
530 return false;
531}
532
536
537 template <class T, class U>
538 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
539 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
540 auto vtx = p->production_vertex();
541 if (!vtx) return false;
542 bool fromHad = false;
543 for ( const auto& parent : particles_in(vtx) ) {
544 if (!parent) continue;
545 // should this really go into parton-level territory?
546 // probably depends where BSM particles are being decayed
547 fromBSM |= isBSM(parent);
548 if (!isPhysical(parent)) return false;
549 fromTau |= isTau(parent);
550 if (isHadron(parent)&&!isBeam(parent)) {
551 if (!hadron) hadron = parent; // assumes linear hadron parentage
552 return true;
553 }
554 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
555 }
556 return fromHad;
557 }
558
561
562 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
563 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
564 decltype(thePart->end_vertex()) pVert(nullptr);
565 if (EndVert != nullptr) {
566 do {
567 bool samePart = false;
568 pVert = nullptr;
569 auto outgoing = EndVert->particles_out();
570 auto incoming = EndVert->particles_in();
571 for (const auto& itrDaug: outgoing) {
572 if (!itrDaug) continue;
573 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
574 // brem on generator level for tau
575 (outgoing.size() == 1 && incoming.size() == 1 &&
577 itrDaug->pdg_id() == thePart->pdg_id()) {
578 samePart = true;
579 pVert = itrDaug->end_vertex();
580 }
581 }
582 if (samePart) EndVert = pVert;
583 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
584 }
585 return EndVert;
586 }
587
589
590 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
591 if (!theVert) return {};
592 decltype(theVert->particles_out()) finalStatePart;
593 auto outgoing = theVert->particles_out();
594 for (const auto& thePart: outgoing) {
595 if (!thePart) continue;
596 finalStatePart.push_back(thePart);
597 if (isStable(thePart)) continue;
598 V pVert = findSimulatedEndVertex(thePart);
599 if (pVert == theVert) break; // to prevent Sherpa loop
600 if (pVert != nullptr) {
601 auto vecPart = findFinalStateParticles<V>(pVert);
602 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
603 }
604 }
605 return finalStatePart;
606 }
607
608}
609#endif

◆ isTop() [1/2]

template<>
bool MC::isTop ( const int & p)
inline

Definition at line 187 of file HepMCHelpers.h.

◆ isTop() [2/2]

template<class T>
bool MC::isTop ( const T & p)
inline

Definition at line 186 of file HepMCHelpers.h.

186{

◆ isTopBaryon()

template<class T>
bool MC::isTopBaryon ( const T & p)
inline

Definition at line 937 of file HepMCHelpers.h.

958{
959inline
960auto particles_in (const HepMC::GenVertex* p) {
961 return std::ranges::subrange (p->particles_in_const_begin(),
962 p->particles_in_const_end());
963}
964}
965#endif
966
967namespace MC
968{
969 template <class VTX>
970 auto particles_in (const VTX* p) { return p->particles_in(); }
971 template <class VTX>
972 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
973
974 namespace Pythia8
975 {
977 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
978
979 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
980
981 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
982 }
983
984#include "AtlasPID.h"
985
987 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
988
990 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
991
993 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
994
996 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
997
999 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1000
1002 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1003
1005 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1006
1008 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1009
1011 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1012
1014 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1015
1019 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1020 const auto vertex = p->end_vertex();
1021 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1022 }
1023
1025 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1026
1028 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1029 const int apid = std::abs(p->pdg_id());
1030 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1031 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1032 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1033 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1034 return false;
1035 }
1036
1038
1039 template <class T> T findMother(T thePart) {
1040 auto partOriVert = thePart->production_vertex();
1041 if (!partOriVert) return nullptr;
1042
1043 long partPDG = thePart->pdg_id();
1044 long MotherPDG(0);
1045
1046 auto MothOriVert = partOriVert;
1047 MothOriVert = nullptr;
1048 T theMoth(nullptr);
1049
1050 size_t itr = 0;
1051 do {
1052 if (itr != 0) partOriVert = MothOriVert;
1053 for ( const auto& p : particles_in(partOriVert) ) {
1054 theMoth = p;
1055 if (!theMoth) continue;
1056 MotherPDG = theMoth->pdg_id();
1057 MothOriVert = theMoth->production_vertex();
1058 if (MotherPDG == partPDG) break;
1059 }
1060 itr++;
1061 if (itr > 100) {
1062 break;
1063 }
1064 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1065 MothOriVert != partOriVert);
1066 return theMoth;
1067 }
1068
1070
1071 template <class C, class T> T findMatching(C TruthContainer, T p) {
1072 T ptrPart = nullptr;
1073 if (!p) return ptrPart;
1074 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1075 for (T truthParticle : *TruthContainer) {
1076 if (HepMC::is_sim_descendant(p,truthParticle)) {
1077 ptrPart = truthParticle;
1078 break;
1079 }
1080 }
1081 }
1082 else {
1083 for (T truthParticle : TruthContainer) {
1084 if (HepMC::is_sim_descendant(p,truthParticle)) {
1085 ptrPart = truthParticle;
1086 break;
1087 }
1088 }
1089 }
1090 return ptrPart;
1091 }
1093
1094 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1095 auto prodVtx = thePart->production_vertex();
1096 if (!prodVtx) return;
1097 for (const auto& theMother: prodVtx->particles_in()) {
1098 if (!theMother) continue;
1099 allancestors.insert(theMother);
1100 findParticleAncestors(theMother, allancestors);
1101 }
1102 }
1103
1105
1106 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1107 auto endVtx = thePart->end_vertex();
1108 if (!endVtx) return;
1109 for (const auto& theDaughter: endVtx->particles_out()) {
1110 if (!theDaughter) continue;
1111 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1112 allstabledescendants.insert(theDaughter);
1113 }
1114 findParticleStableDescendants(theDaughter, allstabledescendants);
1115 }
1116 }
1117
1121
1122 template <class T> bool isHardScatteringVertex(T pVert) {
1123 if (pVert == nullptr) return false;
1124 T pV = pVert;
1125 int numOfPartIn(0);
1126 int pdg(0);
1127
1128 do {
1129 pVert = pV;
1130 auto incoming = pVert->particles_in();
1131 numOfPartIn = incoming.size();
1132 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1133 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1134
1135 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1136
1137 if (numOfPartIn == 2) {
1138 auto incoming = pVert->particles_in();
1139 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1140 }
1141 return false;
1142}
1143
1147
1148 template <class T, class U>
1149 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1150 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1151 auto vtx = p->production_vertex();
1152 if (!vtx) return false;
1153 bool fromHad = false;
1154 for ( const auto& parent : particles_in(vtx) ) {
1155 if (!parent) continue;
1156 // should this really go into parton-level territory?
1157 // probably depends where BSM particles are being decayed
1158 fromBSM |= isBSM(parent);
1159 if (!isPhysical(parent)) return false;
1160 fromTau |= isTau(parent);
1161 if (isHadron(parent)&&!isBeam(parent)) {
1162 if (!hadron) hadron = parent; // assumes linear hadron parentage
1163 return true;
1164 }
1165 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1166 }
1167 return fromHad;
1168 }
1169
1172
1173 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1174 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1175 decltype(thePart->end_vertex()) pVert(nullptr);
1176 if (EndVert != nullptr) {
1177 do {
1178 bool samePart = false;
1179 pVert = nullptr;
1180 auto outgoing = EndVert->particles_out();
1181 auto incoming = EndVert->particles_in();
1182 for (const auto& itrDaug: outgoing) {
1183 if (!itrDaug) continue;
1184 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1185 // brem on generator level for tau
1186 (outgoing.size() == 1 && incoming.size() == 1 &&
1188 itrDaug->pdg_id() == thePart->pdg_id()) {
1189 samePart = true;
1190 pVert = itrDaug->end_vertex();
1191 }
1192 }
1193 if (samePart) EndVert = pVert;
1194 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1195 }
1196 return EndVert;
1197 }
1198
1200
1201 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1202 if (!theVert) return {};
1203 decltype(theVert->particles_out()) finalStatePart;
1204 auto outgoing = theVert->particles_out();
1205 for (const auto& thePart: outgoing) {
1206 if (!thePart) continue;
1207 finalStatePart.push_back(thePart);
1208 if (isStable(thePart)) continue;
1209 V pVert = findSimulatedEndVertex(thePart);
1210 if (pVert == theVert) break; // to prevent Sherpa loop
1211 if (pVert != nullptr) {
1212 auto vecPart = findFinalStateParticles<V>(pVert);
1213 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1214 }
1215 }
1216 return finalStatePart;
1217 }
1218
1219}
1220#endif

◆ isTopHadron()

template<class T>
bool MC::isTopHadron ( const T & p)
inline

Definition at line 914 of file HepMCHelpers.h.

935{
936inline
937auto particles_in (const HepMC::GenVertex* p) {
938 return std::ranges::subrange (p->particles_in_const_begin(),
939 p->particles_in_const_end());
940}
941}
942#endif
943
944namespace MC
945{
946 template <class VTX>
947 auto particles_in (const VTX* p) { return p->particles_in(); }
948 template <class VTX>
949 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
950
951 namespace Pythia8
952 {
954 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
955
956 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
957
958 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
959 }
960
961#include "AtlasPID.h"
962
964 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
965
967 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
968
970 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
971
973 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
974
976 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
977
979 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
980
982 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
983
985 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
986
988 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
989
991 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
992
996 template <class T> inline bool isStableOrSimDecayed(const T& p) {
997 const auto vertex = p->end_vertex();
998 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
999 }
1000
1002 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1003
1005 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1006 const int apid = std::abs(p->pdg_id());
1007 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1008 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1009 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1010 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1011 return false;
1012 }
1013
1015
1016 template <class T> T findMother(T thePart) {
1017 auto partOriVert = thePart->production_vertex();
1018 if (!partOriVert) return nullptr;
1019
1020 long partPDG = thePart->pdg_id();
1021 long MotherPDG(0);
1022
1023 auto MothOriVert = partOriVert;
1024 MothOriVert = nullptr;
1025 T theMoth(nullptr);
1026
1027 size_t itr = 0;
1028 do {
1029 if (itr != 0) partOriVert = MothOriVert;
1030 for ( const auto& p : particles_in(partOriVert) ) {
1031 theMoth = p;
1032 if (!theMoth) continue;
1033 MotherPDG = theMoth->pdg_id();
1034 MothOriVert = theMoth->production_vertex();
1035 if (MotherPDG == partPDG) break;
1036 }
1037 itr++;
1038 if (itr > 100) {
1039 break;
1040 }
1041 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1042 MothOriVert != partOriVert);
1043 return theMoth;
1044 }
1045
1047
1048 template <class C, class T> T findMatching(C TruthContainer, T p) {
1049 T ptrPart = nullptr;
1050 if (!p) return ptrPart;
1051 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1052 for (T truthParticle : *TruthContainer) {
1053 if (HepMC::is_sim_descendant(p,truthParticle)) {
1054 ptrPart = truthParticle;
1055 break;
1056 }
1057 }
1058 }
1059 else {
1060 for (T truthParticle : TruthContainer) {
1061 if (HepMC::is_sim_descendant(p,truthParticle)) {
1062 ptrPart = truthParticle;
1063 break;
1064 }
1065 }
1066 }
1067 return ptrPart;
1068 }
1070
1071 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1072 auto prodVtx = thePart->production_vertex();
1073 if (!prodVtx) return;
1074 for (const auto& theMother: prodVtx->particles_in()) {
1075 if (!theMother) continue;
1076 allancestors.insert(theMother);
1077 findParticleAncestors(theMother, allancestors);
1078 }
1079 }
1080
1082
1083 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1084 auto endVtx = thePart->end_vertex();
1085 if (!endVtx) return;
1086 for (const auto& theDaughter: endVtx->particles_out()) {
1087 if (!theDaughter) continue;
1088 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1089 allstabledescendants.insert(theDaughter);
1090 }
1091 findParticleStableDescendants(theDaughter, allstabledescendants);
1092 }
1093 }
1094
1098
1099 template <class T> bool isHardScatteringVertex(T pVert) {
1100 if (pVert == nullptr) return false;
1101 T pV = pVert;
1102 int numOfPartIn(0);
1103 int pdg(0);
1104
1105 do {
1106 pVert = pV;
1107 auto incoming = pVert->particles_in();
1108 numOfPartIn = incoming.size();
1109 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1110 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1111
1112 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1113
1114 if (numOfPartIn == 2) {
1115 auto incoming = pVert->particles_in();
1116 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1117 }
1118 return false;
1119}
1120
1124
1125 template <class T, class U>
1126 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1127 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1128 auto vtx = p->production_vertex();
1129 if (!vtx) return false;
1130 bool fromHad = false;
1131 for ( const auto& parent : particles_in(vtx) ) {
1132 if (!parent) continue;
1133 // should this really go into parton-level territory?
1134 // probably depends where BSM particles are being decayed
1135 fromBSM |= isBSM(parent);
1136 if (!isPhysical(parent)) return false;
1137 fromTau |= isTau(parent);
1138 if (isHadron(parent)&&!isBeam(parent)) {
1139 if (!hadron) hadron = parent; // assumes linear hadron parentage
1140 return true;
1141 }
1142 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1143 }
1144 return fromHad;
1145 }
1146
1149
1150 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1151 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1152 decltype(thePart->end_vertex()) pVert(nullptr);
1153 if (EndVert != nullptr) {
1154 do {
1155 bool samePart = false;
1156 pVert = nullptr;
1157 auto outgoing = EndVert->particles_out();
1158 auto incoming = EndVert->particles_in();
1159 for (const auto& itrDaug: outgoing) {
1160 if (!itrDaug) continue;
1161 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1162 // brem on generator level for tau
1163 (outgoing.size() == 1 && incoming.size() == 1 &&
1165 itrDaug->pdg_id() == thePart->pdg_id()) {
1166 samePart = true;
1167 pVert = itrDaug->end_vertex();
1168 }
1169 }
1170 if (samePart) EndVert = pVert;
1171 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1172 }
1173 return EndVert;
1174 }
1175
1177
1178 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1179 if (!theVert) return {};
1180 decltype(theVert->particles_out()) finalStatePart;
1181 auto outgoing = theVert->particles_out();
1182 for (const auto& thePart: outgoing) {
1183 if (!thePart) continue;
1184 finalStatePart.push_back(thePart);
1185 if (isStable(thePart)) continue;
1186 V pVert = findSimulatedEndVertex(thePart);
1187 if (pVert == theVert) break; // to prevent Sherpa loop
1188 if (pVert != nullptr) {
1189 auto vecPart = findFinalStateParticles<V>(pVert);
1190 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1191 }
1192 }
1193 return finalStatePart;
1194 }
1195
1196}
1197#endif

◆ isTopMeson()

template<class T>
bool MC::isTopMeson ( const T & p)
inline

Definition at line 921 of file HepMCHelpers.h.

942{
943inline
944auto particles_in (const HepMC::GenVertex* p) {
945 return std::ranges::subrange (p->particles_in_const_begin(),
946 p->particles_in_const_end());
947}
948}
949#endif
950
951namespace MC
952{
953 template <class VTX>
954 auto particles_in (const VTX* p) { return p->particles_in(); }
955 template <class VTX>
956 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
957
958 namespace Pythia8
959 {
961 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
962
963 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
964
965 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
966 }
967
968#include "AtlasPID.h"
969
971 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
972
974 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
975
977 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
978
980 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
981
983 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
984
986 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
987
989 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
990
992 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
993
995 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
996
998 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
999
1003 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1004 const auto vertex = p->end_vertex();
1005 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1006 }
1007
1009 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1010
1012 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1013 const int apid = std::abs(p->pdg_id());
1014 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1015 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1016 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1017 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1018 return false;
1019 }
1020
1022
1023 template <class T> T findMother(T thePart) {
1024 auto partOriVert = thePart->production_vertex();
1025 if (!partOriVert) return nullptr;
1026
1027 long partPDG = thePart->pdg_id();
1028 long MotherPDG(0);
1029
1030 auto MothOriVert = partOriVert;
1031 MothOriVert = nullptr;
1032 T theMoth(nullptr);
1033
1034 size_t itr = 0;
1035 do {
1036 if (itr != 0) partOriVert = MothOriVert;
1037 for ( const auto& p : particles_in(partOriVert) ) {
1038 theMoth = p;
1039 if (!theMoth) continue;
1040 MotherPDG = theMoth->pdg_id();
1041 MothOriVert = theMoth->production_vertex();
1042 if (MotherPDG == partPDG) break;
1043 }
1044 itr++;
1045 if (itr > 100) {
1046 break;
1047 }
1048 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1049 MothOriVert != partOriVert);
1050 return theMoth;
1051 }
1052
1054
1055 template <class C, class T> T findMatching(C TruthContainer, T p) {
1056 T ptrPart = nullptr;
1057 if (!p) return ptrPart;
1058 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1059 for (T truthParticle : *TruthContainer) {
1060 if (HepMC::is_sim_descendant(p,truthParticle)) {
1061 ptrPart = truthParticle;
1062 break;
1063 }
1064 }
1065 }
1066 else {
1067 for (T truthParticle : TruthContainer) {
1068 if (HepMC::is_sim_descendant(p,truthParticle)) {
1069 ptrPart = truthParticle;
1070 break;
1071 }
1072 }
1073 }
1074 return ptrPart;
1075 }
1077
1078 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1079 auto prodVtx = thePart->production_vertex();
1080 if (!prodVtx) return;
1081 for (const auto& theMother: prodVtx->particles_in()) {
1082 if (!theMother) continue;
1083 allancestors.insert(theMother);
1084 findParticleAncestors(theMother, allancestors);
1085 }
1086 }
1087
1089
1090 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1091 auto endVtx = thePart->end_vertex();
1092 if (!endVtx) return;
1093 for (const auto& theDaughter: endVtx->particles_out()) {
1094 if (!theDaughter) continue;
1095 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1096 allstabledescendants.insert(theDaughter);
1097 }
1098 findParticleStableDescendants(theDaughter, allstabledescendants);
1099 }
1100 }
1101
1105
1106 template <class T> bool isHardScatteringVertex(T pVert) {
1107 if (pVert == nullptr) return false;
1108 T pV = pVert;
1109 int numOfPartIn(0);
1110 int pdg(0);
1111
1112 do {
1113 pVert = pV;
1114 auto incoming = pVert->particles_in();
1115 numOfPartIn = incoming.size();
1116 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1117 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1118
1119 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1120
1121 if (numOfPartIn == 2) {
1122 auto incoming = pVert->particles_in();
1123 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1124 }
1125 return false;
1126}
1127
1131
1132 template <class T, class U>
1133 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1134 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1135 auto vtx = p->production_vertex();
1136 if (!vtx) return false;
1137 bool fromHad = false;
1138 for ( const auto& parent : particles_in(vtx) ) {
1139 if (!parent) continue;
1140 // should this really go into parton-level territory?
1141 // probably depends where BSM particles are being decayed
1142 fromBSM |= isBSM(parent);
1143 if (!isPhysical(parent)) return false;
1144 fromTau |= isTau(parent);
1145 if (isHadron(parent)&&!isBeam(parent)) {
1146 if (!hadron) hadron = parent; // assumes linear hadron parentage
1147 return true;
1148 }
1149 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1150 }
1151 return fromHad;
1152 }
1153
1156
1157 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1158 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1159 decltype(thePart->end_vertex()) pVert(nullptr);
1160 if (EndVert != nullptr) {
1161 do {
1162 bool samePart = false;
1163 pVert = nullptr;
1164 auto outgoing = EndVert->particles_out();
1165 auto incoming = EndVert->particles_in();
1166 for (const auto& itrDaug: outgoing) {
1167 if (!itrDaug) continue;
1168 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1169 // brem on generator level for tau
1170 (outgoing.size() == 1 && incoming.size() == 1 &&
1172 itrDaug->pdg_id() == thePart->pdg_id()) {
1173 samePart = true;
1174 pVert = itrDaug->end_vertex();
1175 }
1176 }
1177 if (samePart) EndVert = pVert;
1178 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1179 }
1180 return EndVert;
1181 }
1182
1184
1185 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1186 if (!theVert) return {};
1187 decltype(theVert->particles_out()) finalStatePart;
1188 auto outgoing = theVert->particles_out();
1189 for (const auto& thePart: outgoing) {
1190 if (!thePart) continue;
1191 finalStatePart.push_back(thePart);
1192 if (isStable(thePart)) continue;
1193 V pVert = findSimulatedEndVertex(thePart);
1194 if (pVert == theVert) break; // to prevent Sherpa loop
1195 if (pVert != nullptr) {
1196 auto vecPart = findFinalStateParticles<V>(pVert);
1197 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1198 }
1199 }
1200 return finalStatePart;
1201 }
1202
1203}
1204#endif

◆ isTrajectory() [1/2]

template<>
bool MC::isTrajectory ( const int & p)
inline

Definition at line 361 of file HepMCHelpers.h.

382{
383inline
384auto particles_in (const HepMC::GenVertex* p) {
385 return std::ranges::subrange (p->particles_in_const_begin(),
386 p->particles_in_const_end());
387}
388}
389#endif
390
391namespace MC
392{
393 template <class VTX>
394 auto particles_in (const VTX* p) { return p->particles_in(); }
395 template <class VTX>
396 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
397
398 namespace Pythia8
399 {
401 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
402
403 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
404
405 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
406 }
407
408#include "AtlasPID.h"
409
411 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
412
414 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
415
417 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
418
420 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
421
423 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
424
426 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
427
429 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
430
432 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
433
435 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
436
438 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
439
443 template <class T> inline bool isStableOrSimDecayed(const T& p) {
444 const auto vertex = p->end_vertex();
445 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
446 }
447
449 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
450
452 template <class T> inline bool isSpecialNonInteracting(const T& p) {
453 const int apid = std::abs(p->pdg_id());
454 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
455 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
456 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
457 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
458 return false;
459 }
460
462
463 template <class T> T findMother(T thePart) {
464 auto partOriVert = thePart->production_vertex();
465 if (!partOriVert) return nullptr;
466
467 long partPDG = thePart->pdg_id();
468 long MotherPDG(0);
469
470 auto MothOriVert = partOriVert;
471 MothOriVert = nullptr;
472 T theMoth(nullptr);
473
474 size_t itr = 0;
475 do {
476 if (itr != 0) partOriVert = MothOriVert;
477 for ( const auto& p : particles_in(partOriVert) ) {
478 theMoth = p;
479 if (!theMoth) continue;
480 MotherPDG = theMoth->pdg_id();
481 MothOriVert = theMoth->production_vertex();
482 if (MotherPDG == partPDG) break;
483 }
484 itr++;
485 if (itr > 100) {
486 break;
487 }
488 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
489 MothOriVert != partOriVert);
490 return theMoth;
491 }
492
494
495 template <class C, class T> T findMatching(C TruthContainer, T p) {
496 T ptrPart = nullptr;
497 if (!p) return ptrPart;
498 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
499 for (T truthParticle : *TruthContainer) {
500 if (HepMC::is_sim_descendant(p,truthParticle)) {
501 ptrPart = truthParticle;
502 break;
503 }
504 }
505 }
506 else {
507 for (T truthParticle : TruthContainer) {
508 if (HepMC::is_sim_descendant(p,truthParticle)) {
509 ptrPart = truthParticle;
510 break;
511 }
512 }
513 }
514 return ptrPart;
515 }
517
518 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
519 auto prodVtx = thePart->production_vertex();
520 if (!prodVtx) return;
521 for (const auto& theMother: prodVtx->particles_in()) {
522 if (!theMother) continue;
523 allancestors.insert(theMother);
524 findParticleAncestors(theMother, allancestors);
525 }
526 }
527
529
530 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
531 auto endVtx = thePart->end_vertex();
532 if (!endVtx) return;
533 for (const auto& theDaughter: endVtx->particles_out()) {
534 if (!theDaughter) continue;
535 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
536 allstabledescendants.insert(theDaughter);
537 }
538 findParticleStableDescendants(theDaughter, allstabledescendants);
539 }
540 }
541
545
546 template <class T> bool isHardScatteringVertex(T pVert) {
547 if (pVert == nullptr) return false;
548 T pV = pVert;
549 int numOfPartIn(0);
550 int pdg(0);
551
552 do {
553 pVert = pV;
554 auto incoming = pVert->particles_in();
555 numOfPartIn = incoming.size();
556 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
557 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
558
559 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
560
561 if (numOfPartIn == 2) {
562 auto incoming = pVert->particles_in();
563 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
564 }
565 return false;
566}
567
571
572 template <class T, class U>
573 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
574 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
575 auto vtx = p->production_vertex();
576 if (!vtx) return false;
577 bool fromHad = false;
578 for ( const auto& parent : particles_in(vtx) ) {
579 if (!parent) continue;
580 // should this really go into parton-level territory?
581 // probably depends where BSM particles are being decayed
582 fromBSM |= isBSM(parent);
583 if (!isPhysical(parent)) return false;
584 fromTau |= isTau(parent);
585 if (isHadron(parent)&&!isBeam(parent)) {
586 if (!hadron) hadron = parent; // assumes linear hadron parentage
587 return true;
588 }
589 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
590 }
591 return fromHad;
592 }
593
596
597 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
598 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
599 decltype(thePart->end_vertex()) pVert(nullptr);
600 if (EndVert != nullptr) {
601 do {
602 bool samePart = false;
603 pVert = nullptr;
604 auto outgoing = EndVert->particles_out();
605 auto incoming = EndVert->particles_in();
606 for (const auto& itrDaug: outgoing) {
607 if (!itrDaug) continue;
608 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
609 // brem on generator level for tau
610 (outgoing.size() == 1 && incoming.size() == 1 &&
612 itrDaug->pdg_id() == thePart->pdg_id()) {
613 samePart = true;
614 pVert = itrDaug->end_vertex();
615 }
616 }
617 if (samePart) EndVert = pVert;
618 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
619 }
620 return EndVert;
621 }
622
624
625 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
626 if (!theVert) return {};
627 decltype(theVert->particles_out()) finalStatePart;
628 auto outgoing = theVert->particles_out();
629 for (const auto& thePart: outgoing) {
630 if (!thePart) continue;
631 finalStatePart.push_back(thePart);
632 if (isStable(thePart)) continue;
633 V pVert = findSimulatedEndVertex(thePart);
634 if (pVert == theVert) break; // to prevent Sherpa loop
635 if (pVert != nullptr) {
636 auto vecPart = findFinalStateParticles<V>(pVert);
637 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
638 }
639 }
640 return finalStatePart;
641 }
642
643}
644#endif

◆ isTrajectory() [2/2]

template<class T>
bool MC::isTrajectory ( const T & p)
inline

PDG rule 8: The pomeron and odderon trajectories and a generic reggeon trajectory of states in QCD areassigned codes 990, 9990, and 110 respectively.

Definition at line 360 of file HepMCHelpers.h.

381{
382inline
383auto particles_in (const HepMC::GenVertex* p) {
384 return std::ranges::subrange (p->particles_in_const_begin(),
385 p->particles_in_const_end());
386}
387}
388#endif
389
390namespace MC
391{
392 template <class VTX>
393 auto particles_in (const VTX* p) { return p->particles_in(); }
394 template <class VTX>
395 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
396
397 namespace Pythia8
398 {
400 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
401
402 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
403
404 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
405 }
406
407#include "AtlasPID.h"
408
410 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
411
413 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
414
416 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
417
419 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
420
422 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
423
425 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
426
428 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
429
431 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
432
434 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
435
437 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
438
442 template <class T> inline bool isStableOrSimDecayed(const T& p) {
443 const auto vertex = p->end_vertex();
444 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
445 }
446
448 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
449
451 template <class T> inline bool isSpecialNonInteracting(const T& p) {
452 const int apid = std::abs(p->pdg_id());
453 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
454 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
455 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
456 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
457 return false;
458 }
459
461
462 template <class T> T findMother(T thePart) {
463 auto partOriVert = thePart->production_vertex();
464 if (!partOriVert) return nullptr;
465
466 long partPDG = thePart->pdg_id();
467 long MotherPDG(0);
468
469 auto MothOriVert = partOriVert;
470 MothOriVert = nullptr;
471 T theMoth(nullptr);
472
473 size_t itr = 0;
474 do {
475 if (itr != 0) partOriVert = MothOriVert;
476 for ( const auto& p : particles_in(partOriVert) ) {
477 theMoth = p;
478 if (!theMoth) continue;
479 MotherPDG = theMoth->pdg_id();
480 MothOriVert = theMoth->production_vertex();
481 if (MotherPDG == partPDG) break;
482 }
483 itr++;
484 if (itr > 100) {
485 break;
486 }
487 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
488 MothOriVert != partOriVert);
489 return theMoth;
490 }
491
493
494 template <class C, class T> T findMatching(C TruthContainer, T p) {
495 T ptrPart = nullptr;
496 if (!p) return ptrPart;
497 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
498 for (T truthParticle : *TruthContainer) {
499 if (HepMC::is_sim_descendant(p,truthParticle)) {
500 ptrPart = truthParticle;
501 break;
502 }
503 }
504 }
505 else {
506 for (T truthParticle : TruthContainer) {
507 if (HepMC::is_sim_descendant(p,truthParticle)) {
508 ptrPart = truthParticle;
509 break;
510 }
511 }
512 }
513 return ptrPart;
514 }
516
517 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
518 auto prodVtx = thePart->production_vertex();
519 if (!prodVtx) return;
520 for (const auto& theMother: prodVtx->particles_in()) {
521 if (!theMother) continue;
522 allancestors.insert(theMother);
523 findParticleAncestors(theMother, allancestors);
524 }
525 }
526
528
529 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
530 auto endVtx = thePart->end_vertex();
531 if (!endVtx) return;
532 for (const auto& theDaughter: endVtx->particles_out()) {
533 if (!theDaughter) continue;
534 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
535 allstabledescendants.insert(theDaughter);
536 }
537 findParticleStableDescendants(theDaughter, allstabledescendants);
538 }
539 }
540
544
545 template <class T> bool isHardScatteringVertex(T pVert) {
546 if (pVert == nullptr) return false;
547 T pV = pVert;
548 int numOfPartIn(0);
549 int pdg(0);
550
551 do {
552 pVert = pV;
553 auto incoming = pVert->particles_in();
554 numOfPartIn = incoming.size();
555 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
556 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
557
558 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
559
560 if (numOfPartIn == 2) {
561 auto incoming = pVert->particles_in();
562 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
563 }
564 return false;
565}
566
570
571 template <class T, class U>
572 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
573 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
574 auto vtx = p->production_vertex();
575 if (!vtx) return false;
576 bool fromHad = false;
577 for ( const auto& parent : particles_in(vtx) ) {
578 if (!parent) continue;
579 // should this really go into parton-level territory?
580 // probably depends where BSM particles are being decayed
581 fromBSM |= isBSM(parent);
582 if (!isPhysical(parent)) return false;
583 fromTau |= isTau(parent);
584 if (isHadron(parent)&&!isBeam(parent)) {
585 if (!hadron) hadron = parent; // assumes linear hadron parentage
586 return true;
587 }
588 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
589 }
590 return fromHad;
591 }
592
595
596 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
597 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
598 decltype(thePart->end_vertex()) pVert(nullptr);
599 if (EndVert != nullptr) {
600 do {
601 bool samePart = false;
602 pVert = nullptr;
603 auto outgoing = EndVert->particles_out();
604 auto incoming = EndVert->particles_in();
605 for (const auto& itrDaug: outgoing) {
606 if (!itrDaug) continue;
607 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
608 // brem on generator level for tau
609 (outgoing.size() == 1 && incoming.size() == 1 &&
611 itrDaug->pdg_id() == thePart->pdg_id()) {
612 samePart = true;
613 pVert = itrDaug->end_vertex();
614 }
615 }
616 if (samePart) EndVert = pVert;
617 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
618 }
619 return EndVert;
620 }
621
623
624 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
625 if (!theVert) return {};
626 decltype(theVert->particles_out()) finalStatePart;
627 auto outgoing = theVert->particles_out();
628 for (const auto& thePart: outgoing) {
629 if (!thePart) continue;
630 finalStatePart.push_back(thePart);
631 if (isStable(thePart)) continue;
632 V pVert = findSimulatedEndVertex(thePart);
633 if (pVert == theVert) break; // to prevent Sherpa loop
634 if (pVert != nullptr) {
635 auto vecPart = findFinalStateParticles<V>(pVert);
636 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
637 }
638 }
639 return finalStatePart;
640 }
641
642}
643#endif

◆ isTransportable() [1/3]

template<>
bool MC::isTransportable ( const DecodedPID & p)
inline

Definition at line 875 of file HepMCHelpers.h.

896{
897inline
898auto particles_in (const HepMC::GenVertex* p) {
899 return std::ranges::subrange (p->particles_in_const_begin(),
900 p->particles_in_const_end());
901}
902}
903#endif
904
905namespace MC
906{
907 template <class VTX>
908 auto particles_in (const VTX* p) { return p->particles_in(); }
909 template <class VTX>
910 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
911
912 namespace Pythia8
913 {
915 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
916
917 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
918
919 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
920 }
921
922#include "AtlasPID.h"
923
925 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
926
928 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
929
931 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
932
934 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
935
937 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
938
940 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
941
943 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
944
946 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
947
949 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
950
952 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
953
957 template <class T> inline bool isStableOrSimDecayed(const T& p) {
958 const auto vertex = p->end_vertex();
959 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
960 }
961
963 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
964
966 template <class T> inline bool isSpecialNonInteracting(const T& p) {
967 const int apid = std::abs(p->pdg_id());
968 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
969 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
970 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
971 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
972 return false;
973 }
974
976
977 template <class T> T findMother(T thePart) {
978 auto partOriVert = thePart->production_vertex();
979 if (!partOriVert) return nullptr;
980
981 long partPDG = thePart->pdg_id();
982 long MotherPDG(0);
983
984 auto MothOriVert = partOriVert;
985 MothOriVert = nullptr;
986 T theMoth(nullptr);
987
988 size_t itr = 0;
989 do {
990 if (itr != 0) partOriVert = MothOriVert;
991 for ( const auto& p : particles_in(partOriVert) ) {
992 theMoth = p;
993 if (!theMoth) continue;
994 MotherPDG = theMoth->pdg_id();
995 MothOriVert = theMoth->production_vertex();
996 if (MotherPDG == partPDG) break;
997 }
998 itr++;
999 if (itr > 100) {
1000 break;
1001 }
1002 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1003 MothOriVert != partOriVert);
1004 return theMoth;
1005 }
1006
1008
1009 template <class C, class T> T findMatching(C TruthContainer, T p) {
1010 T ptrPart = nullptr;
1011 if (!p) return ptrPart;
1012 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1013 for (T truthParticle : *TruthContainer) {
1014 if (HepMC::is_sim_descendant(p,truthParticle)) {
1015 ptrPart = truthParticle;
1016 break;
1017 }
1018 }
1019 }
1020 else {
1021 for (T truthParticle : TruthContainer) {
1022 if (HepMC::is_sim_descendant(p,truthParticle)) {
1023 ptrPart = truthParticle;
1024 break;
1025 }
1026 }
1027 }
1028 return ptrPart;
1029 }
1031
1032 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1033 auto prodVtx = thePart->production_vertex();
1034 if (!prodVtx) return;
1035 for (const auto& theMother: prodVtx->particles_in()) {
1036 if (!theMother) continue;
1037 allancestors.insert(theMother);
1038 findParticleAncestors(theMother, allancestors);
1039 }
1040 }
1041
1043
1044 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1045 auto endVtx = thePart->end_vertex();
1046 if (!endVtx) return;
1047 for (const auto& theDaughter: endVtx->particles_out()) {
1048 if (!theDaughter) continue;
1049 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1050 allstabledescendants.insert(theDaughter);
1051 }
1052 findParticleStableDescendants(theDaughter, allstabledescendants);
1053 }
1054 }
1055
1059
1060 template <class T> bool isHardScatteringVertex(T pVert) {
1061 if (pVert == nullptr) return false;
1062 T pV = pVert;
1063 int numOfPartIn(0);
1064 int pdg(0);
1065
1066 do {
1067 pVert = pV;
1068 auto incoming = pVert->particles_in();
1069 numOfPartIn = incoming.size();
1070 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1071 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1072
1073 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1074
1075 if (numOfPartIn == 2) {
1076 auto incoming = pVert->particles_in();
1077 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1078 }
1079 return false;
1080}
1081
1085
1086 template <class T, class U>
1087 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1088 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1089 auto vtx = p->production_vertex();
1090 if (!vtx) return false;
1091 bool fromHad = false;
1092 for ( const auto& parent : particles_in(vtx) ) {
1093 if (!parent) continue;
1094 // should this really go into parton-level territory?
1095 // probably depends where BSM particles are being decayed
1096 fromBSM |= isBSM(parent);
1097 if (!isPhysical(parent)) return false;
1098 fromTau |= isTau(parent);
1099 if (isHadron(parent)&&!isBeam(parent)) {
1100 if (!hadron) hadron = parent; // assumes linear hadron parentage
1101 return true;
1102 }
1103 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1104 }
1105 return fromHad;
1106 }
1107
1110
1111 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1112 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1113 decltype(thePart->end_vertex()) pVert(nullptr);
1114 if (EndVert != nullptr) {
1115 do {
1116 bool samePart = false;
1117 pVert = nullptr;
1118 auto outgoing = EndVert->particles_out();
1119 auto incoming = EndVert->particles_in();
1120 for (const auto& itrDaug: outgoing) {
1121 if (!itrDaug) continue;
1122 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1123 // brem on generator level for tau
1124 (outgoing.size() == 1 && incoming.size() == 1 &&
1126 itrDaug->pdg_id() == thePart->pdg_id()) {
1127 samePart = true;
1128 pVert = itrDaug->end_vertex();
1129 }
1130 }
1131 if (samePart) EndVert = pVert;
1132 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1133 }
1134 return EndVert;
1135 }
1136
1138
1139 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1140 if (!theVert) return {};
1141 decltype(theVert->particles_out()) finalStatePart;
1142 auto outgoing = theVert->particles_out();
1143 for (const auto& thePart: outgoing) {
1144 if (!thePart) continue;
1145 finalStatePart.push_back(thePart);
1146 if (isStable(thePart)) continue;
1147 V pVert = findSimulatedEndVertex(thePart);
1148 if (pVert == theVert) break; // to prevent Sherpa loop
1149 if (pVert != nullptr) {
1150 auto vecPart = findFinalStateParticles<V>(pVert);
1151 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1152 }
1153 }
1154 return finalStatePart;
1155 }
1156
1157}
1158#endif

◆ isTransportable() [2/3]

template<>
bool MC::isTransportable ( const int & p)
inline

Definition at line 876 of file HepMCHelpers.h.

897{
898inline
899auto particles_in (const HepMC::GenVertex* p) {
900 return std::ranges::subrange (p->particles_in_const_begin(),
901 p->particles_in_const_end());
902}
903}
904#endif
905
906namespace MC
907{
908 template <class VTX>
909 auto particles_in (const VTX* p) { return p->particles_in(); }
910 template <class VTX>
911 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
912
913 namespace Pythia8
914 {
916 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
917
918 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
919
920 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
921 }
922
923#include "AtlasPID.h"
924
926 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
927
929 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
930
932 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
933
935 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
936
938 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
939
941 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
942
944 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
945
947 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
948
950 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
951
953 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
954
958 template <class T> inline bool isStableOrSimDecayed(const T& p) {
959 const auto vertex = p->end_vertex();
960 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
961 }
962
964 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
965
967 template <class T> inline bool isSpecialNonInteracting(const T& p) {
968 const int apid = std::abs(p->pdg_id());
969 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
970 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
971 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
972 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
973 return false;
974 }
975
977
978 template <class T> T findMother(T thePart) {
979 auto partOriVert = thePart->production_vertex();
980 if (!partOriVert) return nullptr;
981
982 long partPDG = thePart->pdg_id();
983 long MotherPDG(0);
984
985 auto MothOriVert = partOriVert;
986 MothOriVert = nullptr;
987 T theMoth(nullptr);
988
989 size_t itr = 0;
990 do {
991 if (itr != 0) partOriVert = MothOriVert;
992 for ( const auto& p : particles_in(partOriVert) ) {
993 theMoth = p;
994 if (!theMoth) continue;
995 MotherPDG = theMoth->pdg_id();
996 MothOriVert = theMoth->production_vertex();
997 if (MotherPDG == partPDG) break;
998 }
999 itr++;
1000 if (itr > 100) {
1001 break;
1002 }
1003 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1004 MothOriVert != partOriVert);
1005 return theMoth;
1006 }
1007
1009
1010 template <class C, class T> T findMatching(C TruthContainer, T p) {
1011 T ptrPart = nullptr;
1012 if (!p) return ptrPart;
1013 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1014 for (T truthParticle : *TruthContainer) {
1015 if (HepMC::is_sim_descendant(p,truthParticle)) {
1016 ptrPart = truthParticle;
1017 break;
1018 }
1019 }
1020 }
1021 else {
1022 for (T truthParticle : TruthContainer) {
1023 if (HepMC::is_sim_descendant(p,truthParticle)) {
1024 ptrPart = truthParticle;
1025 break;
1026 }
1027 }
1028 }
1029 return ptrPart;
1030 }
1032
1033 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1034 auto prodVtx = thePart->production_vertex();
1035 if (!prodVtx) return;
1036 for (const auto& theMother: prodVtx->particles_in()) {
1037 if (!theMother) continue;
1038 allancestors.insert(theMother);
1039 findParticleAncestors(theMother, allancestors);
1040 }
1041 }
1042
1044
1045 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1046 auto endVtx = thePart->end_vertex();
1047 if (!endVtx) return;
1048 for (const auto& theDaughter: endVtx->particles_out()) {
1049 if (!theDaughter) continue;
1050 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1051 allstabledescendants.insert(theDaughter);
1052 }
1053 findParticleStableDescendants(theDaughter, allstabledescendants);
1054 }
1055 }
1056
1060
1061 template <class T> bool isHardScatteringVertex(T pVert) {
1062 if (pVert == nullptr) return false;
1063 T pV = pVert;
1064 int numOfPartIn(0);
1065 int pdg(0);
1066
1067 do {
1068 pVert = pV;
1069 auto incoming = pVert->particles_in();
1070 numOfPartIn = incoming.size();
1071 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1072 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1073
1074 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1075
1076 if (numOfPartIn == 2) {
1077 auto incoming = pVert->particles_in();
1078 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1079 }
1080 return false;
1081}
1082
1086
1087 template <class T, class U>
1088 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1089 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1090 auto vtx = p->production_vertex();
1091 if (!vtx) return false;
1092 bool fromHad = false;
1093 for ( const auto& parent : particles_in(vtx) ) {
1094 if (!parent) continue;
1095 // should this really go into parton-level territory?
1096 // probably depends where BSM particles are being decayed
1097 fromBSM |= isBSM(parent);
1098 if (!isPhysical(parent)) return false;
1099 fromTau |= isTau(parent);
1100 if (isHadron(parent)&&!isBeam(parent)) {
1101 if (!hadron) hadron = parent; // assumes linear hadron parentage
1102 return true;
1103 }
1104 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1105 }
1106 return fromHad;
1107 }
1108
1111
1112 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1113 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1114 decltype(thePart->end_vertex()) pVert(nullptr);
1115 if (EndVert != nullptr) {
1116 do {
1117 bool samePart = false;
1118 pVert = nullptr;
1119 auto outgoing = EndVert->particles_out();
1120 auto incoming = EndVert->particles_in();
1121 for (const auto& itrDaug: outgoing) {
1122 if (!itrDaug) continue;
1123 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1124 // brem on generator level for tau
1125 (outgoing.size() == 1 && incoming.size() == 1 &&
1127 itrDaug->pdg_id() == thePart->pdg_id()) {
1128 samePart = true;
1129 pVert = itrDaug->end_vertex();
1130 }
1131 }
1132 if (samePart) EndVert = pVert;
1133 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1134 }
1135 return EndVert;
1136 }
1137
1139
1140 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1141 if (!theVert) return {};
1142 decltype(theVert->particles_out()) finalStatePart;
1143 auto outgoing = theVert->particles_out();
1144 for (const auto& thePart: outgoing) {
1145 if (!thePart) continue;
1146 finalStatePart.push_back(thePart);
1147 if (isStable(thePart)) continue;
1148 V pVert = findSimulatedEndVertex(thePart);
1149 if (pVert == theVert) break; // to prevent Sherpa loop
1150 if (pVert != nullptr) {
1151 auto vecPart = findFinalStateParticles<V>(pVert);
1152 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1153 }
1154 }
1155 return finalStatePart;
1156 }
1157
1158}
1159#endif

◆ isTransportable() [3/3]

template<class T>
bool MC::isTransportable ( const T & p)
inline

Definition at line 874 of file HepMCHelpers.h.

895{
896inline
897auto particles_in (const HepMC::GenVertex* p) {
898 return std::ranges::subrange (p->particles_in_const_begin(),
899 p->particles_in_const_end());
900}
901}
902#endif
903
904namespace MC
905{
906 template <class VTX>
907 auto particles_in (const VTX* p) { return p->particles_in(); }
908 template <class VTX>
909 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
910
911 namespace Pythia8
912 {
914 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
915
916 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
917
918 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
919 }
920
921#include "AtlasPID.h"
922
924 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
925
927 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
928
930 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
931
933 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
934
936 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
937
939 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
940
942 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
943
945 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
946
948 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
949
951 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
952
956 template <class T> inline bool isStableOrSimDecayed(const T& p) {
957 const auto vertex = p->end_vertex();
958 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
959 }
960
962 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
963
965 template <class T> inline bool isSpecialNonInteracting(const T& p) {
966 const int apid = std::abs(p->pdg_id());
967 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
968 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
969 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
970 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
971 return false;
972 }
973
975
976 template <class T> T findMother(T thePart) {
977 auto partOriVert = thePart->production_vertex();
978 if (!partOriVert) return nullptr;
979
980 long partPDG = thePart->pdg_id();
981 long MotherPDG(0);
982
983 auto MothOriVert = partOriVert;
984 MothOriVert = nullptr;
985 T theMoth(nullptr);
986
987 size_t itr = 0;
988 do {
989 if (itr != 0) partOriVert = MothOriVert;
990 for ( const auto& p : particles_in(partOriVert) ) {
991 theMoth = p;
992 if (!theMoth) continue;
993 MotherPDG = theMoth->pdg_id();
994 MothOriVert = theMoth->production_vertex();
995 if (MotherPDG == partPDG) break;
996 }
997 itr++;
998 if (itr > 100) {
999 break;
1000 }
1001 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1002 MothOriVert != partOriVert);
1003 return theMoth;
1004 }
1005
1007
1008 template <class C, class T> T findMatching(C TruthContainer, T p) {
1009 T ptrPart = nullptr;
1010 if (!p) return ptrPart;
1011 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1012 for (T truthParticle : *TruthContainer) {
1013 if (HepMC::is_sim_descendant(p,truthParticle)) {
1014 ptrPart = truthParticle;
1015 break;
1016 }
1017 }
1018 }
1019 else {
1020 for (T truthParticle : TruthContainer) {
1021 if (HepMC::is_sim_descendant(p,truthParticle)) {
1022 ptrPart = truthParticle;
1023 break;
1024 }
1025 }
1026 }
1027 return ptrPart;
1028 }
1030
1031 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1032 auto prodVtx = thePart->production_vertex();
1033 if (!prodVtx) return;
1034 for (const auto& theMother: prodVtx->particles_in()) {
1035 if (!theMother) continue;
1036 allancestors.insert(theMother);
1037 findParticleAncestors(theMother, allancestors);
1038 }
1039 }
1040
1042
1043 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1044 auto endVtx = thePart->end_vertex();
1045 if (!endVtx) return;
1046 for (const auto& theDaughter: endVtx->particles_out()) {
1047 if (!theDaughter) continue;
1048 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1049 allstabledescendants.insert(theDaughter);
1050 }
1051 findParticleStableDescendants(theDaughter, allstabledescendants);
1052 }
1053 }
1054
1058
1059 template <class T> bool isHardScatteringVertex(T pVert) {
1060 if (pVert == nullptr) return false;
1061 T pV = pVert;
1062 int numOfPartIn(0);
1063 int pdg(0);
1064
1065 do {
1066 pVert = pV;
1067 auto incoming = pVert->particles_in();
1068 numOfPartIn = incoming.size();
1069 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1070 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1071
1072 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1073
1074 if (numOfPartIn == 2) {
1075 auto incoming = pVert->particles_in();
1076 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1077 }
1078 return false;
1079}
1080
1084
1085 template <class T, class U>
1086 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1087 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1088 auto vtx = p->production_vertex();
1089 if (!vtx) return false;
1090 bool fromHad = false;
1091 for ( const auto& parent : particles_in(vtx) ) {
1092 if (!parent) continue;
1093 // should this really go into parton-level territory?
1094 // probably depends where BSM particles are being decayed
1095 fromBSM |= isBSM(parent);
1096 if (!isPhysical(parent)) return false;
1097 fromTau |= isTau(parent);
1098 if (isHadron(parent)&&!isBeam(parent)) {
1099 if (!hadron) hadron = parent; // assumes linear hadron parentage
1100 return true;
1101 }
1102 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1103 }
1104 return fromHad;
1105 }
1106
1109
1110 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1111 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1112 decltype(thePart->end_vertex()) pVert(nullptr);
1113 if (EndVert != nullptr) {
1114 do {
1115 bool samePart = false;
1116 pVert = nullptr;
1117 auto outgoing = EndVert->particles_out();
1118 auto incoming = EndVert->particles_in();
1119 for (const auto& itrDaug: outgoing) {
1120 if (!itrDaug) continue;
1121 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1122 // brem on generator level for tau
1123 (outgoing.size() == 1 && incoming.size() == 1 &&
1125 itrDaug->pdg_id() == thePart->pdg_id()) {
1126 samePart = true;
1127 pVert = itrDaug->end_vertex();
1128 }
1129 }
1130 if (samePart) EndVert = pVert;
1131 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1132 }
1133 return EndVert;
1134 }
1135
1137
1138 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1139 if (!theVert) return {};
1140 decltype(theVert->particles_out()) finalStatePart;
1141 auto outgoing = theVert->particles_out();
1142 for (const auto& thePart: outgoing) {
1143 if (!thePart) continue;
1144 finalStatePart.push_back(thePart);
1145 if (isStable(thePart)) continue;
1146 V pVert = findSimulatedEndVertex(thePart);
1147 if (pVert == theVert) break; // to prevent Sherpa loop
1148 if (pVert != nullptr) {
1149 auto vecPart = findFinalStateParticles<V>(pVert);
1150 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1151 }
1152 }
1153 return finalStatePart;
1154 }
1155
1156}
1157#endif

◆ isValid() [1/3]

template<>
bool MC::isValid ( const DecodedPID & p)
inline

Definition at line 880 of file HepMCHelpers.h.

901 {
902inline
903auto particles_in (const HepMC::GenVertex* p) {
904 return std::ranges::subrange (p->particles_in_const_begin(),
905 p->particles_in_const_end());
906}
907}
908#endif
909
910namespace MC
911{
912 template <class VTX>
913 auto particles_in (const VTX* p) { return p->particles_in(); }
914 template <class VTX>
915 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
916
917 namespace Pythia8
918 {
920 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
921
922 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
923
924 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
925 }
926
927#include "AtlasPID.h"
928
930 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
931
933 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
934
936 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
937
939 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
940
942 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
943
945 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
946
948 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
949
951 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
952
954 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
955
957 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
958
962 template <class T> inline bool isStableOrSimDecayed(const T& p) {
963 const auto vertex = p->end_vertex();
964 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
965 }
966
968 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
969
971 template <class T> inline bool isSpecialNonInteracting(const T& p) {
972 const int apid = std::abs(p->pdg_id());
973 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
974 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
975 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
976 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
977 return false;
978 }
979
981
982 template <class T> T findMother(T thePart) {
983 auto partOriVert = thePart->production_vertex();
984 if (!partOriVert) return nullptr;
985
986 long partPDG = thePart->pdg_id();
987 long MotherPDG(0);
988
989 auto MothOriVert = partOriVert;
990 MothOriVert = nullptr;
991 T theMoth(nullptr);
992
993 size_t itr = 0;
994 do {
995 if (itr != 0) partOriVert = MothOriVert;
996 for ( const auto& p : particles_in(partOriVert) ) {
997 theMoth = p;
998 if (!theMoth) continue;
999 MotherPDG = theMoth->pdg_id();
1000 MothOriVert = theMoth->production_vertex();
1001 if (MotherPDG == partPDG) break;
1002 }
1003 itr++;
1004 if (itr > 100) {
1005 break;
1006 }
1007 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1008 MothOriVert != partOriVert);
1009 return theMoth;
1010 }
1011
1013
1014 template <class C, class T> T findMatching(C TruthContainer, T p) {
1015 T ptrPart = nullptr;
1016 if (!p) return ptrPart;
1017 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1018 for (T truthParticle : *TruthContainer) {
1019 if (HepMC::is_sim_descendant(p,truthParticle)) {
1020 ptrPart = truthParticle;
1021 break;
1022 }
1023 }
1024 }
1025 else {
1026 for (T truthParticle : TruthContainer) {
1027 if (HepMC::is_sim_descendant(p,truthParticle)) {
1028 ptrPart = truthParticle;
1029 break;
1030 }
1031 }
1032 }
1033 return ptrPart;
1034 }
1036
1037 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1038 auto prodVtx = thePart->production_vertex();
1039 if (!prodVtx) return;
1040 for (const auto& theMother: prodVtx->particles_in()) {
1041 if (!theMother) continue;
1042 allancestors.insert(theMother);
1043 findParticleAncestors(theMother, allancestors);
1044 }
1045 }
1046
1048
1049 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1050 auto endVtx = thePart->end_vertex();
1051 if (!endVtx) return;
1052 for (const auto& theDaughter: endVtx->particles_out()) {
1053 if (!theDaughter) continue;
1054 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1055 allstabledescendants.insert(theDaughter);
1056 }
1057 findParticleStableDescendants(theDaughter, allstabledescendants);
1058 }
1059 }
1060
1064
1065 template <class T> bool isHardScatteringVertex(T pVert) {
1066 if (pVert == nullptr) return false;
1067 T pV = pVert;
1068 int numOfPartIn(0);
1069 int pdg(0);
1070
1071 do {
1072 pVert = pV;
1073 auto incoming = pVert->particles_in();
1074 numOfPartIn = incoming.size();
1075 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1076 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1077
1078 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1079
1080 if (numOfPartIn == 2) {
1081 auto incoming = pVert->particles_in();
1082 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1083 }
1084 return false;
1085}
1086
1090
1091 template <class T, class U>
1092 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1093 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1094 auto vtx = p->production_vertex();
1095 if (!vtx) return false;
1096 bool fromHad = false;
1097 for ( const auto& parent : particles_in(vtx) ) {
1098 if (!parent) continue;
1099 // should this really go into parton-level territory?
1100 // probably depends where BSM particles are being decayed
1101 fromBSM |= isBSM(parent);
1102 if (!isPhysical(parent)) return false;
1103 fromTau |= isTau(parent);
1104 if (isHadron(parent)&&!isBeam(parent)) {
1105 if (!hadron) hadron = parent; // assumes linear hadron parentage
1106 return true;
1107 }
1108 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1109 }
1110 return fromHad;
1111 }
1112
1115
1116 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1117 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1118 decltype(thePart->end_vertex()) pVert(nullptr);
1119 if (EndVert != nullptr) {
1120 do {
1121 bool samePart = false;
1122 pVert = nullptr;
1123 auto outgoing = EndVert->particles_out();
1124 auto incoming = EndVert->particles_in();
1125 for (const auto& itrDaug: outgoing) {
1126 if (!itrDaug) continue;
1127 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1128 // brem on generator level for tau
1129 (outgoing.size() == 1 && incoming.size() == 1 &&
1131 itrDaug->pdg_id() == thePart->pdg_id()) {
1132 samePart = true;
1133 pVert = itrDaug->end_vertex();
1134 }
1135 }
1136 if (samePart) EndVert = pVert;
1137 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1138 }
1139 return EndVert;
1140 }
1141
1143
1144 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1145 if (!theVert) return {};
1146 decltype(theVert->particles_out()) finalStatePart;
1147 auto outgoing = theVert->particles_out();
1148 for (const auto& thePart: outgoing) {
1149 if (!thePart) continue;
1150 finalStatePart.push_back(thePart);
1151 if (isStable(thePart)) continue;
1152 V pVert = findSimulatedEndVertex(thePart);
1153 if (pVert == theVert) break; // to prevent Sherpa loop
1154 if (pVert != nullptr) {
1155 auto vecPart = findFinalStateParticles<V>(pVert);
1156 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1157 }
1158 }
1159 return finalStatePart;
1160 }
1161
1162}
1163#endif

◆ isValid() [2/3]

template<>
bool MC::isValid ( const int & p)
inline

Definition at line 885 of file HepMCHelpers.h.

906 {
907inline
908auto particles_in (const HepMC::GenVertex* p) {
909 return std::ranges::subrange (p->particles_in_const_begin(),
910 p->particles_in_const_end());
911}
912}
913#endif
914
915namespace MC
916{
917 template <class VTX>
918 auto particles_in (const VTX* p) { return p->particles_in(); }
919 template <class VTX>
920 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
921
922 namespace Pythia8
923 {
925 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
926
927 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
928
929 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
930 }
931
932#include "AtlasPID.h"
933
935 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
936
938 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
939
941 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
942
944 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
945
947 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
948
950 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
951
953 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
954
956 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
957
959 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
960
962 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
963
967 template <class T> inline bool isStableOrSimDecayed(const T& p) {
968 const auto vertex = p->end_vertex();
969 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
970 }
971
973 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
974
976 template <class T> inline bool isSpecialNonInteracting(const T& p) {
977 const int apid = std::abs(p->pdg_id());
978 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
979 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
980 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
981 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
982 return false;
983 }
984
986
987 template <class T> T findMother(T thePart) {
988 auto partOriVert = thePart->production_vertex();
989 if (!partOriVert) return nullptr;
990
991 long partPDG = thePart->pdg_id();
992 long MotherPDG(0);
993
994 auto MothOriVert = partOriVert;
995 MothOriVert = nullptr;
996 T theMoth(nullptr);
997
998 size_t itr = 0;
999 do {
1000 if (itr != 0) partOriVert = MothOriVert;
1001 for ( const auto& p : particles_in(partOriVert) ) {
1002 theMoth = p;
1003 if (!theMoth) continue;
1004 MotherPDG = theMoth->pdg_id();
1005 MothOriVert = theMoth->production_vertex();
1006 if (MotherPDG == partPDG) break;
1007 }
1008 itr++;
1009 if (itr > 100) {
1010 break;
1011 }
1012 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1013 MothOriVert != partOriVert);
1014 return theMoth;
1015 }
1016
1018
1019 template <class C, class T> T findMatching(C TruthContainer, T p) {
1020 T ptrPart = nullptr;
1021 if (!p) return ptrPart;
1022 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1023 for (T truthParticle : *TruthContainer) {
1024 if (HepMC::is_sim_descendant(p,truthParticle)) {
1025 ptrPart = truthParticle;
1026 break;
1027 }
1028 }
1029 }
1030 else {
1031 for (T truthParticle : TruthContainer) {
1032 if (HepMC::is_sim_descendant(p,truthParticle)) {
1033 ptrPart = truthParticle;
1034 break;
1035 }
1036 }
1037 }
1038 return ptrPart;
1039 }
1041
1042 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1043 auto prodVtx = thePart->production_vertex();
1044 if (!prodVtx) return;
1045 for (const auto& theMother: prodVtx->particles_in()) {
1046 if (!theMother) continue;
1047 allancestors.insert(theMother);
1048 findParticleAncestors(theMother, allancestors);
1049 }
1050 }
1051
1053
1054 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1055 auto endVtx = thePart->end_vertex();
1056 if (!endVtx) return;
1057 for (const auto& theDaughter: endVtx->particles_out()) {
1058 if (!theDaughter) continue;
1059 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1060 allstabledescendants.insert(theDaughter);
1061 }
1062 findParticleStableDescendants(theDaughter, allstabledescendants);
1063 }
1064 }
1065
1069
1070 template <class T> bool isHardScatteringVertex(T pVert) {
1071 if (pVert == nullptr) return false;
1072 T pV = pVert;
1073 int numOfPartIn(0);
1074 int pdg(0);
1075
1076 do {
1077 pVert = pV;
1078 auto incoming = pVert->particles_in();
1079 numOfPartIn = incoming.size();
1080 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1081 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1082
1083 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1084
1085 if (numOfPartIn == 2) {
1086 auto incoming = pVert->particles_in();
1087 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1088 }
1089 return false;
1090}
1091
1095
1096 template <class T, class U>
1097 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1098 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1099 auto vtx = p->production_vertex();
1100 if (!vtx) return false;
1101 bool fromHad = false;
1102 for ( const auto& parent : particles_in(vtx) ) {
1103 if (!parent) continue;
1104 // should this really go into parton-level territory?
1105 // probably depends where BSM particles are being decayed
1106 fromBSM |= isBSM(parent);
1107 if (!isPhysical(parent)) return false;
1108 fromTau |= isTau(parent);
1109 if (isHadron(parent)&&!isBeam(parent)) {
1110 if (!hadron) hadron = parent; // assumes linear hadron parentage
1111 return true;
1112 }
1113 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1114 }
1115 return fromHad;
1116 }
1117
1120
1121 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1122 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1123 decltype(thePart->end_vertex()) pVert(nullptr);
1124 if (EndVert != nullptr) {
1125 do {
1126 bool samePart = false;
1127 pVert = nullptr;
1128 auto outgoing = EndVert->particles_out();
1129 auto incoming = EndVert->particles_in();
1130 for (const auto& itrDaug: outgoing) {
1131 if (!itrDaug) continue;
1132 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1133 // brem on generator level for tau
1134 (outgoing.size() == 1 && incoming.size() == 1 &&
1136 itrDaug->pdg_id() == thePart->pdg_id()) {
1137 samePart = true;
1138 pVert = itrDaug->end_vertex();
1139 }
1140 }
1141 if (samePart) EndVert = pVert;
1142 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1143 }
1144 return EndVert;
1145 }
1146
1148
1149 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1150 if (!theVert) return {};
1151 decltype(theVert->particles_out()) finalStatePart;
1152 auto outgoing = theVert->particles_out();
1153 for (const auto& thePart: outgoing) {
1154 if (!thePart) continue;
1155 finalStatePart.push_back(thePart);
1156 if (isStable(thePart)) continue;
1157 V pVert = findSimulatedEndVertex(thePart);
1158 if (pVert == theVert) break; // to prevent Sherpa loop
1159 if (pVert != nullptr) {
1160 auto vecPart = findFinalStateParticles<V>(pVert);
1161 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1162 }
1163 }
1164 return finalStatePart;
1165 }
1166
1167}
1168#endif

◆ isValid() [3/3]

template<class T>
bool MC::isValid ( const T & p)
inline

Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.

Definition at line 879 of file HepMCHelpers.h.

900{
901inline
902auto particles_in (const HepMC::GenVertex* p) {
903 return std::ranges::subrange (p->particles_in_const_begin(),
904 p->particles_in_const_end());
905}
906}
907#endif
908
909namespace MC
910{
911 template <class VTX>
912 auto particles_in (const VTX* p) { return p->particles_in(); }
913 template <class VTX>
914 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
915
916 namespace Pythia8
917 {
919 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
920
921 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
922
923 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
924 }
925
926#include "AtlasPID.h"
927
929 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
930
932 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
933
935 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
936
938 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
939
941 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
942
944 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
945
947 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
948
950 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
951
953 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
954
956 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
957
961 template <class T> inline bool isStableOrSimDecayed(const T& p) {
962 const auto vertex = p->end_vertex();
963 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
964 }
965
967 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
968
970 template <class T> inline bool isSpecialNonInteracting(const T& p) {
971 const int apid = std::abs(p->pdg_id());
972 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
973 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
974 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
975 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
976 return false;
977 }
978
980
981 template <class T> T findMother(T thePart) {
982 auto partOriVert = thePart->production_vertex();
983 if (!partOriVert) return nullptr;
984
985 long partPDG = thePart->pdg_id();
986 long MotherPDG(0);
987
988 auto MothOriVert = partOriVert;
989 MothOriVert = nullptr;
990 T theMoth(nullptr);
991
992 size_t itr = 0;
993 do {
994 if (itr != 0) partOriVert = MothOriVert;
995 for ( const auto& p : particles_in(partOriVert) ) {
996 theMoth = p;
997 if (!theMoth) continue;
998 MotherPDG = theMoth->pdg_id();
999 MothOriVert = theMoth->production_vertex();
1000 if (MotherPDG == partPDG) break;
1001 }
1002 itr++;
1003 if (itr > 100) {
1004 break;
1005 }
1006 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1007 MothOriVert != partOriVert);
1008 return theMoth;
1009 }
1010
1012
1013 template <class C, class T> T findMatching(C TruthContainer, T p) {
1014 T ptrPart = nullptr;
1015 if (!p) return ptrPart;
1016 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1017 for (T truthParticle : *TruthContainer) {
1018 if (HepMC::is_sim_descendant(p,truthParticle)) {
1019 ptrPart = truthParticle;
1020 break;
1021 }
1022 }
1023 }
1024 else {
1025 for (T truthParticle : TruthContainer) {
1026 if (HepMC::is_sim_descendant(p,truthParticle)) {
1027 ptrPart = truthParticle;
1028 break;
1029 }
1030 }
1031 }
1032 return ptrPart;
1033 }
1035
1036 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1037 auto prodVtx = thePart->production_vertex();
1038 if (!prodVtx) return;
1039 for (const auto& theMother: prodVtx->particles_in()) {
1040 if (!theMother) continue;
1041 allancestors.insert(theMother);
1042 findParticleAncestors(theMother, allancestors);
1043 }
1044 }
1045
1047
1048 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1049 auto endVtx = thePart->end_vertex();
1050 if (!endVtx) return;
1051 for (const auto& theDaughter: endVtx->particles_out()) {
1052 if (!theDaughter) continue;
1053 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1054 allstabledescendants.insert(theDaughter);
1055 }
1056 findParticleStableDescendants(theDaughter, allstabledescendants);
1057 }
1058 }
1059
1063
1064 template <class T> bool isHardScatteringVertex(T pVert) {
1065 if (pVert == nullptr) return false;
1066 T pV = pVert;
1067 int numOfPartIn(0);
1068 int pdg(0);
1069
1070 do {
1071 pVert = pV;
1072 auto incoming = pVert->particles_in();
1073 numOfPartIn = incoming.size();
1074 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1075 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1076
1077 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1078
1079 if (numOfPartIn == 2) {
1080 auto incoming = pVert->particles_in();
1081 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1082 }
1083 return false;
1084}
1085
1089
1090 template <class T, class U>
1091 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1092 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1093 auto vtx = p->production_vertex();
1094 if (!vtx) return false;
1095 bool fromHad = false;
1096 for ( const auto& parent : particles_in(vtx) ) {
1097 if (!parent) continue;
1098 // should this really go into parton-level territory?
1099 // probably depends where BSM particles are being decayed
1100 fromBSM |= isBSM(parent);
1101 if (!isPhysical(parent)) return false;
1102 fromTau |= isTau(parent);
1103 if (isHadron(parent)&&!isBeam(parent)) {
1104 if (!hadron) hadron = parent; // assumes linear hadron parentage
1105 return true;
1106 }
1107 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1108 }
1109 return fromHad;
1110 }
1111
1114
1115 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1116 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1117 decltype(thePart->end_vertex()) pVert(nullptr);
1118 if (EndVert != nullptr) {
1119 do {
1120 bool samePart = false;
1121 pVert = nullptr;
1122 auto outgoing = EndVert->particles_out();
1123 auto incoming = EndVert->particles_in();
1124 for (const auto& itrDaug: outgoing) {
1125 if (!itrDaug) continue;
1126 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1127 // brem on generator level for tau
1128 (outgoing.size() == 1 && incoming.size() == 1 &&
1130 itrDaug->pdg_id() == thePart->pdg_id()) {
1131 samePart = true;
1132 pVert = itrDaug->end_vertex();
1133 }
1134 }
1135 if (samePart) EndVert = pVert;
1136 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1137 }
1138 return EndVert;
1139 }
1140
1142
1143 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1144 if (!theVert) return {};
1145 decltype(theVert->particles_out()) finalStatePart;
1146 auto outgoing = theVert->particles_out();
1147 for (const auto& thePart: outgoing) {
1148 if (!thePart) continue;
1149 finalStatePart.push_back(thePart);
1150 if (isStable(thePart)) continue;
1151 V pVert = findSimulatedEndVertex(thePart);
1152 if (pVert == theVert) break; // to prevent Sherpa loop
1153 if (pVert != nullptr) {
1154 auto vecPart = findFinalStateParticles<V>(pVert);
1155 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1156 }
1157 }
1158 return finalStatePart;
1159 }
1160
1161}
1162#endif

◆ isW() [1/2]

template<>
bool MC::isW ( const int & p)
inline

Definition at line 384 of file HepMCHelpers.h.

405{
406inline
407auto particles_in (const HepMC::GenVertex* p) {
408 return std::ranges::subrange (p->particles_in_const_begin(),
409 p->particles_in_const_end());
410}
411}
412#endif
413
414namespace MC
415{
416 template <class VTX>
417 auto particles_in (const VTX* p) { return p->particles_in(); }
418 template <class VTX>
419 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
420
421 namespace Pythia8
422 {
424 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
425
426 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
427
428 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
429 }
430
431#include "AtlasPID.h"
432
434 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
435
437 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
438
440 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
441
443 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
444
446 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
447
449 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
450
452 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
453
455 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
456
458 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
459
461 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
462
466 template <class T> inline bool isStableOrSimDecayed(const T& p) {
467 const auto vertex = p->end_vertex();
468 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
469 }
470
472 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
473
475 template <class T> inline bool isSpecialNonInteracting(const T& p) {
476 const int apid = std::abs(p->pdg_id());
477 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
478 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
479 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
480 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
481 return false;
482 }
483
485
486 template <class T> T findMother(T thePart) {
487 auto partOriVert = thePart->production_vertex();
488 if (!partOriVert) return nullptr;
489
490 long partPDG = thePart->pdg_id();
491 long MotherPDG(0);
492
493 auto MothOriVert = partOriVert;
494 MothOriVert = nullptr;
495 T theMoth(nullptr);
496
497 size_t itr = 0;
498 do {
499 if (itr != 0) partOriVert = MothOriVert;
500 for ( const auto& p : particles_in(partOriVert) ) {
501 theMoth = p;
502 if (!theMoth) continue;
503 MotherPDG = theMoth->pdg_id();
504 MothOriVert = theMoth->production_vertex();
505 if (MotherPDG == partPDG) break;
506 }
507 itr++;
508 if (itr > 100) {
509 break;
510 }
511 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
512 MothOriVert != partOriVert);
513 return theMoth;
514 }
515
517
518 template <class C, class T> T findMatching(C TruthContainer, T p) {
519 T ptrPart = nullptr;
520 if (!p) return ptrPart;
521 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
522 for (T truthParticle : *TruthContainer) {
523 if (HepMC::is_sim_descendant(p,truthParticle)) {
524 ptrPart = truthParticle;
525 break;
526 }
527 }
528 }
529 else {
530 for (T truthParticle : TruthContainer) {
531 if (HepMC::is_sim_descendant(p,truthParticle)) {
532 ptrPart = truthParticle;
533 break;
534 }
535 }
536 }
537 return ptrPart;
538 }
540
541 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
542 auto prodVtx = thePart->production_vertex();
543 if (!prodVtx) return;
544 for (const auto& theMother: prodVtx->particles_in()) {
545 if (!theMother) continue;
546 allancestors.insert(theMother);
547 findParticleAncestors(theMother, allancestors);
548 }
549 }
550
552
553 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
554 auto endVtx = thePart->end_vertex();
555 if (!endVtx) return;
556 for (const auto& theDaughter: endVtx->particles_out()) {
557 if (!theDaughter) continue;
558 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
559 allstabledescendants.insert(theDaughter);
560 }
561 findParticleStableDescendants(theDaughter, allstabledescendants);
562 }
563 }
564
568
569 template <class T> bool isHardScatteringVertex(T pVert) {
570 if (pVert == nullptr) return false;
571 T pV = pVert;
572 int numOfPartIn(0);
573 int pdg(0);
574
575 do {
576 pVert = pV;
577 auto incoming = pVert->particles_in();
578 numOfPartIn = incoming.size();
579 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
580 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
581
582 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
583
584 if (numOfPartIn == 2) {
585 auto incoming = pVert->particles_in();
586 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
587 }
588 return false;
589}
590
594
595 template <class T, class U>
596 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
597 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
598 auto vtx = p->production_vertex();
599 if (!vtx) return false;
600 bool fromHad = false;
601 for ( const auto& parent : particles_in(vtx) ) {
602 if (!parent) continue;
603 // should this really go into parton-level territory?
604 // probably depends where BSM particles are being decayed
605 fromBSM |= isBSM(parent);
606 if (!isPhysical(parent)) return false;
607 fromTau |= isTau(parent);
608 if (isHadron(parent)&&!isBeam(parent)) {
609 if (!hadron) hadron = parent; // assumes linear hadron parentage
610 return true;
611 }
612 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
613 }
614 return fromHad;
615 }
616
619
620 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
621 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
622 decltype(thePart->end_vertex()) pVert(nullptr);
623 if (EndVert != nullptr) {
624 do {
625 bool samePart = false;
626 pVert = nullptr;
627 auto outgoing = EndVert->particles_out();
628 auto incoming = EndVert->particles_in();
629 for (const auto& itrDaug: outgoing) {
630 if (!itrDaug) continue;
631 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
632 // brem on generator level for tau
633 (outgoing.size() == 1 && incoming.size() == 1 &&
635 itrDaug->pdg_id() == thePart->pdg_id()) {
636 samePart = true;
637 pVert = itrDaug->end_vertex();
638 }
639 }
640 if (samePart) EndVert = pVert;
641 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
642 }
643 return EndVert;
644 }
645
647
648 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
649 if (!theVert) return {};
650 decltype(theVert->particles_out()) finalStatePart;
651 auto outgoing = theVert->particles_out();
652 for (const auto& thePart: outgoing) {
653 if (!thePart) continue;
654 finalStatePart.push_back(thePart);
655 if (isStable(thePart)) continue;
656 V pVert = findSimulatedEndVertex(thePart);
657 if (pVert == theVert) break; // to prevent Sherpa loop
658 if (pVert != nullptr) {
659 auto vecPart = findFinalStateParticles<V>(pVert);
660 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
661 }
662 }
663 return finalStatePart;
664 }
665
666}
667#endif

◆ isW() [2/2]

template<class T>
bool MC::isW ( const T & p)
inline

Definition at line 383 of file HepMCHelpers.h.

404{
405inline
406auto particles_in (const HepMC::GenVertex* p) {
407 return std::ranges::subrange (p->particles_in_const_begin(),
408 p->particles_in_const_end());
409}
410}
411#endif
412
413namespace MC
414{
415 template <class VTX>
416 auto particles_in (const VTX* p) { return p->particles_in(); }
417 template <class VTX>
418 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
419
420 namespace Pythia8
421 {
423 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
424
425 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
426
427 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
428 }
429
430#include "AtlasPID.h"
431
433 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
434
436 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
437
439 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
440
442 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
443
445 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
446
448 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
449
451 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
452
454 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
455
457 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
458
460 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
461
465 template <class T> inline bool isStableOrSimDecayed(const T& p) {
466 const auto vertex = p->end_vertex();
467 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
468 }
469
471 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
472
474 template <class T> inline bool isSpecialNonInteracting(const T& p) {
475 const int apid = std::abs(p->pdg_id());
476 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
477 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
478 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
479 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
480 return false;
481 }
482
484
485 template <class T> T findMother(T thePart) {
486 auto partOriVert = thePart->production_vertex();
487 if (!partOriVert) return nullptr;
488
489 long partPDG = thePart->pdg_id();
490 long MotherPDG(0);
491
492 auto MothOriVert = partOriVert;
493 MothOriVert = nullptr;
494 T theMoth(nullptr);
495
496 size_t itr = 0;
497 do {
498 if (itr != 0) partOriVert = MothOriVert;
499 for ( const auto& p : particles_in(partOriVert) ) {
500 theMoth = p;
501 if (!theMoth) continue;
502 MotherPDG = theMoth->pdg_id();
503 MothOriVert = theMoth->production_vertex();
504 if (MotherPDG == partPDG) break;
505 }
506 itr++;
507 if (itr > 100) {
508 break;
509 }
510 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
511 MothOriVert != partOriVert);
512 return theMoth;
513 }
514
516
517 template <class C, class T> T findMatching(C TruthContainer, T p) {
518 T ptrPart = nullptr;
519 if (!p) return ptrPart;
520 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
521 for (T truthParticle : *TruthContainer) {
522 if (HepMC::is_sim_descendant(p,truthParticle)) {
523 ptrPart = truthParticle;
524 break;
525 }
526 }
527 }
528 else {
529 for (T truthParticle : TruthContainer) {
530 if (HepMC::is_sim_descendant(p,truthParticle)) {
531 ptrPart = truthParticle;
532 break;
533 }
534 }
535 }
536 return ptrPart;
537 }
539
540 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
541 auto prodVtx = thePart->production_vertex();
542 if (!prodVtx) return;
543 for (const auto& theMother: prodVtx->particles_in()) {
544 if (!theMother) continue;
545 allancestors.insert(theMother);
546 findParticleAncestors(theMother, allancestors);
547 }
548 }
549
551
552 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
553 auto endVtx = thePart->end_vertex();
554 if (!endVtx) return;
555 for (const auto& theDaughter: endVtx->particles_out()) {
556 if (!theDaughter) continue;
557 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
558 allstabledescendants.insert(theDaughter);
559 }
560 findParticleStableDescendants(theDaughter, allstabledescendants);
561 }
562 }
563
567
568 template <class T> bool isHardScatteringVertex(T pVert) {
569 if (pVert == nullptr) return false;
570 T pV = pVert;
571 int numOfPartIn(0);
572 int pdg(0);
573
574 do {
575 pVert = pV;
576 auto incoming = pVert->particles_in();
577 numOfPartIn = incoming.size();
578 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
579 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
580
581 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
582
583 if (numOfPartIn == 2) {
584 auto incoming = pVert->particles_in();
585 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
586 }
587 return false;
588}
589
593
594 template <class T, class U>
595 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
596 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
597 auto vtx = p->production_vertex();
598 if (!vtx) return false;
599 bool fromHad = false;
600 for ( const auto& parent : particles_in(vtx) ) {
601 if (!parent) continue;
602 // should this really go into parton-level territory?
603 // probably depends where BSM particles are being decayed
604 fromBSM |= isBSM(parent);
605 if (!isPhysical(parent)) return false;
606 fromTau |= isTau(parent);
607 if (isHadron(parent)&&!isBeam(parent)) {
608 if (!hadron) hadron = parent; // assumes linear hadron parentage
609 return true;
610 }
611 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
612 }
613 return fromHad;
614 }
615
618
619 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
620 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
621 decltype(thePart->end_vertex()) pVert(nullptr);
622 if (EndVert != nullptr) {
623 do {
624 bool samePart = false;
625 pVert = nullptr;
626 auto outgoing = EndVert->particles_out();
627 auto incoming = EndVert->particles_in();
628 for (const auto& itrDaug: outgoing) {
629 if (!itrDaug) continue;
630 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
631 // brem on generator level for tau
632 (outgoing.size() == 1 && incoming.size() == 1 &&
634 itrDaug->pdg_id() == thePart->pdg_id()) {
635 samePart = true;
636 pVert = itrDaug->end_vertex();
637 }
638 }
639 if (samePart) EndVert = pVert;
640 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
641 }
642 return EndVert;
643 }
644
646
647 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
648 if (!theVert) return {};
649 decltype(theVert->particles_out()) finalStatePart;
650 auto outgoing = theVert->particles_out();
651 for (const auto& thePart: outgoing) {
652 if (!thePart) continue;
653 finalStatePart.push_back(thePart);
654 if (isStable(thePart)) continue;
655 V pVert = findSimulatedEndVertex(thePart);
656 if (pVert == theVert) break; // to prevent Sherpa loop
657 if (pVert != nullptr) {
658 auto vecPart = findFinalStateParticles<V>(pVert);
659 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
660 }
661 }
662 return finalStatePart;
663 }
664
665}
666#endif

◆ isWeaklyDecayingBHadron() [1/3]

template<>
bool MC::isWeaklyDecayingBHadron ( const DecodedPID & p)
inline

Definition at line 969 of file HepMCHelpers.h.

990{
991inline
992auto particles_in (const HepMC::GenVertex* p) {
993 return std::ranges::subrange (p->particles_in_const_begin(),
994 p->particles_in_const_end());
995}
996}
997#endif
998
999namespace MC
1000{
1001 template <class VTX>
1002 auto particles_in (const VTX* p) { return p->particles_in(); }
1003 template <class VTX>
1004 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1005
1006 namespace Pythia8
1007 {
1009 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1010
1011 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1012
1013 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1014 }
1015
1016#include "AtlasPID.h"
1017
1019 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1020
1022 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1023
1025 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1026
1028 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1029
1031 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1032
1034 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1035
1037 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1038
1040 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1041
1043 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1044
1046 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1047
1051 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1052 const auto vertex = p->end_vertex();
1053 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1054 }
1055
1057 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1058
1060 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1061 const int apid = std::abs(p->pdg_id());
1062 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1063 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1064 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1065 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1066 return false;
1067 }
1068
1070
1071 template <class T> T findMother(T thePart) {
1072 auto partOriVert = thePart->production_vertex();
1073 if (!partOriVert) return nullptr;
1074
1075 long partPDG = thePart->pdg_id();
1076 long MotherPDG(0);
1077
1078 auto MothOriVert = partOriVert;
1079 MothOriVert = nullptr;
1080 T theMoth(nullptr);
1081
1082 size_t itr = 0;
1083 do {
1084 if (itr != 0) partOriVert = MothOriVert;
1085 for ( const auto& p : particles_in(partOriVert) ) {
1086 theMoth = p;
1087 if (!theMoth) continue;
1088 MotherPDG = theMoth->pdg_id();
1089 MothOriVert = theMoth->production_vertex();
1090 if (MotherPDG == partPDG) break;
1091 }
1092 itr++;
1093 if (itr > 100) {
1094 break;
1095 }
1096 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1097 MothOriVert != partOriVert);
1098 return theMoth;
1099 }
1100
1102
1103 template <class C, class T> T findMatching(C TruthContainer, T p) {
1104 T ptrPart = nullptr;
1105 if (!p) return ptrPart;
1106 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1107 for (T truthParticle : *TruthContainer) {
1108 if (HepMC::is_sim_descendant(p,truthParticle)) {
1109 ptrPart = truthParticle;
1110 break;
1111 }
1112 }
1113 }
1114 else {
1115 for (T truthParticle : TruthContainer) {
1116 if (HepMC::is_sim_descendant(p,truthParticle)) {
1117 ptrPart = truthParticle;
1118 break;
1119 }
1120 }
1121 }
1122 return ptrPart;
1123 }
1125
1126 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1127 auto prodVtx = thePart->production_vertex();
1128 if (!prodVtx) return;
1129 for (const auto& theMother: prodVtx->particles_in()) {
1130 if (!theMother) continue;
1131 allancestors.insert(theMother);
1132 findParticleAncestors(theMother, allancestors);
1133 }
1134 }
1135
1137
1138 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1139 auto endVtx = thePart->end_vertex();
1140 if (!endVtx) return;
1141 for (const auto& theDaughter: endVtx->particles_out()) {
1142 if (!theDaughter) continue;
1143 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1144 allstabledescendants.insert(theDaughter);
1145 }
1146 findParticleStableDescendants(theDaughter, allstabledescendants);
1147 }
1148 }
1149
1153
1154 template <class T> bool isHardScatteringVertex(T pVert) {
1155 if (pVert == nullptr) return false;
1156 T pV = pVert;
1157 int numOfPartIn(0);
1158 int pdg(0);
1159
1160 do {
1161 pVert = pV;
1162 auto incoming = pVert->particles_in();
1163 numOfPartIn = incoming.size();
1164 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1165 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1166
1167 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1168
1169 if (numOfPartIn == 2) {
1170 auto incoming = pVert->particles_in();
1171 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1172 }
1173 return false;
1174}
1175
1179
1180 template <class T, class U>
1181 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1182 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1183 auto vtx = p->production_vertex();
1184 if (!vtx) return false;
1185 bool fromHad = false;
1186 for ( const auto& parent : particles_in(vtx) ) {
1187 if (!parent) continue;
1188 // should this really go into parton-level territory?
1189 // probably depends where BSM particles are being decayed
1190 fromBSM |= isBSM(parent);
1191 if (!isPhysical(parent)) return false;
1192 fromTau |= isTau(parent);
1193 if (isHadron(parent)&&!isBeam(parent)) {
1194 if (!hadron) hadron = parent; // assumes linear hadron parentage
1195 return true;
1196 }
1197 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1198 }
1199 return fromHad;
1200 }
1201
1204
1205 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1206 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1207 decltype(thePart->end_vertex()) pVert(nullptr);
1208 if (EndVert != nullptr) {
1209 do {
1210 bool samePart = false;
1211 pVert = nullptr;
1212 auto outgoing = EndVert->particles_out();
1213 auto incoming = EndVert->particles_in();
1214 for (const auto& itrDaug: outgoing) {
1215 if (!itrDaug) continue;
1216 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1217 // brem on generator level for tau
1218 (outgoing.size() == 1 && incoming.size() == 1 &&
1220 itrDaug->pdg_id() == thePart->pdg_id()) {
1221 samePart = true;
1222 pVert = itrDaug->end_vertex();
1223 }
1224 }
1225 if (samePart) EndVert = pVert;
1226 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1227 }
1228 return EndVert;
1229 }
1230
1232
1233 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1234 if (!theVert) return {};
1235 decltype(theVert->particles_out()) finalStatePart;
1236 auto outgoing = theVert->particles_out();
1237 for (const auto& thePart: outgoing) {
1238 if (!thePart) continue;
1239 finalStatePart.push_back(thePart);
1240 if (isStable(thePart)) continue;
1241 V pVert = findSimulatedEndVertex(thePart);
1242 if (pVert == theVert) break; // to prevent Sherpa loop
1243 if (pVert != nullptr) {
1244 auto vecPart = findFinalStateParticles<V>(pVert);
1245 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1246 }
1247 }
1248 return finalStatePart;
1249 }
1250
1251}
1252#endif

◆ isWeaklyDecayingBHadron() [2/3]

template<>
bool MC::isWeaklyDecayingBHadron ( const int & p)
inline

Definition at line 944 of file HepMCHelpers.h.

965 {
966inline
967auto particles_in (const HepMC::GenVertex* p) {
968 return std::ranges::subrange (p->particles_in_const_begin(),
969 p->particles_in_const_end());
970}
971}
972#endif
973
974namespace MC
975{
976 template <class VTX>
977 auto particles_in (const VTX* p) { return p->particles_in(); }
978 template <class VTX>
979 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
980
981 namespace Pythia8
982 {
984 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
985
986 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
987
988 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
989 }
990
991#include "AtlasPID.h"
992
994 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
995
997 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
998
1000 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1001
1003 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1004
1006 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1007
1009 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1010
1012 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1013
1015 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1016
1018 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1019
1021 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1022
1026 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1027 const auto vertex = p->end_vertex();
1028 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1029 }
1030
1032 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1033
1035 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1036 const int apid = std::abs(p->pdg_id());
1037 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1038 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1039 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1040 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1041 return false;
1042 }
1043
1045
1046 template <class T> T findMother(T thePart) {
1047 auto partOriVert = thePart->production_vertex();
1048 if (!partOriVert) return nullptr;
1049
1050 long partPDG = thePart->pdg_id();
1051 long MotherPDG(0);
1052
1053 auto MothOriVert = partOriVert;
1054 MothOriVert = nullptr;
1055 T theMoth(nullptr);
1056
1057 size_t itr = 0;
1058 do {
1059 if (itr != 0) partOriVert = MothOriVert;
1060 for ( const auto& p : particles_in(partOriVert) ) {
1061 theMoth = p;
1062 if (!theMoth) continue;
1063 MotherPDG = theMoth->pdg_id();
1064 MothOriVert = theMoth->production_vertex();
1065 if (MotherPDG == partPDG) break;
1066 }
1067 itr++;
1068 if (itr > 100) {
1069 break;
1070 }
1071 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1072 MothOriVert != partOriVert);
1073 return theMoth;
1074 }
1075
1077
1078 template <class C, class T> T findMatching(C TruthContainer, T p) {
1079 T ptrPart = nullptr;
1080 if (!p) return ptrPart;
1081 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1082 for (T truthParticle : *TruthContainer) {
1083 if (HepMC::is_sim_descendant(p,truthParticle)) {
1084 ptrPart = truthParticle;
1085 break;
1086 }
1087 }
1088 }
1089 else {
1090 for (T truthParticle : TruthContainer) {
1091 if (HepMC::is_sim_descendant(p,truthParticle)) {
1092 ptrPart = truthParticle;
1093 break;
1094 }
1095 }
1096 }
1097 return ptrPart;
1098 }
1100
1101 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1102 auto prodVtx = thePart->production_vertex();
1103 if (!prodVtx) return;
1104 for (const auto& theMother: prodVtx->particles_in()) {
1105 if (!theMother) continue;
1106 allancestors.insert(theMother);
1107 findParticleAncestors(theMother, allancestors);
1108 }
1109 }
1110
1112
1113 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1114 auto endVtx = thePart->end_vertex();
1115 if (!endVtx) return;
1116 for (const auto& theDaughter: endVtx->particles_out()) {
1117 if (!theDaughter) continue;
1118 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1119 allstabledescendants.insert(theDaughter);
1120 }
1121 findParticleStableDescendants(theDaughter, allstabledescendants);
1122 }
1123 }
1124
1128
1129 template <class T> bool isHardScatteringVertex(T pVert) {
1130 if (pVert == nullptr) return false;
1131 T pV = pVert;
1132 int numOfPartIn(0);
1133 int pdg(0);
1134
1135 do {
1136 pVert = pV;
1137 auto incoming = pVert->particles_in();
1138 numOfPartIn = incoming.size();
1139 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1140 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1141
1142 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1143
1144 if (numOfPartIn == 2) {
1145 auto incoming = pVert->particles_in();
1146 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1147 }
1148 return false;
1149}
1150
1154
1155 template <class T, class U>
1156 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1157 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1158 auto vtx = p->production_vertex();
1159 if (!vtx) return false;
1160 bool fromHad = false;
1161 for ( const auto& parent : particles_in(vtx) ) {
1162 if (!parent) continue;
1163 // should this really go into parton-level territory?
1164 // probably depends where BSM particles are being decayed
1165 fromBSM |= isBSM(parent);
1166 if (!isPhysical(parent)) return false;
1167 fromTau |= isTau(parent);
1168 if (isHadron(parent)&&!isBeam(parent)) {
1169 if (!hadron) hadron = parent; // assumes linear hadron parentage
1170 return true;
1171 }
1172 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1173 }
1174 return fromHad;
1175 }
1176
1179
1180 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1181 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1182 decltype(thePart->end_vertex()) pVert(nullptr);
1183 if (EndVert != nullptr) {
1184 do {
1185 bool samePart = false;
1186 pVert = nullptr;
1187 auto outgoing = EndVert->particles_out();
1188 auto incoming = EndVert->particles_in();
1189 for (const auto& itrDaug: outgoing) {
1190 if (!itrDaug) continue;
1191 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1192 // brem on generator level for tau
1193 (outgoing.size() == 1 && incoming.size() == 1 &&
1195 itrDaug->pdg_id() == thePart->pdg_id()) {
1196 samePart = true;
1197 pVert = itrDaug->end_vertex();
1198 }
1199 }
1200 if (samePart) EndVert = pVert;
1201 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1202 }
1203 return EndVert;
1204 }
1205
1207
1208 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1209 if (!theVert) return {};
1210 decltype(theVert->particles_out()) finalStatePart;
1211 auto outgoing = theVert->particles_out();
1212 for (const auto& thePart: outgoing) {
1213 if (!thePart) continue;
1214 finalStatePart.push_back(thePart);
1215 if (isStable(thePart)) continue;
1216 V pVert = findSimulatedEndVertex(thePart);
1217 if (pVert == theVert) break; // to prevent Sherpa loop
1218 if (pVert != nullptr) {
1219 auto vecPart = findFinalStateParticles<V>(pVert);
1220 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1221 }
1222 }
1223 return finalStatePart;
1224 }
1225
1226}
1227#endif

◆ isWeaklyDecayingBHadron() [3/3]

template<class T>
bool MC::isWeaklyDecayingBHadron ( const T & p)
inline

Definition at line 943 of file HepMCHelpers.h.

964{
965inline
966auto particles_in (const HepMC::GenVertex* p) {
967 return std::ranges::subrange (p->particles_in_const_begin(),
968 p->particles_in_const_end());
969}
970}
971#endif
972
973namespace MC
974{
975 template <class VTX>
976 auto particles_in (const VTX* p) { return p->particles_in(); }
977 template <class VTX>
978 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
979
980 namespace Pythia8
981 {
983 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
984
985 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
986
987 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
988 }
989
990#include "AtlasPID.h"
991
993 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
994
996 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
997
999 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1000
1002 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1003
1005 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1006
1008 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1009
1011 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1012
1014 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1015
1017 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1018
1020 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1021
1025 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1026 const auto vertex = p->end_vertex();
1027 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1028 }
1029
1031 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1032
1034 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1035 const int apid = std::abs(p->pdg_id());
1036 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1037 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1038 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1039 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1040 return false;
1041 }
1042
1044
1045 template <class T> T findMother(T thePart) {
1046 auto partOriVert = thePart->production_vertex();
1047 if (!partOriVert) return nullptr;
1048
1049 long partPDG = thePart->pdg_id();
1050 long MotherPDG(0);
1051
1052 auto MothOriVert = partOriVert;
1053 MothOriVert = nullptr;
1054 T theMoth(nullptr);
1055
1056 size_t itr = 0;
1057 do {
1058 if (itr != 0) partOriVert = MothOriVert;
1059 for ( const auto& p : particles_in(partOriVert) ) {
1060 theMoth = p;
1061 if (!theMoth) continue;
1062 MotherPDG = theMoth->pdg_id();
1063 MothOriVert = theMoth->production_vertex();
1064 if (MotherPDG == partPDG) break;
1065 }
1066 itr++;
1067 if (itr > 100) {
1068 break;
1069 }
1070 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1071 MothOriVert != partOriVert);
1072 return theMoth;
1073 }
1074
1076
1077 template <class C, class T> T findMatching(C TruthContainer, T p) {
1078 T ptrPart = nullptr;
1079 if (!p) return ptrPart;
1080 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1081 for (T truthParticle : *TruthContainer) {
1082 if (HepMC::is_sim_descendant(p,truthParticle)) {
1083 ptrPart = truthParticle;
1084 break;
1085 }
1086 }
1087 }
1088 else {
1089 for (T truthParticle : TruthContainer) {
1090 if (HepMC::is_sim_descendant(p,truthParticle)) {
1091 ptrPart = truthParticle;
1092 break;
1093 }
1094 }
1095 }
1096 return ptrPart;
1097 }
1099
1100 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1101 auto prodVtx = thePart->production_vertex();
1102 if (!prodVtx) return;
1103 for (const auto& theMother: prodVtx->particles_in()) {
1104 if (!theMother) continue;
1105 allancestors.insert(theMother);
1106 findParticleAncestors(theMother, allancestors);
1107 }
1108 }
1109
1111
1112 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1113 auto endVtx = thePart->end_vertex();
1114 if (!endVtx) return;
1115 for (const auto& theDaughter: endVtx->particles_out()) {
1116 if (!theDaughter) continue;
1117 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1118 allstabledescendants.insert(theDaughter);
1119 }
1120 findParticleStableDescendants(theDaughter, allstabledescendants);
1121 }
1122 }
1123
1127
1128 template <class T> bool isHardScatteringVertex(T pVert) {
1129 if (pVert == nullptr) return false;
1130 T pV = pVert;
1131 int numOfPartIn(0);
1132 int pdg(0);
1133
1134 do {
1135 pVert = pV;
1136 auto incoming = pVert->particles_in();
1137 numOfPartIn = incoming.size();
1138 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1139 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1140
1141 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1142
1143 if (numOfPartIn == 2) {
1144 auto incoming = pVert->particles_in();
1145 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1146 }
1147 return false;
1148}
1149
1153
1154 template <class T, class U>
1155 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1156 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1157 auto vtx = p->production_vertex();
1158 if (!vtx) return false;
1159 bool fromHad = false;
1160 for ( const auto& parent : particles_in(vtx) ) {
1161 if (!parent) continue;
1162 // should this really go into parton-level territory?
1163 // probably depends where BSM particles are being decayed
1164 fromBSM |= isBSM(parent);
1165 if (!isPhysical(parent)) return false;
1166 fromTau |= isTau(parent);
1167 if (isHadron(parent)&&!isBeam(parent)) {
1168 if (!hadron) hadron = parent; // assumes linear hadron parentage
1169 return true;
1170 }
1171 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1172 }
1173 return fromHad;
1174 }
1175
1178
1179 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1180 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1181 decltype(thePart->end_vertex()) pVert(nullptr);
1182 if (EndVert != nullptr) {
1183 do {
1184 bool samePart = false;
1185 pVert = nullptr;
1186 auto outgoing = EndVert->particles_out();
1187 auto incoming = EndVert->particles_in();
1188 for (const auto& itrDaug: outgoing) {
1189 if (!itrDaug) continue;
1190 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1191 // brem on generator level for tau
1192 (outgoing.size() == 1 && incoming.size() == 1 &&
1194 itrDaug->pdg_id() == thePart->pdg_id()) {
1195 samePart = true;
1196 pVert = itrDaug->end_vertex();
1197 }
1198 }
1199 if (samePart) EndVert = pVert;
1200 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1201 }
1202 return EndVert;
1203 }
1204
1206
1207 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1208 if (!theVert) return {};
1209 decltype(theVert->particles_out()) finalStatePart;
1210 auto outgoing = theVert->particles_out();
1211 for (const auto& thePart: outgoing) {
1212 if (!thePart) continue;
1213 finalStatePart.push_back(thePart);
1214 if (isStable(thePart)) continue;
1215 V pVert = findSimulatedEndVertex(thePart);
1216 if (pVert == theVert) break; // to prevent Sherpa loop
1217 if (pVert != nullptr) {
1218 auto vecPart = findFinalStateParticles<V>(pVert);
1219 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1220 }
1221 }
1222 return finalStatePart;
1223 }
1224
1225}
1226#endif

◆ isWeaklyDecayingCHadron() [1/3]

template<>
bool MC::isWeaklyDecayingCHadron ( const DecodedPID & p)
inline

Definition at line 993 of file HepMCHelpers.h.

1014{
1015inline
1016auto particles_in (const HepMC::GenVertex* p) {
1017 return std::ranges::subrange (p->particles_in_const_begin(),
1018 p->particles_in_const_end());
1019}
1020}
1021#endif
1022
1023namespace MC
1024{
1025 template <class VTX>
1026 auto particles_in (const VTX* p) { return p->particles_in(); }
1027 template <class VTX>
1028 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1029
1030 namespace Pythia8
1031 {
1033 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1034
1035 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1036
1037 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1038 }
1039
1040#include "AtlasPID.h"
1041
1043 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1044
1046 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1047
1049 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1050
1052 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1053
1055 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1056
1058 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1059
1061 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1062
1064 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1065
1067 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1068
1070 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1071
1075 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1076 const auto vertex = p->end_vertex();
1077 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1078 }
1079
1081 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1082
1084 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1085 const int apid = std::abs(p->pdg_id());
1086 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1087 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1088 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1089 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1090 return false;
1091 }
1092
1094
1095 template <class T> T findMother(T thePart) {
1096 auto partOriVert = thePart->production_vertex();
1097 if (!partOriVert) return nullptr;
1098
1099 long partPDG = thePart->pdg_id();
1100 long MotherPDG(0);
1101
1102 auto MothOriVert = partOriVert;
1103 MothOriVert = nullptr;
1104 T theMoth(nullptr);
1105
1106 size_t itr = 0;
1107 do {
1108 if (itr != 0) partOriVert = MothOriVert;
1109 for ( const auto& p : particles_in(partOriVert) ) {
1110 theMoth = p;
1111 if (!theMoth) continue;
1112 MotherPDG = theMoth->pdg_id();
1113 MothOriVert = theMoth->production_vertex();
1114 if (MotherPDG == partPDG) break;
1115 }
1116 itr++;
1117 if (itr > 100) {
1118 break;
1119 }
1120 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1121 MothOriVert != partOriVert);
1122 return theMoth;
1123 }
1124
1126
1127 template <class C, class T> T findMatching(C TruthContainer, T p) {
1128 T ptrPart = nullptr;
1129 if (!p) return ptrPart;
1130 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1131 for (T truthParticle : *TruthContainer) {
1132 if (HepMC::is_sim_descendant(p,truthParticle)) {
1133 ptrPart = truthParticle;
1134 break;
1135 }
1136 }
1137 }
1138 else {
1139 for (T truthParticle : TruthContainer) {
1140 if (HepMC::is_sim_descendant(p,truthParticle)) {
1141 ptrPart = truthParticle;
1142 break;
1143 }
1144 }
1145 }
1146 return ptrPart;
1147 }
1149
1150 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1151 auto prodVtx = thePart->production_vertex();
1152 if (!prodVtx) return;
1153 for (const auto& theMother: prodVtx->particles_in()) {
1154 if (!theMother) continue;
1155 allancestors.insert(theMother);
1156 findParticleAncestors(theMother, allancestors);
1157 }
1158 }
1159
1161
1162 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1163 auto endVtx = thePart->end_vertex();
1164 if (!endVtx) return;
1165 for (const auto& theDaughter: endVtx->particles_out()) {
1166 if (!theDaughter) continue;
1167 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1168 allstabledescendants.insert(theDaughter);
1169 }
1170 findParticleStableDescendants(theDaughter, allstabledescendants);
1171 }
1172 }
1173
1177
1178 template <class T> bool isHardScatteringVertex(T pVert) {
1179 if (pVert == nullptr) return false;
1180 T pV = pVert;
1181 int numOfPartIn(0);
1182 int pdg(0);
1183
1184 do {
1185 pVert = pV;
1186 auto incoming = pVert->particles_in();
1187 numOfPartIn = incoming.size();
1188 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1189 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1190
1191 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1192
1193 if (numOfPartIn == 2) {
1194 auto incoming = pVert->particles_in();
1195 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1196 }
1197 return false;
1198}
1199
1203
1204 template <class T, class U>
1205 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1206 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1207 auto vtx = p->production_vertex();
1208 if (!vtx) return false;
1209 bool fromHad = false;
1210 for ( const auto& parent : particles_in(vtx) ) {
1211 if (!parent) continue;
1212 // should this really go into parton-level territory?
1213 // probably depends where BSM particles are being decayed
1214 fromBSM |= isBSM(parent);
1215 if (!isPhysical(parent)) return false;
1216 fromTau |= isTau(parent);
1217 if (isHadron(parent)&&!isBeam(parent)) {
1218 if (!hadron) hadron = parent; // assumes linear hadron parentage
1219 return true;
1220 }
1221 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1222 }
1223 return fromHad;
1224 }
1225
1228
1229 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1230 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1231 decltype(thePart->end_vertex()) pVert(nullptr);
1232 if (EndVert != nullptr) {
1233 do {
1234 bool samePart = false;
1235 pVert = nullptr;
1236 auto outgoing = EndVert->particles_out();
1237 auto incoming = EndVert->particles_in();
1238 for (const auto& itrDaug: outgoing) {
1239 if (!itrDaug) continue;
1240 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1241 // brem on generator level for tau
1242 (outgoing.size() == 1 && incoming.size() == 1 &&
1244 itrDaug->pdg_id() == thePart->pdg_id()) {
1245 samePart = true;
1246 pVert = itrDaug->end_vertex();
1247 }
1248 }
1249 if (samePart) EndVert = pVert;
1250 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1251 }
1252 return EndVert;
1253 }
1254
1256
1257 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1258 if (!theVert) return {};
1259 decltype(theVert->particles_out()) finalStatePart;
1260 auto outgoing = theVert->particles_out();
1261 for (const auto& thePart: outgoing) {
1262 if (!thePart) continue;
1263 finalStatePart.push_back(thePart);
1264 if (isStable(thePart)) continue;
1265 V pVert = findSimulatedEndVertex(thePart);
1266 if (pVert == theVert) break; // to prevent Sherpa loop
1267 if (pVert != nullptr) {
1268 auto vecPart = findFinalStateParticles<V>(pVert);
1269 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1270 }
1271 }
1272 return finalStatePart;
1273 }
1274
1275}
1276#endif

◆ isWeaklyDecayingCHadron() [2/3]

template<>
bool MC::isWeaklyDecayingCHadron ( const int & p)
inline

Definition at line 979 of file HepMCHelpers.h.

1000 {
1001inline
1002auto particles_in (const HepMC::GenVertex* p) {
1003 return std::ranges::subrange (p->particles_in_const_begin(),
1004 p->particles_in_const_end());
1005}
1006}
1007#endif
1008
1009namespace MC
1010{
1011 template <class VTX>
1012 auto particles_in (const VTX* p) { return p->particles_in(); }
1013 template <class VTX>
1014 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1015
1016 namespace Pythia8
1017 {
1019 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1020
1021 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1022
1023 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1024 }
1025
1026#include "AtlasPID.h"
1027
1029 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1030
1032 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1033
1035 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1036
1038 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1039
1041 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1042
1044 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1045
1047 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1048
1050 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1051
1053 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1054
1056 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1057
1061 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1062 const auto vertex = p->end_vertex();
1063 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1064 }
1065
1067 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1068
1070 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1071 const int apid = std::abs(p->pdg_id());
1072 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1073 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1074 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1075 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1076 return false;
1077 }
1078
1080
1081 template <class T> T findMother(T thePart) {
1082 auto partOriVert = thePart->production_vertex();
1083 if (!partOriVert) return nullptr;
1084
1085 long partPDG = thePart->pdg_id();
1086 long MotherPDG(0);
1087
1088 auto MothOriVert = partOriVert;
1089 MothOriVert = nullptr;
1090 T theMoth(nullptr);
1091
1092 size_t itr = 0;
1093 do {
1094 if (itr != 0) partOriVert = MothOriVert;
1095 for ( const auto& p : particles_in(partOriVert) ) {
1096 theMoth = p;
1097 if (!theMoth) continue;
1098 MotherPDG = theMoth->pdg_id();
1099 MothOriVert = theMoth->production_vertex();
1100 if (MotherPDG == partPDG) break;
1101 }
1102 itr++;
1103 if (itr > 100) {
1104 break;
1105 }
1106 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1107 MothOriVert != partOriVert);
1108 return theMoth;
1109 }
1110
1112
1113 template <class C, class T> T findMatching(C TruthContainer, T p) {
1114 T ptrPart = nullptr;
1115 if (!p) return ptrPart;
1116 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1117 for (T truthParticle : *TruthContainer) {
1118 if (HepMC::is_sim_descendant(p,truthParticle)) {
1119 ptrPart = truthParticle;
1120 break;
1121 }
1122 }
1123 }
1124 else {
1125 for (T truthParticle : TruthContainer) {
1126 if (HepMC::is_sim_descendant(p,truthParticle)) {
1127 ptrPart = truthParticle;
1128 break;
1129 }
1130 }
1131 }
1132 return ptrPart;
1133 }
1135
1136 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1137 auto prodVtx = thePart->production_vertex();
1138 if (!prodVtx) return;
1139 for (const auto& theMother: prodVtx->particles_in()) {
1140 if (!theMother) continue;
1141 allancestors.insert(theMother);
1142 findParticleAncestors(theMother, allancestors);
1143 }
1144 }
1145
1147
1148 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1149 auto endVtx = thePart->end_vertex();
1150 if (!endVtx) return;
1151 for (const auto& theDaughter: endVtx->particles_out()) {
1152 if (!theDaughter) continue;
1153 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1154 allstabledescendants.insert(theDaughter);
1155 }
1156 findParticleStableDescendants(theDaughter, allstabledescendants);
1157 }
1158 }
1159
1163
1164 template <class T> bool isHardScatteringVertex(T pVert) {
1165 if (pVert == nullptr) return false;
1166 T pV = pVert;
1167 int numOfPartIn(0);
1168 int pdg(0);
1169
1170 do {
1171 pVert = pV;
1172 auto incoming = pVert->particles_in();
1173 numOfPartIn = incoming.size();
1174 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1175 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1176
1177 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1178
1179 if (numOfPartIn == 2) {
1180 auto incoming = pVert->particles_in();
1181 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1182 }
1183 return false;
1184}
1185
1189
1190 template <class T, class U>
1191 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1192 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1193 auto vtx = p->production_vertex();
1194 if (!vtx) return false;
1195 bool fromHad = false;
1196 for ( const auto& parent : particles_in(vtx) ) {
1197 if (!parent) continue;
1198 // should this really go into parton-level territory?
1199 // probably depends where BSM particles are being decayed
1200 fromBSM |= isBSM(parent);
1201 if (!isPhysical(parent)) return false;
1202 fromTau |= isTau(parent);
1203 if (isHadron(parent)&&!isBeam(parent)) {
1204 if (!hadron) hadron = parent; // assumes linear hadron parentage
1205 return true;
1206 }
1207 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1208 }
1209 return fromHad;
1210 }
1211
1214
1215 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1216 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1217 decltype(thePart->end_vertex()) pVert(nullptr);
1218 if (EndVert != nullptr) {
1219 do {
1220 bool samePart = false;
1221 pVert = nullptr;
1222 auto outgoing = EndVert->particles_out();
1223 auto incoming = EndVert->particles_in();
1224 for (const auto& itrDaug: outgoing) {
1225 if (!itrDaug) continue;
1226 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1227 // brem on generator level for tau
1228 (outgoing.size() == 1 && incoming.size() == 1 &&
1230 itrDaug->pdg_id() == thePart->pdg_id()) {
1231 samePart = true;
1232 pVert = itrDaug->end_vertex();
1233 }
1234 }
1235 if (samePart) EndVert = pVert;
1236 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1237 }
1238 return EndVert;
1239 }
1240
1242
1243 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1244 if (!theVert) return {};
1245 decltype(theVert->particles_out()) finalStatePart;
1246 auto outgoing = theVert->particles_out();
1247 for (const auto& thePart: outgoing) {
1248 if (!thePart) continue;
1249 finalStatePart.push_back(thePart);
1250 if (isStable(thePart)) continue;
1251 V pVert = findSimulatedEndVertex(thePart);
1252 if (pVert == theVert) break; // to prevent Sherpa loop
1253 if (pVert != nullptr) {
1254 auto vecPart = findFinalStateParticles<V>(pVert);
1255 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1256 }
1257 }
1258 return finalStatePart;
1259 }
1260
1261}
1262#endif

◆ isWeaklyDecayingCHadron() [3/3]

template<class T>
bool MC::isWeaklyDecayingCHadron ( const T & p)
inline

Definition at line 978 of file HepMCHelpers.h.

999{
1000inline
1001auto particles_in (const HepMC::GenVertex* p) {
1002 return std::ranges::subrange (p->particles_in_const_begin(),
1003 p->particles_in_const_end());
1004}
1005}
1006#endif
1007
1008namespace MC
1009{
1010 template <class VTX>
1011 auto particles_in (const VTX* p) { return p->particles_in(); }
1012 template <class VTX>
1013 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1014
1015 namespace Pythia8
1016 {
1018 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1019
1020 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1021
1022 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1023 }
1024
1025#include "AtlasPID.h"
1026
1028 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1029
1031 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1032
1034 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1035
1037 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1038
1040 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1041
1043 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1044
1046 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1047
1049 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1050
1052 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1053
1055 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1056
1060 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1061 const auto vertex = p->end_vertex();
1062 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1063 }
1064
1066 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1067
1069 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1070 const int apid = std::abs(p->pdg_id());
1071 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1072 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1073 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1074 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1075 return false;
1076 }
1077
1079
1080 template <class T> T findMother(T thePart) {
1081 auto partOriVert = thePart->production_vertex();
1082 if (!partOriVert) return nullptr;
1083
1084 long partPDG = thePart->pdg_id();
1085 long MotherPDG(0);
1086
1087 auto MothOriVert = partOriVert;
1088 MothOriVert = nullptr;
1089 T theMoth(nullptr);
1090
1091 size_t itr = 0;
1092 do {
1093 if (itr != 0) partOriVert = MothOriVert;
1094 for ( const auto& p : particles_in(partOriVert) ) {
1095 theMoth = p;
1096 if (!theMoth) continue;
1097 MotherPDG = theMoth->pdg_id();
1098 MothOriVert = theMoth->production_vertex();
1099 if (MotherPDG == partPDG) break;
1100 }
1101 itr++;
1102 if (itr > 100) {
1103 break;
1104 }
1105 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1106 MothOriVert != partOriVert);
1107 return theMoth;
1108 }
1109
1111
1112 template <class C, class T> T findMatching(C TruthContainer, T p) {
1113 T ptrPart = nullptr;
1114 if (!p) return ptrPart;
1115 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1116 for (T truthParticle : *TruthContainer) {
1117 if (HepMC::is_sim_descendant(p,truthParticle)) {
1118 ptrPart = truthParticle;
1119 break;
1120 }
1121 }
1122 }
1123 else {
1124 for (T truthParticle : TruthContainer) {
1125 if (HepMC::is_sim_descendant(p,truthParticle)) {
1126 ptrPart = truthParticle;
1127 break;
1128 }
1129 }
1130 }
1131 return ptrPart;
1132 }
1134
1135 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1136 auto prodVtx = thePart->production_vertex();
1137 if (!prodVtx) return;
1138 for (const auto& theMother: prodVtx->particles_in()) {
1139 if (!theMother) continue;
1140 allancestors.insert(theMother);
1141 findParticleAncestors(theMother, allancestors);
1142 }
1143 }
1144
1146
1147 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1148 auto endVtx = thePart->end_vertex();
1149 if (!endVtx) return;
1150 for (const auto& theDaughter: endVtx->particles_out()) {
1151 if (!theDaughter) continue;
1152 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1153 allstabledescendants.insert(theDaughter);
1154 }
1155 findParticleStableDescendants(theDaughter, allstabledescendants);
1156 }
1157 }
1158
1162
1163 template <class T> bool isHardScatteringVertex(T pVert) {
1164 if (pVert == nullptr) return false;
1165 T pV = pVert;
1166 int numOfPartIn(0);
1167 int pdg(0);
1168
1169 do {
1170 pVert = pV;
1171 auto incoming = pVert->particles_in();
1172 numOfPartIn = incoming.size();
1173 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1174 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1175
1176 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1177
1178 if (numOfPartIn == 2) {
1179 auto incoming = pVert->particles_in();
1180 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1181 }
1182 return false;
1183}
1184
1188
1189 template <class T, class U>
1190 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1191 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1192 auto vtx = p->production_vertex();
1193 if (!vtx) return false;
1194 bool fromHad = false;
1195 for ( const auto& parent : particles_in(vtx) ) {
1196 if (!parent) continue;
1197 // should this really go into parton-level territory?
1198 // probably depends where BSM particles are being decayed
1199 fromBSM |= isBSM(parent);
1200 if (!isPhysical(parent)) return false;
1201 fromTau |= isTau(parent);
1202 if (isHadron(parent)&&!isBeam(parent)) {
1203 if (!hadron) hadron = parent; // assumes linear hadron parentage
1204 return true;
1205 }
1206 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1207 }
1208 return fromHad;
1209 }
1210
1213
1214 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1215 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1216 decltype(thePart->end_vertex()) pVert(nullptr);
1217 if (EndVert != nullptr) {
1218 do {
1219 bool samePart = false;
1220 pVert = nullptr;
1221 auto outgoing = EndVert->particles_out();
1222 auto incoming = EndVert->particles_in();
1223 for (const auto& itrDaug: outgoing) {
1224 if (!itrDaug) continue;
1225 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1226 // brem on generator level for tau
1227 (outgoing.size() == 1 && incoming.size() == 1 &&
1229 itrDaug->pdg_id() == thePart->pdg_id()) {
1230 samePart = true;
1231 pVert = itrDaug->end_vertex();
1232 }
1233 }
1234 if (samePart) EndVert = pVert;
1235 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1236 }
1237 return EndVert;
1238 }
1239
1241
1242 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1243 if (!theVert) return {};
1244 decltype(theVert->particles_out()) finalStatePart;
1245 auto outgoing = theVert->particles_out();
1246 for (const auto& thePart: outgoing) {
1247 if (!thePart) continue;
1248 finalStatePart.push_back(thePart);
1249 if (isStable(thePart)) continue;
1250 V pVert = findSimulatedEndVertex(thePart);
1251 if (pVert == theVert) break; // to prevent Sherpa loop
1252 if (pVert != nullptr) {
1253 auto vecPart = findFinalStateParticles<V>(pVert);
1254 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1255 }
1256 }
1257 return finalStatePart;
1258 }
1259
1260}
1261#endif

◆ isZ() [1/2]

template<>
bool MC::isZ ( const int & p)
inline

Definition at line 381 of file HepMCHelpers.h.

402{
403inline
404auto particles_in (const HepMC::GenVertex* p) {
405 return std::ranges::subrange (p->particles_in_const_begin(),
406 p->particles_in_const_end());
407}
408}
409#endif
410
411namespace MC
412{
413 template <class VTX>
414 auto particles_in (const VTX* p) { return p->particles_in(); }
415 template <class VTX>
416 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
417
418 namespace Pythia8
419 {
421 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
422
423 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
424
425 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
426 }
427
428#include "AtlasPID.h"
429
431 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
432
434 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
435
437 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
438
440 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
441
443 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
444
446 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
447
449 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
450
452 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
453
455 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
456
458 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
459
463 template <class T> inline bool isStableOrSimDecayed(const T& p) {
464 const auto vertex = p->end_vertex();
465 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
466 }
467
469 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
470
472 template <class T> inline bool isSpecialNonInteracting(const T& p) {
473 const int apid = std::abs(p->pdg_id());
474 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
475 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
476 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
477 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
478 return false;
479 }
480
482
483 template <class T> T findMother(T thePart) {
484 auto partOriVert = thePart->production_vertex();
485 if (!partOriVert) return nullptr;
486
487 long partPDG = thePart->pdg_id();
488 long MotherPDG(0);
489
490 auto MothOriVert = partOriVert;
491 MothOriVert = nullptr;
492 T theMoth(nullptr);
493
494 size_t itr = 0;
495 do {
496 if (itr != 0) partOriVert = MothOriVert;
497 for ( const auto& p : particles_in(partOriVert) ) {
498 theMoth = p;
499 if (!theMoth) continue;
500 MotherPDG = theMoth->pdg_id();
501 MothOriVert = theMoth->production_vertex();
502 if (MotherPDG == partPDG) break;
503 }
504 itr++;
505 if (itr > 100) {
506 break;
507 }
508 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
509 MothOriVert != partOriVert);
510 return theMoth;
511 }
512
514
515 template <class C, class T> T findMatching(C TruthContainer, T p) {
516 T ptrPart = nullptr;
517 if (!p) return ptrPart;
518 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
519 for (T truthParticle : *TruthContainer) {
520 if (HepMC::is_sim_descendant(p,truthParticle)) {
521 ptrPart = truthParticle;
522 break;
523 }
524 }
525 }
526 else {
527 for (T truthParticle : TruthContainer) {
528 if (HepMC::is_sim_descendant(p,truthParticle)) {
529 ptrPart = truthParticle;
530 break;
531 }
532 }
533 }
534 return ptrPart;
535 }
537
538 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
539 auto prodVtx = thePart->production_vertex();
540 if (!prodVtx) return;
541 for (const auto& theMother: prodVtx->particles_in()) {
542 if (!theMother) continue;
543 allancestors.insert(theMother);
544 findParticleAncestors(theMother, allancestors);
545 }
546 }
547
549
550 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
551 auto endVtx = thePart->end_vertex();
552 if (!endVtx) return;
553 for (const auto& theDaughter: endVtx->particles_out()) {
554 if (!theDaughter) continue;
555 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
556 allstabledescendants.insert(theDaughter);
557 }
558 findParticleStableDescendants(theDaughter, allstabledescendants);
559 }
560 }
561
565
566 template <class T> bool isHardScatteringVertex(T pVert) {
567 if (pVert == nullptr) return false;
568 T pV = pVert;
569 int numOfPartIn(0);
570 int pdg(0);
571
572 do {
573 pVert = pV;
574 auto incoming = pVert->particles_in();
575 numOfPartIn = incoming.size();
576 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
577 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
578
579 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
580
581 if (numOfPartIn == 2) {
582 auto incoming = pVert->particles_in();
583 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
584 }
585 return false;
586}
587
591
592 template <class T, class U>
593 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
594 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
595 auto vtx = p->production_vertex();
596 if (!vtx) return false;
597 bool fromHad = false;
598 for ( const auto& parent : particles_in(vtx) ) {
599 if (!parent) continue;
600 // should this really go into parton-level territory?
601 // probably depends where BSM particles are being decayed
602 fromBSM |= isBSM(parent);
603 if (!isPhysical(parent)) return false;
604 fromTau |= isTau(parent);
605 if (isHadron(parent)&&!isBeam(parent)) {
606 if (!hadron) hadron = parent; // assumes linear hadron parentage
607 return true;
608 }
609 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
610 }
611 return fromHad;
612 }
613
616
617 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
618 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
619 decltype(thePart->end_vertex()) pVert(nullptr);
620 if (EndVert != nullptr) {
621 do {
622 bool samePart = false;
623 pVert = nullptr;
624 auto outgoing = EndVert->particles_out();
625 auto incoming = EndVert->particles_in();
626 for (const auto& itrDaug: outgoing) {
627 if (!itrDaug) continue;
628 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
629 // brem on generator level for tau
630 (outgoing.size() == 1 && incoming.size() == 1 &&
632 itrDaug->pdg_id() == thePart->pdg_id()) {
633 samePart = true;
634 pVert = itrDaug->end_vertex();
635 }
636 }
637 if (samePart) EndVert = pVert;
638 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
639 }
640 return EndVert;
641 }
642
644
645 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
646 if (!theVert) return {};
647 decltype(theVert->particles_out()) finalStatePart;
648 auto outgoing = theVert->particles_out();
649 for (const auto& thePart: outgoing) {
650 if (!thePart) continue;
651 finalStatePart.push_back(thePart);
652 if (isStable(thePart)) continue;
653 V pVert = findSimulatedEndVertex(thePart);
654 if (pVert == theVert) break; // to prevent Sherpa loop
655 if (pVert != nullptr) {
656 auto vecPart = findFinalStateParticles<V>(pVert);
657 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
658 }
659 }
660 return finalStatePart;
661 }
662
663}
664#endif

◆ isZ() [2/2]

template<class T>
bool MC::isZ ( const T & p)
inline

Definition at line 380 of file HepMCHelpers.h.

401{
402inline
403auto particles_in (const HepMC::GenVertex* p) {
404 return std::ranges::subrange (p->particles_in_const_begin(),
405 p->particles_in_const_end());
406}
407}
408#endif
409
410namespace MC
411{
412 template <class VTX>
413 auto particles_in (const VTX* p) { return p->particles_in(); }
414 template <class VTX>
415 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
416
417 namespace Pythia8
418 {
420 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
421
422 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
423
424 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
425 }
426
427#include "AtlasPID.h"
428
430 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
431
433 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
434
436 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
437
439 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
440
442 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
443
445 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
446
448 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
449
451 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
452
454 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
455
457 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
458
462 template <class T> inline bool isStableOrSimDecayed(const T& p) {
463 const auto vertex = p->end_vertex();
464 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
465 }
466
468 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
469
471 template <class T> inline bool isSpecialNonInteracting(const T& p) {
472 const int apid = std::abs(p->pdg_id());
473 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
474 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
475 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
476 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
477 return false;
478 }
479
481
482 template <class T> T findMother(T thePart) {
483 auto partOriVert = thePart->production_vertex();
484 if (!partOriVert) return nullptr;
485
486 long partPDG = thePart->pdg_id();
487 long MotherPDG(0);
488
489 auto MothOriVert = partOriVert;
490 MothOriVert = nullptr;
491 T theMoth(nullptr);
492
493 size_t itr = 0;
494 do {
495 if (itr != 0) partOriVert = MothOriVert;
496 for ( const auto& p : particles_in(partOriVert) ) {
497 theMoth = p;
498 if (!theMoth) continue;
499 MotherPDG = theMoth->pdg_id();
500 MothOriVert = theMoth->production_vertex();
501 if (MotherPDG == partPDG) break;
502 }
503 itr++;
504 if (itr > 100) {
505 break;
506 }
507 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
508 MothOriVert != partOriVert);
509 return theMoth;
510 }
511
513
514 template <class C, class T> T findMatching(C TruthContainer, T p) {
515 T ptrPart = nullptr;
516 if (!p) return ptrPart;
517 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
518 for (T truthParticle : *TruthContainer) {
519 if (HepMC::is_sim_descendant(p,truthParticle)) {
520 ptrPart = truthParticle;
521 break;
522 }
523 }
524 }
525 else {
526 for (T truthParticle : TruthContainer) {
527 if (HepMC::is_sim_descendant(p,truthParticle)) {
528 ptrPart = truthParticle;
529 break;
530 }
531 }
532 }
533 return ptrPart;
534 }
536
537 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
538 auto prodVtx = thePart->production_vertex();
539 if (!prodVtx) return;
540 for (const auto& theMother: prodVtx->particles_in()) {
541 if (!theMother) continue;
542 allancestors.insert(theMother);
543 findParticleAncestors(theMother, allancestors);
544 }
545 }
546
548
549 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
550 auto endVtx = thePart->end_vertex();
551 if (!endVtx) return;
552 for (const auto& theDaughter: endVtx->particles_out()) {
553 if (!theDaughter) continue;
554 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
555 allstabledescendants.insert(theDaughter);
556 }
557 findParticleStableDescendants(theDaughter, allstabledescendants);
558 }
559 }
560
564
565 template <class T> bool isHardScatteringVertex(T pVert) {
566 if (pVert == nullptr) return false;
567 T pV = pVert;
568 int numOfPartIn(0);
569 int pdg(0);
570
571 do {
572 pVert = pV;
573 auto incoming = pVert->particles_in();
574 numOfPartIn = incoming.size();
575 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
576 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
577
578 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
579
580 if (numOfPartIn == 2) {
581 auto incoming = pVert->particles_in();
582 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
583 }
584 return false;
585}
586
590
591 template <class T, class U>
592 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
593 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
594 auto vtx = p->production_vertex();
595 if (!vtx) return false;
596 bool fromHad = false;
597 for ( const auto& parent : particles_in(vtx) ) {
598 if (!parent) continue;
599 // should this really go into parton-level territory?
600 // probably depends where BSM particles are being decayed
601 fromBSM |= isBSM(parent);
602 if (!isPhysical(parent)) return false;
603 fromTau |= isTau(parent);
604 if (isHadron(parent)&&!isBeam(parent)) {
605 if (!hadron) hadron = parent; // assumes linear hadron parentage
606 return true;
607 }
608 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
609 }
610 return fromHad;
611 }
612
615
616 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
617 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
618 decltype(thePart->end_vertex()) pVert(nullptr);
619 if (EndVert != nullptr) {
620 do {
621 bool samePart = false;
622 pVert = nullptr;
623 auto outgoing = EndVert->particles_out();
624 auto incoming = EndVert->particles_in();
625 for (const auto& itrDaug: outgoing) {
626 if (!itrDaug) continue;
627 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
628 // brem on generator level for tau
629 (outgoing.size() == 1 && incoming.size() == 1 &&
631 itrDaug->pdg_id() == thePart->pdg_id()) {
632 samePart = true;
633 pVert = itrDaug->end_vertex();
634 }
635 }
636 if (samePart) EndVert = pVert;
637 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
638 }
639 return EndVert;
640 }
641
643
644 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
645 if (!theVert) return {};
646 decltype(theVert->particles_out()) finalStatePart;
647 auto outgoing = theVert->particles_out();
648 for (const auto& thePart: outgoing) {
649 if (!thePart) continue;
650 finalStatePart.push_back(thePart);
651 if (isStable(thePart)) continue;
652 V pVert = findSimulatedEndVertex(thePart);
653 if (pVert == theVert) break; // to prevent Sherpa loop
654 if (pVert != nullptr) {
655 auto vecPart = findFinalStateParticles<V>(pVert);
656 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
657 }
658 }
659 return finalStatePart;
660 }
661
662}
663#endif

◆ isZeroEnergyPhoton()

template<class T>
bool MC::isZeroEnergyPhoton ( const T & p)
inline

Identify a photon with zero energy. Probably a workaround for a generator bug.

Definition at line 89 of file HepMCHelpers.h.

89{ return isPhoton<T>(p) && p->e() == 0;}

◆ leadingQuark() [1/3]

template<>
int MC::leadingQuark ( const DecodedPID & p)
inline

Definition at line 891 of file HepMCHelpers.h.

912 {
913inline
914auto particles_in (const HepMC::GenVertex* p) {
915 return std::ranges::subrange (p->particles_in_const_begin(),
916 p->particles_in_const_end());
917}
918}
919#endif
920
921namespace MC
922{
923 template <class VTX>
924 auto particles_in (const VTX* p) { return p->particles_in(); }
925 template <class VTX>
926 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
927
928 namespace Pythia8
929 {
931 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
932
933 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
934
935 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
936 }
937
938#include "AtlasPID.h"
939
941 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
942
944 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
945
947 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
948
950 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
951
953 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
954
956 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
957
959 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
960
962 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
963
965 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
966
968 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
969
973 template <class T> inline bool isStableOrSimDecayed(const T& p) {
974 const auto vertex = p->end_vertex();
975 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
976 }
977
979 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
980
982 template <class T> inline bool isSpecialNonInteracting(const T& p) {
983 const int apid = std::abs(p->pdg_id());
984 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
985 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
986 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
987 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
988 return false;
989 }
990
992
993 template <class T> T findMother(T thePart) {
994 auto partOriVert = thePart->production_vertex();
995 if (!partOriVert) return nullptr;
996
997 long partPDG = thePart->pdg_id();
998 long MotherPDG(0);
999
1000 auto MothOriVert = partOriVert;
1001 MothOriVert = nullptr;
1002 T theMoth(nullptr);
1003
1004 size_t itr = 0;
1005 do {
1006 if (itr != 0) partOriVert = MothOriVert;
1007 for ( const auto& p : particles_in(partOriVert) ) {
1008 theMoth = p;
1009 if (!theMoth) continue;
1010 MotherPDG = theMoth->pdg_id();
1011 MothOriVert = theMoth->production_vertex();
1012 if (MotherPDG == partPDG) break;
1013 }
1014 itr++;
1015 if (itr > 100) {
1016 break;
1017 }
1018 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1019 MothOriVert != partOriVert);
1020 return theMoth;
1021 }
1022
1024
1025 template <class C, class T> T findMatching(C TruthContainer, T p) {
1026 T ptrPart = nullptr;
1027 if (!p) return ptrPart;
1028 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1029 for (T truthParticle : *TruthContainer) {
1030 if (HepMC::is_sim_descendant(p,truthParticle)) {
1031 ptrPart = truthParticle;
1032 break;
1033 }
1034 }
1035 }
1036 else {
1037 for (T truthParticle : TruthContainer) {
1038 if (HepMC::is_sim_descendant(p,truthParticle)) {
1039 ptrPart = truthParticle;
1040 break;
1041 }
1042 }
1043 }
1044 return ptrPart;
1045 }
1047
1048 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1049 auto prodVtx = thePart->production_vertex();
1050 if (!prodVtx) return;
1051 for (const auto& theMother: prodVtx->particles_in()) {
1052 if (!theMother) continue;
1053 allancestors.insert(theMother);
1054 findParticleAncestors(theMother, allancestors);
1055 }
1056 }
1057
1059
1060 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1061 auto endVtx = thePart->end_vertex();
1062 if (!endVtx) return;
1063 for (const auto& theDaughter: endVtx->particles_out()) {
1064 if (!theDaughter) continue;
1065 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1066 allstabledescendants.insert(theDaughter);
1067 }
1068 findParticleStableDescendants(theDaughter, allstabledescendants);
1069 }
1070 }
1071
1075
1076 template <class T> bool isHardScatteringVertex(T pVert) {
1077 if (pVert == nullptr) return false;
1078 T pV = pVert;
1079 int numOfPartIn(0);
1080 int pdg(0);
1081
1082 do {
1083 pVert = pV;
1084 auto incoming = pVert->particles_in();
1085 numOfPartIn = incoming.size();
1086 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1087 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1088
1089 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1090
1091 if (numOfPartIn == 2) {
1092 auto incoming = pVert->particles_in();
1093 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1094 }
1095 return false;
1096}
1097
1101
1102 template <class T, class U>
1103 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1104 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1105 auto vtx = p->production_vertex();
1106 if (!vtx) return false;
1107 bool fromHad = false;
1108 for ( const auto& parent : particles_in(vtx) ) {
1109 if (!parent) continue;
1110 // should this really go into parton-level territory?
1111 // probably depends where BSM particles are being decayed
1112 fromBSM |= isBSM(parent);
1113 if (!isPhysical(parent)) return false;
1114 fromTau |= isTau(parent);
1115 if (isHadron(parent)&&!isBeam(parent)) {
1116 if (!hadron) hadron = parent; // assumes linear hadron parentage
1117 return true;
1118 }
1119 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1120 }
1121 return fromHad;
1122 }
1123
1126
1127 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1128 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1129 decltype(thePart->end_vertex()) pVert(nullptr);
1130 if (EndVert != nullptr) {
1131 do {
1132 bool samePart = false;
1133 pVert = nullptr;
1134 auto outgoing = EndVert->particles_out();
1135 auto incoming = EndVert->particles_in();
1136 for (const auto& itrDaug: outgoing) {
1137 if (!itrDaug) continue;
1138 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1139 // brem on generator level for tau
1140 (outgoing.size() == 1 && incoming.size() == 1 &&
1142 itrDaug->pdg_id() == thePart->pdg_id()) {
1143 samePart = true;
1144 pVert = itrDaug->end_vertex();
1145 }
1146 }
1147 if (samePart) EndVert = pVert;
1148 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1149 }
1150 return EndVert;
1151 }
1152
1154
1155 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1156 if (!theVert) return {};
1157 decltype(theVert->particles_out()) finalStatePart;
1158 auto outgoing = theVert->particles_out();
1159 for (const auto& thePart: outgoing) {
1160 if (!thePart) continue;
1161 finalStatePart.push_back(thePart);
1162 if (isStable(thePart)) continue;
1163 V pVert = findSimulatedEndVertex(thePart);
1164 if (pVert == theVert) break; // to prevent Sherpa loop
1165 if (pVert != nullptr) {
1166 auto vecPart = findFinalStateParticles<V>(pVert);
1167 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1168 }
1169 }
1170 return finalStatePart;
1171 }
1172
1173}
1174#endif

◆ leadingQuark() [2/3]

template<>
int MC::leadingQuark ( const int & p)
inline

Definition at line 907 of file HepMCHelpers.h.

928{
929inline
930auto particles_in (const HepMC::GenVertex* p) {
931 return std::ranges::subrange (p->particles_in_const_begin(),
932 p->particles_in_const_end());
933}
934}
935#endif
936
937namespace MC
938{
939 template <class VTX>
940 auto particles_in (const VTX* p) { return p->particles_in(); }
941 template <class VTX>
942 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
943
944 namespace Pythia8
945 {
947 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
948
949 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
950
951 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
952 }
953
954#include "AtlasPID.h"
955
957 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
958
960 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
961
963 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
964
966 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
967
969 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
970
972 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
973
975 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
976
978 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
979
981 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
982
984 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
985
989 template <class T> inline bool isStableOrSimDecayed(const T& p) {
990 const auto vertex = p->end_vertex();
991 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
992 }
993
995 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
996
998 template <class T> inline bool isSpecialNonInteracting(const T& p) {
999 const int apid = std::abs(p->pdg_id());
1000 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1001 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1002 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1003 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1004 return false;
1005 }
1006
1008
1009 template <class T> T findMother(T thePart) {
1010 auto partOriVert = thePart->production_vertex();
1011 if (!partOriVert) return nullptr;
1012
1013 long partPDG = thePart->pdg_id();
1014 long MotherPDG(0);
1015
1016 auto MothOriVert = partOriVert;
1017 MothOriVert = nullptr;
1018 T theMoth(nullptr);
1019
1020 size_t itr = 0;
1021 do {
1022 if (itr != 0) partOriVert = MothOriVert;
1023 for ( const auto& p : particles_in(partOriVert) ) {
1024 theMoth = p;
1025 if (!theMoth) continue;
1026 MotherPDG = theMoth->pdg_id();
1027 MothOriVert = theMoth->production_vertex();
1028 if (MotherPDG == partPDG) break;
1029 }
1030 itr++;
1031 if (itr > 100) {
1032 break;
1033 }
1034 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1035 MothOriVert != partOriVert);
1036 return theMoth;
1037 }
1038
1040
1041 template <class C, class T> T findMatching(C TruthContainer, T p) {
1042 T ptrPart = nullptr;
1043 if (!p) return ptrPart;
1044 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1045 for (T truthParticle : *TruthContainer) {
1046 if (HepMC::is_sim_descendant(p,truthParticle)) {
1047 ptrPart = truthParticle;
1048 break;
1049 }
1050 }
1051 }
1052 else {
1053 for (T truthParticle : TruthContainer) {
1054 if (HepMC::is_sim_descendant(p,truthParticle)) {
1055 ptrPart = truthParticle;
1056 break;
1057 }
1058 }
1059 }
1060 return ptrPart;
1061 }
1063
1064 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1065 auto prodVtx = thePart->production_vertex();
1066 if (!prodVtx) return;
1067 for (const auto& theMother: prodVtx->particles_in()) {
1068 if (!theMother) continue;
1069 allancestors.insert(theMother);
1070 findParticleAncestors(theMother, allancestors);
1071 }
1072 }
1073
1075
1076 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1077 auto endVtx = thePart->end_vertex();
1078 if (!endVtx) return;
1079 for (const auto& theDaughter: endVtx->particles_out()) {
1080 if (!theDaughter) continue;
1081 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1082 allstabledescendants.insert(theDaughter);
1083 }
1084 findParticleStableDescendants(theDaughter, allstabledescendants);
1085 }
1086 }
1087
1091
1092 template <class T> bool isHardScatteringVertex(T pVert) {
1093 if (pVert == nullptr) return false;
1094 T pV = pVert;
1095 int numOfPartIn(0);
1096 int pdg(0);
1097
1098 do {
1099 pVert = pV;
1100 auto incoming = pVert->particles_in();
1101 numOfPartIn = incoming.size();
1102 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1103 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1104
1105 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1106
1107 if (numOfPartIn == 2) {
1108 auto incoming = pVert->particles_in();
1109 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1110 }
1111 return false;
1112}
1113
1117
1118 template <class T, class U>
1119 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1120 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1121 auto vtx = p->production_vertex();
1122 if (!vtx) return false;
1123 bool fromHad = false;
1124 for ( const auto& parent : particles_in(vtx) ) {
1125 if (!parent) continue;
1126 // should this really go into parton-level territory?
1127 // probably depends where BSM particles are being decayed
1128 fromBSM |= isBSM(parent);
1129 if (!isPhysical(parent)) return false;
1130 fromTau |= isTau(parent);
1131 if (isHadron(parent)&&!isBeam(parent)) {
1132 if (!hadron) hadron = parent; // assumes linear hadron parentage
1133 return true;
1134 }
1135 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1136 }
1137 return fromHad;
1138 }
1139
1142
1143 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1144 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1145 decltype(thePart->end_vertex()) pVert(nullptr);
1146 if (EndVert != nullptr) {
1147 do {
1148 bool samePart = false;
1149 pVert = nullptr;
1150 auto outgoing = EndVert->particles_out();
1151 auto incoming = EndVert->particles_in();
1152 for (const auto& itrDaug: outgoing) {
1153 if (!itrDaug) continue;
1154 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1155 // brem on generator level for tau
1156 (outgoing.size() == 1 && incoming.size() == 1 &&
1158 itrDaug->pdg_id() == thePart->pdg_id()) {
1159 samePart = true;
1160 pVert = itrDaug->end_vertex();
1161 }
1162 }
1163 if (samePart) EndVert = pVert;
1164 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1165 }
1166 return EndVert;
1167 }
1168
1170
1171 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1172 if (!theVert) return {};
1173 decltype(theVert->particles_out()) finalStatePart;
1174 auto outgoing = theVert->particles_out();
1175 for (const auto& thePart: outgoing) {
1176 if (!thePart) continue;
1177 finalStatePart.push_back(thePart);
1178 if (isStable(thePart)) continue;
1179 V pVert = findSimulatedEndVertex(thePart);
1180 if (pVert == theVert) break; // to prevent Sherpa loop
1181 if (pVert != nullptr) {
1182 auto vecPart = findFinalStateParticles<V>(pVert);
1183 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1184 }
1185 }
1186 return finalStatePart;
1187 }
1188
1189}
1190#endif

◆ leadingQuark() [3/3]

template<class T>
int MC::leadingQuark ( const T & p)
inline

Definition at line 890 of file HepMCHelpers.h.

911{
912inline
913auto particles_in (const HepMC::GenVertex* p) {
914 return std::ranges::subrange (p->particles_in_const_begin(),
915 p->particles_in_const_end());
916}
917}
918#endif
919
920namespace MC
921{
922 template <class VTX>
923 auto particles_in (const VTX* p) { return p->particles_in(); }
924 template <class VTX>
925 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
926
927 namespace Pythia8
928 {
930 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
931
932 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
933
934 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
935 }
936
937#include "AtlasPID.h"
938
940 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
941
943 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
944
946 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
947
949 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
950
952 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
953
955 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
956
958 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
959
961 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
962
964 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
965
967 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
968
972 template <class T> inline bool isStableOrSimDecayed(const T& p) {
973 const auto vertex = p->end_vertex();
974 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
975 }
976
978 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
979
981 template <class T> inline bool isSpecialNonInteracting(const T& p) {
982 const int apid = std::abs(p->pdg_id());
983 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
984 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
985 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
986 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
987 return false;
988 }
989
991
992 template <class T> T findMother(T thePart) {
993 auto partOriVert = thePart->production_vertex();
994 if (!partOriVert) return nullptr;
995
996 long partPDG = thePart->pdg_id();
997 long MotherPDG(0);
998
999 auto MothOriVert = partOriVert;
1000 MothOriVert = nullptr;
1001 T theMoth(nullptr);
1002
1003 size_t itr = 0;
1004 do {
1005 if (itr != 0) partOriVert = MothOriVert;
1006 for ( const auto& p : particles_in(partOriVert) ) {
1007 theMoth = p;
1008 if (!theMoth) continue;
1009 MotherPDG = theMoth->pdg_id();
1010 MothOriVert = theMoth->production_vertex();
1011 if (MotherPDG == partPDG) break;
1012 }
1013 itr++;
1014 if (itr > 100) {
1015 break;
1016 }
1017 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1018 MothOriVert != partOriVert);
1019 return theMoth;
1020 }
1021
1023
1024 template <class C, class T> T findMatching(C TruthContainer, T p) {
1025 T ptrPart = nullptr;
1026 if (!p) return ptrPart;
1027 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1028 for (T truthParticle : *TruthContainer) {
1029 if (HepMC::is_sim_descendant(p,truthParticle)) {
1030 ptrPart = truthParticle;
1031 break;
1032 }
1033 }
1034 }
1035 else {
1036 for (T truthParticle : TruthContainer) {
1037 if (HepMC::is_sim_descendant(p,truthParticle)) {
1038 ptrPart = truthParticle;
1039 break;
1040 }
1041 }
1042 }
1043 return ptrPart;
1044 }
1046
1047 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1048 auto prodVtx = thePart->production_vertex();
1049 if (!prodVtx) return;
1050 for (const auto& theMother: prodVtx->particles_in()) {
1051 if (!theMother) continue;
1052 allancestors.insert(theMother);
1053 findParticleAncestors(theMother, allancestors);
1054 }
1055 }
1056
1058
1059 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1060 auto endVtx = thePart->end_vertex();
1061 if (!endVtx) return;
1062 for (const auto& theDaughter: endVtx->particles_out()) {
1063 if (!theDaughter) continue;
1064 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1065 allstabledescendants.insert(theDaughter);
1066 }
1067 findParticleStableDescendants(theDaughter, allstabledescendants);
1068 }
1069 }
1070
1074
1075 template <class T> bool isHardScatteringVertex(T pVert) {
1076 if (pVert == nullptr) return false;
1077 T pV = pVert;
1078 int numOfPartIn(0);
1079 int pdg(0);
1080
1081 do {
1082 pVert = pV;
1083 auto incoming = pVert->particles_in();
1084 numOfPartIn = incoming.size();
1085 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1086 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1087
1088 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1089
1090 if (numOfPartIn == 2) {
1091 auto incoming = pVert->particles_in();
1092 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1093 }
1094 return false;
1095}
1096
1100
1101 template <class T, class U>
1102 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1103 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1104 auto vtx = p->production_vertex();
1105 if (!vtx) return false;
1106 bool fromHad = false;
1107 for ( const auto& parent : particles_in(vtx) ) {
1108 if (!parent) continue;
1109 // should this really go into parton-level territory?
1110 // probably depends where BSM particles are being decayed
1111 fromBSM |= isBSM(parent);
1112 if (!isPhysical(parent)) return false;
1113 fromTau |= isTau(parent);
1114 if (isHadron(parent)&&!isBeam(parent)) {
1115 if (!hadron) hadron = parent; // assumes linear hadron parentage
1116 return true;
1117 }
1118 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1119 }
1120 return fromHad;
1121 }
1122
1125
1126 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1127 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1128 decltype(thePart->end_vertex()) pVert(nullptr);
1129 if (EndVert != nullptr) {
1130 do {
1131 bool samePart = false;
1132 pVert = nullptr;
1133 auto outgoing = EndVert->particles_out();
1134 auto incoming = EndVert->particles_in();
1135 for (const auto& itrDaug: outgoing) {
1136 if (!itrDaug) continue;
1137 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1138 // brem on generator level for tau
1139 (outgoing.size() == 1 && incoming.size() == 1 &&
1141 itrDaug->pdg_id() == thePart->pdg_id()) {
1142 samePart = true;
1143 pVert = itrDaug->end_vertex();
1144 }
1145 }
1146 if (samePart) EndVert = pVert;
1147 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1148 }
1149 return EndVert;
1150 }
1151
1153
1154 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1155 if (!theVert) return {};
1156 decltype(theVert->particles_out()) finalStatePart;
1157 auto outgoing = theVert->particles_out();
1158 for (const auto& thePart: outgoing) {
1159 if (!thePart) continue;
1160 finalStatePart.push_back(thePart);
1161 if (isStable(thePart)) continue;
1162 V pVert = findSimulatedEndVertex(thePart);
1163 if (pVert == theVert) break; // to prevent Sherpa loop
1164 if (pVert != nullptr) {
1165 auto vecPart = findFinalStateParticles<V>(pVert);
1166 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1167 }
1168 }
1169 return finalStatePart;
1170 }
1171
1172}
1173#endif

◆ numberOfLambdas() [1/3]

template<>
int MC::numberOfLambdas ( const DecodedPID & p)
inline

Definition at line 826 of file HepMCHelpers.h.

847 {
848inline
849auto particles_in (const HepMC::GenVertex* p) {
850 return std::ranges::subrange (p->particles_in_const_begin(),
851 p->particles_in_const_end());
852}
853}
854#endif
855
856namespace MC
857{
858 template <class VTX>
859 auto particles_in (const VTX* p) { return p->particles_in(); }
860 template <class VTX>
861 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
862
863 namespace Pythia8
864 {
866 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
867
868 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
869
870 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
871 }
872
873#include "AtlasPID.h"
874
876 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
877
879 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
880
882 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
883
885 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
886
888 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
889
891 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
892
894 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
895
897 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
898
900 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
901
903 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
904
908 template <class T> inline bool isStableOrSimDecayed(const T& p) {
909 const auto vertex = p->end_vertex();
910 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
911 }
912
914 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
915
917 template <class T> inline bool isSpecialNonInteracting(const T& p) {
918 const int apid = std::abs(p->pdg_id());
919 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
920 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
921 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
922 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
923 return false;
924 }
925
927
928 template <class T> T findMother(T thePart) {
929 auto partOriVert = thePart->production_vertex();
930 if (!partOriVert) return nullptr;
931
932 long partPDG = thePart->pdg_id();
933 long MotherPDG(0);
934
935 auto MothOriVert = partOriVert;
936 MothOriVert = nullptr;
937 T theMoth(nullptr);
938
939 size_t itr = 0;
940 do {
941 if (itr != 0) partOriVert = MothOriVert;
942 for ( const auto& p : particles_in(partOriVert) ) {
943 theMoth = p;
944 if (!theMoth) continue;
945 MotherPDG = theMoth->pdg_id();
946 MothOriVert = theMoth->production_vertex();
947 if (MotherPDG == partPDG) break;
948 }
949 itr++;
950 if (itr > 100) {
951 break;
952 }
953 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
954 MothOriVert != partOriVert);
955 return theMoth;
956 }
957
959
960 template <class C, class T> T findMatching(C TruthContainer, T p) {
961 T ptrPart = nullptr;
962 if (!p) return ptrPart;
963 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
964 for (T truthParticle : *TruthContainer) {
965 if (HepMC::is_sim_descendant(p,truthParticle)) {
966 ptrPart = truthParticle;
967 break;
968 }
969 }
970 }
971 else {
972 for (T truthParticle : TruthContainer) {
973 if (HepMC::is_sim_descendant(p,truthParticle)) {
974 ptrPart = truthParticle;
975 break;
976 }
977 }
978 }
979 return ptrPart;
980 }
982
983 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
984 auto prodVtx = thePart->production_vertex();
985 if (!prodVtx) return;
986 for (const auto& theMother: prodVtx->particles_in()) {
987 if (!theMother) continue;
988 allancestors.insert(theMother);
989 findParticleAncestors(theMother, allancestors);
990 }
991 }
992
994
995 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
996 auto endVtx = thePart->end_vertex();
997 if (!endVtx) return;
998 for (const auto& theDaughter: endVtx->particles_out()) {
999 if (!theDaughter) continue;
1000 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1001 allstabledescendants.insert(theDaughter);
1002 }
1003 findParticleStableDescendants(theDaughter, allstabledescendants);
1004 }
1005 }
1006
1010
1011 template <class T> bool isHardScatteringVertex(T pVert) {
1012 if (pVert == nullptr) return false;
1013 T pV = pVert;
1014 int numOfPartIn(0);
1015 int pdg(0);
1016
1017 do {
1018 pVert = pV;
1019 auto incoming = pVert->particles_in();
1020 numOfPartIn = incoming.size();
1021 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1022 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1023
1024 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1025
1026 if (numOfPartIn == 2) {
1027 auto incoming = pVert->particles_in();
1028 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1029 }
1030 return false;
1031}
1032
1036
1037 template <class T, class U>
1038 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1039 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1040 auto vtx = p->production_vertex();
1041 if (!vtx) return false;
1042 bool fromHad = false;
1043 for ( const auto& parent : particles_in(vtx) ) {
1044 if (!parent) continue;
1045 // should this really go into parton-level territory?
1046 // probably depends where BSM particles are being decayed
1047 fromBSM |= isBSM(parent);
1048 if (!isPhysical(parent)) return false;
1049 fromTau |= isTau(parent);
1050 if (isHadron(parent)&&!isBeam(parent)) {
1051 if (!hadron) hadron = parent; // assumes linear hadron parentage
1052 return true;
1053 }
1054 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1055 }
1056 return fromHad;
1057 }
1058
1061
1062 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1063 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1064 decltype(thePart->end_vertex()) pVert(nullptr);
1065 if (EndVert != nullptr) {
1066 do {
1067 bool samePart = false;
1068 pVert = nullptr;
1069 auto outgoing = EndVert->particles_out();
1070 auto incoming = EndVert->particles_in();
1071 for (const auto& itrDaug: outgoing) {
1072 if (!itrDaug) continue;
1073 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1074 // brem on generator level for tau
1075 (outgoing.size() == 1 && incoming.size() == 1 &&
1077 itrDaug->pdg_id() == thePart->pdg_id()) {
1078 samePart = true;
1079 pVert = itrDaug->end_vertex();
1080 }
1081 }
1082 if (samePart) EndVert = pVert;
1083 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1084 }
1085 return EndVert;
1086 }
1087
1089
1090 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1091 if (!theVert) return {};
1092 decltype(theVert->particles_out()) finalStatePart;
1093 auto outgoing = theVert->particles_out();
1094 for (const auto& thePart: outgoing) {
1095 if (!thePart) continue;
1096 finalStatePart.push_back(thePart);
1097 if (isStable(thePart)) continue;
1098 V pVert = findSimulatedEndVertex(thePart);
1099 if (pVert == theVert) break; // to prevent Sherpa loop
1100 if (pVert != nullptr) {
1101 auto vecPart = findFinalStateParticles<V>(pVert);
1102 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1103 }
1104 }
1105 return finalStatePart;
1106 }
1107
1108}
1109#endif

◆ numberOfLambdas() [2/3]

template<>
int MC::numberOfLambdas ( const int & p)
inline

Definition at line 831 of file HepMCHelpers.h.

852{
853inline
854auto particles_in (const HepMC::GenVertex* p) {
855 return std::ranges::subrange (p->particles_in_const_begin(),
856 p->particles_in_const_end());
857}
858}
859#endif
860
861namespace MC
862{
863 template <class VTX>
864 auto particles_in (const VTX* p) { return p->particles_in(); }
865 template <class VTX>
866 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
867
868 namespace Pythia8
869 {
871 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
872
873 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
874
875 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
876 }
877
878#include "AtlasPID.h"
879
881 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
882
884 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
885
887 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
888
890 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
891
893 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
894
896 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
897
899 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
900
902 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
903
905 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
906
908 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
909
913 template <class T> inline bool isStableOrSimDecayed(const T& p) {
914 const auto vertex = p->end_vertex();
915 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
916 }
917
919 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
920
922 template <class T> inline bool isSpecialNonInteracting(const T& p) {
923 const int apid = std::abs(p->pdg_id());
924 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
925 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
926 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
927 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
928 return false;
929 }
930
932
933 template <class T> T findMother(T thePart) {
934 auto partOriVert = thePart->production_vertex();
935 if (!partOriVert) return nullptr;
936
937 long partPDG = thePart->pdg_id();
938 long MotherPDG(0);
939
940 auto MothOriVert = partOriVert;
941 MothOriVert = nullptr;
942 T theMoth(nullptr);
943
944 size_t itr = 0;
945 do {
946 if (itr != 0) partOriVert = MothOriVert;
947 for ( const auto& p : particles_in(partOriVert) ) {
948 theMoth = p;
949 if (!theMoth) continue;
950 MotherPDG = theMoth->pdg_id();
951 MothOriVert = theMoth->production_vertex();
952 if (MotherPDG == partPDG) break;
953 }
954 itr++;
955 if (itr > 100) {
956 break;
957 }
958 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
959 MothOriVert != partOriVert);
960 return theMoth;
961 }
962
964
965 template <class C, class T> T findMatching(C TruthContainer, T p) {
966 T ptrPart = nullptr;
967 if (!p) return ptrPart;
968 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
969 for (T truthParticle : *TruthContainer) {
970 if (HepMC::is_sim_descendant(p,truthParticle)) {
971 ptrPart = truthParticle;
972 break;
973 }
974 }
975 }
976 else {
977 for (T truthParticle : TruthContainer) {
978 if (HepMC::is_sim_descendant(p,truthParticle)) {
979 ptrPart = truthParticle;
980 break;
981 }
982 }
983 }
984 return ptrPart;
985 }
987
988 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
989 auto prodVtx = thePart->production_vertex();
990 if (!prodVtx) return;
991 for (const auto& theMother: prodVtx->particles_in()) {
992 if (!theMother) continue;
993 allancestors.insert(theMother);
994 findParticleAncestors(theMother, allancestors);
995 }
996 }
997
999
1000 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1001 auto endVtx = thePart->end_vertex();
1002 if (!endVtx) return;
1003 for (const auto& theDaughter: endVtx->particles_out()) {
1004 if (!theDaughter) continue;
1005 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1006 allstabledescendants.insert(theDaughter);
1007 }
1008 findParticleStableDescendants(theDaughter, allstabledescendants);
1009 }
1010 }
1011
1015
1016 template <class T> bool isHardScatteringVertex(T pVert) {
1017 if (pVert == nullptr) return false;
1018 T pV = pVert;
1019 int numOfPartIn(0);
1020 int pdg(0);
1021
1022 do {
1023 pVert = pV;
1024 auto incoming = pVert->particles_in();
1025 numOfPartIn = incoming.size();
1026 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1027 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1028
1029 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1030
1031 if (numOfPartIn == 2) {
1032 auto incoming = pVert->particles_in();
1033 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1034 }
1035 return false;
1036}
1037
1041
1042 template <class T, class U>
1043 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1044 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1045 auto vtx = p->production_vertex();
1046 if (!vtx) return false;
1047 bool fromHad = false;
1048 for ( const auto& parent : particles_in(vtx) ) {
1049 if (!parent) continue;
1050 // should this really go into parton-level territory?
1051 // probably depends where BSM particles are being decayed
1052 fromBSM |= isBSM(parent);
1053 if (!isPhysical(parent)) return false;
1054 fromTau |= isTau(parent);
1055 if (isHadron(parent)&&!isBeam(parent)) {
1056 if (!hadron) hadron = parent; // assumes linear hadron parentage
1057 return true;
1058 }
1059 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1060 }
1061 return fromHad;
1062 }
1063
1066
1067 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1068 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1069 decltype(thePart->end_vertex()) pVert(nullptr);
1070 if (EndVert != nullptr) {
1071 do {
1072 bool samePart = false;
1073 pVert = nullptr;
1074 auto outgoing = EndVert->particles_out();
1075 auto incoming = EndVert->particles_in();
1076 for (const auto& itrDaug: outgoing) {
1077 if (!itrDaug) continue;
1078 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1079 // brem on generator level for tau
1080 (outgoing.size() == 1 && incoming.size() == 1 &&
1082 itrDaug->pdg_id() == thePart->pdg_id()) {
1083 samePart = true;
1084 pVert = itrDaug->end_vertex();
1085 }
1086 }
1087 if (samePart) EndVert = pVert;
1088 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1089 }
1090 return EndVert;
1091 }
1092
1094
1095 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1096 if (!theVert) return {};
1097 decltype(theVert->particles_out()) finalStatePart;
1098 auto outgoing = theVert->particles_out();
1099 for (const auto& thePart: outgoing) {
1100 if (!thePart) continue;
1101 finalStatePart.push_back(thePart);
1102 if (isStable(thePart)) continue;
1103 V pVert = findSimulatedEndVertex(thePart);
1104 if (pVert == theVert) break; // to prevent Sherpa loop
1105 if (pVert != nullptr) {
1106 auto vecPart = findFinalStateParticles<V>(pVert);
1107 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1108 }
1109 }
1110 return finalStatePart;
1111 }
1112
1113}
1114#endif

◆ numberOfLambdas() [3/3]

template<class T>
int MC::numberOfLambdas ( const T & p)
inline

Definition at line 825 of file HepMCHelpers.h.

846{
847inline
848auto particles_in (const HepMC::GenVertex* p) {
849 return std::ranges::subrange (p->particles_in_const_begin(),
850 p->particles_in_const_end());
851}
852}
853#endif
854
855namespace MC
856{
857 template <class VTX>
858 auto particles_in (const VTX* p) { return p->particles_in(); }
859 template <class VTX>
860 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
861
862 namespace Pythia8
863 {
865 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
866
867 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
868
869 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
870 }
871
872#include "AtlasPID.h"
873
875 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
876
878 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
879
881 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
882
884 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
885
887 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
888
890 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
891
893 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
894
896 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
897
899 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
900
902 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
903
907 template <class T> inline bool isStableOrSimDecayed(const T& p) {
908 const auto vertex = p->end_vertex();
909 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
910 }
911
913 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
914
916 template <class T> inline bool isSpecialNonInteracting(const T& p) {
917 const int apid = std::abs(p->pdg_id());
918 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
919 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
920 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
921 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
922 return false;
923 }
924
926
927 template <class T> T findMother(T thePart) {
928 auto partOriVert = thePart->production_vertex();
929 if (!partOriVert) return nullptr;
930
931 long partPDG = thePart->pdg_id();
932 long MotherPDG(0);
933
934 auto MothOriVert = partOriVert;
935 MothOriVert = nullptr;
936 T theMoth(nullptr);
937
938 size_t itr = 0;
939 do {
940 if (itr != 0) partOriVert = MothOriVert;
941 for ( const auto& p : particles_in(partOriVert) ) {
942 theMoth = p;
943 if (!theMoth) continue;
944 MotherPDG = theMoth->pdg_id();
945 MothOriVert = theMoth->production_vertex();
946 if (MotherPDG == partPDG) break;
947 }
948 itr++;
949 if (itr > 100) {
950 break;
951 }
952 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
953 MothOriVert != partOriVert);
954 return theMoth;
955 }
956
958
959 template <class C, class T> T findMatching(C TruthContainer, T p) {
960 T ptrPart = nullptr;
961 if (!p) return ptrPart;
962 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
963 for (T truthParticle : *TruthContainer) {
964 if (HepMC::is_sim_descendant(p,truthParticle)) {
965 ptrPart = truthParticle;
966 break;
967 }
968 }
969 }
970 else {
971 for (T truthParticle : TruthContainer) {
972 if (HepMC::is_sim_descendant(p,truthParticle)) {
973 ptrPart = truthParticle;
974 break;
975 }
976 }
977 }
978 return ptrPart;
979 }
981
982 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
983 auto prodVtx = thePart->production_vertex();
984 if (!prodVtx) return;
985 for (const auto& theMother: prodVtx->particles_in()) {
986 if (!theMother) continue;
987 allancestors.insert(theMother);
988 findParticleAncestors(theMother, allancestors);
989 }
990 }
991
993
994 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
995 auto endVtx = thePart->end_vertex();
996 if (!endVtx) return;
997 for (const auto& theDaughter: endVtx->particles_out()) {
998 if (!theDaughter) continue;
999 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1000 allstabledescendants.insert(theDaughter);
1001 }
1002 findParticleStableDescendants(theDaughter, allstabledescendants);
1003 }
1004 }
1005
1009
1010 template <class T> bool isHardScatteringVertex(T pVert) {
1011 if (pVert == nullptr) return false;
1012 T pV = pVert;
1013 int numOfPartIn(0);
1014 int pdg(0);
1015
1016 do {
1017 pVert = pV;
1018 auto incoming = pVert->particles_in();
1019 numOfPartIn = incoming.size();
1020 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1021 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1022
1023 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1024
1025 if (numOfPartIn == 2) {
1026 auto incoming = pVert->particles_in();
1027 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1028 }
1029 return false;
1030}
1031
1035
1036 template <class T, class U>
1037 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1038 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1039 auto vtx = p->production_vertex();
1040 if (!vtx) return false;
1041 bool fromHad = false;
1042 for ( const auto& parent : particles_in(vtx) ) {
1043 if (!parent) continue;
1044 // should this really go into parton-level territory?
1045 // probably depends where BSM particles are being decayed
1046 fromBSM |= isBSM(parent);
1047 if (!isPhysical(parent)) return false;
1048 fromTau |= isTau(parent);
1049 if (isHadron(parent)&&!isBeam(parent)) {
1050 if (!hadron) hadron = parent; // assumes linear hadron parentage
1051 return true;
1052 }
1053 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1054 }
1055 return fromHad;
1056 }
1057
1060
1061 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1062 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1063 decltype(thePart->end_vertex()) pVert(nullptr);
1064 if (EndVert != nullptr) {
1065 do {
1066 bool samePart = false;
1067 pVert = nullptr;
1068 auto outgoing = EndVert->particles_out();
1069 auto incoming = EndVert->particles_in();
1070 for (const auto& itrDaug: outgoing) {
1071 if (!itrDaug) continue;
1072 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1073 // brem on generator level for tau
1074 (outgoing.size() == 1 && incoming.size() == 1 &&
1076 itrDaug->pdg_id() == thePart->pdg_id()) {
1077 samePart = true;
1078 pVert = itrDaug->end_vertex();
1079 }
1080 }
1081 if (samePart) EndVert = pVert;
1082 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1083 }
1084 return EndVert;
1085 }
1086
1088
1089 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1090 if (!theVert) return {};
1091 decltype(theVert->particles_out()) finalStatePart;
1092 auto outgoing = theVert->particles_out();
1093 for (const auto& thePart: outgoing) {
1094 if (!thePart) continue;
1095 finalStatePart.push_back(thePart);
1096 if (isStable(thePart)) continue;
1097 V pVert = findSimulatedEndVertex(thePart);
1098 if (pVert == theVert) break; // to prevent Sherpa loop
1099 if (pVert != nullptr) {
1100 auto vecPart = findFinalStateParticles<V>(pVert);
1101 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1102 }
1103 }
1104 return finalStatePart;
1105 }
1106
1107}
1108#endif

◆ numberOfProtons() [1/3]

template<>
int MC::numberOfProtons ( const DecodedPID & p)
inline

Definition at line 835 of file HepMCHelpers.h.

856 {
857inline
858auto particles_in (const HepMC::GenVertex* p) {
859 return std::ranges::subrange (p->particles_in_const_begin(),
860 p->particles_in_const_end());
861}
862}
863#endif
864
865namespace MC
866{
867 template <class VTX>
868 auto particles_in (const VTX* p) { return p->particles_in(); }
869 template <class VTX>
870 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
871
872 namespace Pythia8
873 {
875 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
876
877 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
878
879 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
880 }
881
882#include "AtlasPID.h"
883
885 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
886
888 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
889
891 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
892
894 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
895
897 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
898
900 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
901
903 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
904
906 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
907
909 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
910
912 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
913
917 template <class T> inline bool isStableOrSimDecayed(const T& p) {
918 const auto vertex = p->end_vertex();
919 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
920 }
921
923 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
924
926 template <class T> inline bool isSpecialNonInteracting(const T& p) {
927 const int apid = std::abs(p->pdg_id());
928 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
929 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
930 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
931 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
932 return false;
933 }
934
936
937 template <class T> T findMother(T thePart) {
938 auto partOriVert = thePart->production_vertex();
939 if (!partOriVert) return nullptr;
940
941 long partPDG = thePart->pdg_id();
942 long MotherPDG(0);
943
944 auto MothOriVert = partOriVert;
945 MothOriVert = nullptr;
946 T theMoth(nullptr);
947
948 size_t itr = 0;
949 do {
950 if (itr != 0) partOriVert = MothOriVert;
951 for ( const auto& p : particles_in(partOriVert) ) {
952 theMoth = p;
953 if (!theMoth) continue;
954 MotherPDG = theMoth->pdg_id();
955 MothOriVert = theMoth->production_vertex();
956 if (MotherPDG == partPDG) break;
957 }
958 itr++;
959 if (itr > 100) {
960 break;
961 }
962 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
963 MothOriVert != partOriVert);
964 return theMoth;
965 }
966
968
969 template <class C, class T> T findMatching(C TruthContainer, T p) {
970 T ptrPart = nullptr;
971 if (!p) return ptrPart;
972 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
973 for (T truthParticle : *TruthContainer) {
974 if (HepMC::is_sim_descendant(p,truthParticle)) {
975 ptrPart = truthParticle;
976 break;
977 }
978 }
979 }
980 else {
981 for (T truthParticle : TruthContainer) {
982 if (HepMC::is_sim_descendant(p,truthParticle)) {
983 ptrPart = truthParticle;
984 break;
985 }
986 }
987 }
988 return ptrPart;
989 }
991
992 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
993 auto prodVtx = thePart->production_vertex();
994 if (!prodVtx) return;
995 for (const auto& theMother: prodVtx->particles_in()) {
996 if (!theMother) continue;
997 allancestors.insert(theMother);
998 findParticleAncestors(theMother, allancestors);
999 }
1000 }
1001
1003
1004 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1005 auto endVtx = thePart->end_vertex();
1006 if (!endVtx) return;
1007 for (const auto& theDaughter: endVtx->particles_out()) {
1008 if (!theDaughter) continue;
1009 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1010 allstabledescendants.insert(theDaughter);
1011 }
1012 findParticleStableDescendants(theDaughter, allstabledescendants);
1013 }
1014 }
1015
1019
1020 template <class T> bool isHardScatteringVertex(T pVert) {
1021 if (pVert == nullptr) return false;
1022 T pV = pVert;
1023 int numOfPartIn(0);
1024 int pdg(0);
1025
1026 do {
1027 pVert = pV;
1028 auto incoming = pVert->particles_in();
1029 numOfPartIn = incoming.size();
1030 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1031 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1032
1033 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1034
1035 if (numOfPartIn == 2) {
1036 auto incoming = pVert->particles_in();
1037 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1038 }
1039 return false;
1040}
1041
1045
1046 template <class T, class U>
1047 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1048 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1049 auto vtx = p->production_vertex();
1050 if (!vtx) return false;
1051 bool fromHad = false;
1052 for ( const auto& parent : particles_in(vtx) ) {
1053 if (!parent) continue;
1054 // should this really go into parton-level territory?
1055 // probably depends where BSM particles are being decayed
1056 fromBSM |= isBSM(parent);
1057 if (!isPhysical(parent)) return false;
1058 fromTau |= isTau(parent);
1059 if (isHadron(parent)&&!isBeam(parent)) {
1060 if (!hadron) hadron = parent; // assumes linear hadron parentage
1061 return true;
1062 }
1063 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1064 }
1065 return fromHad;
1066 }
1067
1070
1071 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1072 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1073 decltype(thePart->end_vertex()) pVert(nullptr);
1074 if (EndVert != nullptr) {
1075 do {
1076 bool samePart = false;
1077 pVert = nullptr;
1078 auto outgoing = EndVert->particles_out();
1079 auto incoming = EndVert->particles_in();
1080 for (const auto& itrDaug: outgoing) {
1081 if (!itrDaug) continue;
1082 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1083 // brem on generator level for tau
1084 (outgoing.size() == 1 && incoming.size() == 1 &&
1086 itrDaug->pdg_id() == thePart->pdg_id()) {
1087 samePart = true;
1088 pVert = itrDaug->end_vertex();
1089 }
1090 }
1091 if (samePart) EndVert = pVert;
1092 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1093 }
1094 return EndVert;
1095 }
1096
1098
1099 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1100 if (!theVert) return {};
1101 decltype(theVert->particles_out()) finalStatePart;
1102 auto outgoing = theVert->particles_out();
1103 for (const auto& thePart: outgoing) {
1104 if (!thePart) continue;
1105 finalStatePart.push_back(thePart);
1106 if (isStable(thePart)) continue;
1107 V pVert = findSimulatedEndVertex(thePart);
1108 if (pVert == theVert) break; // to prevent Sherpa loop
1109 if (pVert != nullptr) {
1110 auto vecPart = findFinalStateParticles<V>(pVert);
1111 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1112 }
1113 }
1114 return finalStatePart;
1115 }
1116
1117}
1118#endif

◆ numberOfProtons() [2/3]

template<>
int MC::numberOfProtons ( const int & p)
inline

Definition at line 843 of file HepMCHelpers.h.

864{
865inline
866auto particles_in (const HepMC::GenVertex* p) {
867 return std::ranges::subrange (p->particles_in_const_begin(),
868 p->particles_in_const_end());
869}
870}
871#endif
872
873namespace MC
874{
875 template <class VTX>
876 auto particles_in (const VTX* p) { return p->particles_in(); }
877 template <class VTX>
878 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
879
880 namespace Pythia8
881 {
883 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
884
885 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
886
887 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
888 }
889
890#include "AtlasPID.h"
891
893 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
894
896 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
897
899 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
900
902 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
903
905 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
906
908 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
909
911 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
912
914 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
915
917 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
918
920 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
921
925 template <class T> inline bool isStableOrSimDecayed(const T& p) {
926 const auto vertex = p->end_vertex();
927 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
928 }
929
931 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
932
934 template <class T> inline bool isSpecialNonInteracting(const T& p) {
935 const int apid = std::abs(p->pdg_id());
936 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
937 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
938 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
939 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
940 return false;
941 }
942
944
945 template <class T> T findMother(T thePart) {
946 auto partOriVert = thePart->production_vertex();
947 if (!partOriVert) return nullptr;
948
949 long partPDG = thePart->pdg_id();
950 long MotherPDG(0);
951
952 auto MothOriVert = partOriVert;
953 MothOriVert = nullptr;
954 T theMoth(nullptr);
955
956 size_t itr = 0;
957 do {
958 if (itr != 0) partOriVert = MothOriVert;
959 for ( const auto& p : particles_in(partOriVert) ) {
960 theMoth = p;
961 if (!theMoth) continue;
962 MotherPDG = theMoth->pdg_id();
963 MothOriVert = theMoth->production_vertex();
964 if (MotherPDG == partPDG) break;
965 }
966 itr++;
967 if (itr > 100) {
968 break;
969 }
970 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
971 MothOriVert != partOriVert);
972 return theMoth;
973 }
974
976
977 template <class C, class T> T findMatching(C TruthContainer, T p) {
978 T ptrPart = nullptr;
979 if (!p) return ptrPart;
980 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
981 for (T truthParticle : *TruthContainer) {
982 if (HepMC::is_sim_descendant(p,truthParticle)) {
983 ptrPart = truthParticle;
984 break;
985 }
986 }
987 }
988 else {
989 for (T truthParticle : TruthContainer) {
990 if (HepMC::is_sim_descendant(p,truthParticle)) {
991 ptrPart = truthParticle;
992 break;
993 }
994 }
995 }
996 return ptrPart;
997 }
999
1000 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1001 auto prodVtx = thePart->production_vertex();
1002 if (!prodVtx) return;
1003 for (const auto& theMother: prodVtx->particles_in()) {
1004 if (!theMother) continue;
1005 allancestors.insert(theMother);
1006 findParticleAncestors(theMother, allancestors);
1007 }
1008 }
1009
1011
1012 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1013 auto endVtx = thePart->end_vertex();
1014 if (!endVtx) return;
1015 for (const auto& theDaughter: endVtx->particles_out()) {
1016 if (!theDaughter) continue;
1017 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1018 allstabledescendants.insert(theDaughter);
1019 }
1020 findParticleStableDescendants(theDaughter, allstabledescendants);
1021 }
1022 }
1023
1027
1028 template <class T> bool isHardScatteringVertex(T pVert) {
1029 if (pVert == nullptr) return false;
1030 T pV = pVert;
1031 int numOfPartIn(0);
1032 int pdg(0);
1033
1034 do {
1035 pVert = pV;
1036 auto incoming = pVert->particles_in();
1037 numOfPartIn = incoming.size();
1038 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1039 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1040
1041 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1042
1043 if (numOfPartIn == 2) {
1044 auto incoming = pVert->particles_in();
1045 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1046 }
1047 return false;
1048}
1049
1053
1054 template <class T, class U>
1055 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1056 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1057 auto vtx = p->production_vertex();
1058 if (!vtx) return false;
1059 bool fromHad = false;
1060 for ( const auto& parent : particles_in(vtx) ) {
1061 if (!parent) continue;
1062 // should this really go into parton-level territory?
1063 // probably depends where BSM particles are being decayed
1064 fromBSM |= isBSM(parent);
1065 if (!isPhysical(parent)) return false;
1066 fromTau |= isTau(parent);
1067 if (isHadron(parent)&&!isBeam(parent)) {
1068 if (!hadron) hadron = parent; // assumes linear hadron parentage
1069 return true;
1070 }
1071 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1072 }
1073 return fromHad;
1074 }
1075
1078
1079 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1080 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1081 decltype(thePart->end_vertex()) pVert(nullptr);
1082 if (EndVert != nullptr) {
1083 do {
1084 bool samePart = false;
1085 pVert = nullptr;
1086 auto outgoing = EndVert->particles_out();
1087 auto incoming = EndVert->particles_in();
1088 for (const auto& itrDaug: outgoing) {
1089 if (!itrDaug) continue;
1090 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1091 // brem on generator level for tau
1092 (outgoing.size() == 1 && incoming.size() == 1 &&
1094 itrDaug->pdg_id() == thePart->pdg_id()) {
1095 samePart = true;
1096 pVert = itrDaug->end_vertex();
1097 }
1098 }
1099 if (samePart) EndVert = pVert;
1100 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1101 }
1102 return EndVert;
1103 }
1104
1106
1107 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1108 if (!theVert) return {};
1109 decltype(theVert->particles_out()) finalStatePart;
1110 auto outgoing = theVert->particles_out();
1111 for (const auto& thePart: outgoing) {
1112 if (!thePart) continue;
1113 finalStatePart.push_back(thePart);
1114 if (isStable(thePart)) continue;
1115 V pVert = findSimulatedEndVertex(thePart);
1116 if (pVert == theVert) break; // to prevent Sherpa loop
1117 if (pVert != nullptr) {
1118 auto vecPart = findFinalStateParticles<V>(pVert);
1119 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1120 }
1121 }
1122 return finalStatePart;
1123 }
1124
1125}
1126#endif

◆ numberOfProtons() [3/3]

template<class T>
int MC::numberOfProtons ( const T & p)
inline

Definition at line 834 of file HepMCHelpers.h.

855{
856inline
857auto particles_in (const HepMC::GenVertex* p) {
858 return std::ranges::subrange (p->particles_in_const_begin(),
859 p->particles_in_const_end());
860}
861}
862#endif
863
864namespace MC
865{
866 template <class VTX>
867 auto particles_in (const VTX* p) { return p->particles_in(); }
868 template <class VTX>
869 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
870
871 namespace Pythia8
872 {
874 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
875
876 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
877
878 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
879 }
880
881#include "AtlasPID.h"
882
884 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
885
887 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
888
890 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
891
893 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
894
896 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
897
899 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
900
902 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
903
905 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
906
908 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
909
911 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
912
916 template <class T> inline bool isStableOrSimDecayed(const T& p) {
917 const auto vertex = p->end_vertex();
918 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
919 }
920
922 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
923
925 template <class T> inline bool isSpecialNonInteracting(const T& p) {
926 const int apid = std::abs(p->pdg_id());
927 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
928 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
929 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
930 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
931 return false;
932 }
933
935
936 template <class T> T findMother(T thePart) {
937 auto partOriVert = thePart->production_vertex();
938 if (!partOriVert) return nullptr;
939
940 long partPDG = thePart->pdg_id();
941 long MotherPDG(0);
942
943 auto MothOriVert = partOriVert;
944 MothOriVert = nullptr;
945 T theMoth(nullptr);
946
947 size_t itr = 0;
948 do {
949 if (itr != 0) partOriVert = MothOriVert;
950 for ( const auto& p : particles_in(partOriVert) ) {
951 theMoth = p;
952 if (!theMoth) continue;
953 MotherPDG = theMoth->pdg_id();
954 MothOriVert = theMoth->production_vertex();
955 if (MotherPDG == partPDG) break;
956 }
957 itr++;
958 if (itr > 100) {
959 break;
960 }
961 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
962 MothOriVert != partOriVert);
963 return theMoth;
964 }
965
967
968 template <class C, class T> T findMatching(C TruthContainer, T p) {
969 T ptrPart = nullptr;
970 if (!p) return ptrPart;
971 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
972 for (T truthParticle : *TruthContainer) {
973 if (HepMC::is_sim_descendant(p,truthParticle)) {
974 ptrPart = truthParticle;
975 break;
976 }
977 }
978 }
979 else {
980 for (T truthParticle : TruthContainer) {
981 if (HepMC::is_sim_descendant(p,truthParticle)) {
982 ptrPart = truthParticle;
983 break;
984 }
985 }
986 }
987 return ptrPart;
988 }
990
991 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
992 auto prodVtx = thePart->production_vertex();
993 if (!prodVtx) return;
994 for (const auto& theMother: prodVtx->particles_in()) {
995 if (!theMother) continue;
996 allancestors.insert(theMother);
997 findParticleAncestors(theMother, allancestors);
998 }
999 }
1000
1002
1003 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1004 auto endVtx = thePart->end_vertex();
1005 if (!endVtx) return;
1006 for (const auto& theDaughter: endVtx->particles_out()) {
1007 if (!theDaughter) continue;
1008 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1009 allstabledescendants.insert(theDaughter);
1010 }
1011 findParticleStableDescendants(theDaughter, allstabledescendants);
1012 }
1013 }
1014
1018
1019 template <class T> bool isHardScatteringVertex(T pVert) {
1020 if (pVert == nullptr) return false;
1021 T pV = pVert;
1022 int numOfPartIn(0);
1023 int pdg(0);
1024
1025 do {
1026 pVert = pV;
1027 auto incoming = pVert->particles_in();
1028 numOfPartIn = incoming.size();
1029 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1030 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1031
1032 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1033
1034 if (numOfPartIn == 2) {
1035 auto incoming = pVert->particles_in();
1036 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1037 }
1038 return false;
1039}
1040
1044
1045 template <class T, class U>
1046 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1047 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1048 auto vtx = p->production_vertex();
1049 if (!vtx) return false;
1050 bool fromHad = false;
1051 for ( const auto& parent : particles_in(vtx) ) {
1052 if (!parent) continue;
1053 // should this really go into parton-level territory?
1054 // probably depends where BSM particles are being decayed
1055 fromBSM |= isBSM(parent);
1056 if (!isPhysical(parent)) return false;
1057 fromTau |= isTau(parent);
1058 if (isHadron(parent)&&!isBeam(parent)) {
1059 if (!hadron) hadron = parent; // assumes linear hadron parentage
1060 return true;
1061 }
1062 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1063 }
1064 return fromHad;
1065 }
1066
1069
1070 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1071 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1072 decltype(thePart->end_vertex()) pVert(nullptr);
1073 if (EndVert != nullptr) {
1074 do {
1075 bool samePart = false;
1076 pVert = nullptr;
1077 auto outgoing = EndVert->particles_out();
1078 auto incoming = EndVert->particles_in();
1079 for (const auto& itrDaug: outgoing) {
1080 if (!itrDaug) continue;
1081 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1082 // brem on generator level for tau
1083 (outgoing.size() == 1 && incoming.size() == 1 &&
1085 itrDaug->pdg_id() == thePart->pdg_id()) {
1086 samePart = true;
1087 pVert = itrDaug->end_vertex();
1088 }
1089 }
1090 if (samePart) EndVert = pVert;
1091 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1092 }
1093 return EndVert;
1094 }
1095
1097
1098 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1099 if (!theVert) return {};
1100 decltype(theVert->particles_out()) finalStatePart;
1101 auto outgoing = theVert->particles_out();
1102 for (const auto& thePart: outgoing) {
1103 if (!thePart) continue;
1104 finalStatePart.push_back(thePart);
1105 if (isStable(thePart)) continue;
1106 V pVert = findSimulatedEndVertex(thePart);
1107 if (pVert == theVert) break; // to prevent Sherpa loop
1108 if (pVert != nullptr) {
1109 auto vecPart = findFinalStateParticles<V>(pVert);
1110 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1111 }
1112 }
1113 return finalStatePart;
1114 }
1115
1116}
1117#endif

◆ particles_in() [1/3]

auto MC::particles_in ( const HepMC::GenVertex * p)
inline

Definition at line 24 of file HepMCHelpers.h.

24 {
25 return std::ranges::subrange (p->particles_in_const_begin(),
26 p->particles_in_const_end());
27}

◆ particles_in() [2/3]

template<class VTX>
auto MC::particles_in ( const std::shared_ptr< VTX > & p)

Definition at line 36 of file HepMCHelpers.h.

36{ return p->particles_in(); }

◆ particles_in() [3/3]

template<class VTX>
auto MC::particles_in ( const VTX * p)

Definition at line 34 of file HepMCHelpers.h.

34{ return p->particles_in(); }

◆ spin() [1/3]

template<>
double MC::spin ( const DecodedPID & p)
inline

Definition at line 1149 of file HepMCHelpers.h.

1170{
1171inline
1172auto particles_in (const HepMC::GenVertex* p) {
1173 return std::ranges::subrange (p->particles_in_const_begin(),
1174 p->particles_in_const_end());
1175}
1176}
1177#endif
1178
1179namespace MC
1180{
1181 template <class VTX>
1182 auto particles_in (const VTX* p) { return p->particles_in(); }
1183 template <class VTX>
1184 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1185
1186 namespace Pythia8
1187 {
1189 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1190
1191 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1192
1193 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1194 }
1195
1196#include "AtlasPID.h"
1197
1199 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1200
1202 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1203
1205 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1206
1208 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1209
1211 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1212
1214 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1215
1217 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1218
1220 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1221
1223 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1224
1226 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1227
1231 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1232 const auto vertex = p->end_vertex();
1233 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1234 }
1235
1237 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1238
1240 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1241 const int apid = std::abs(p->pdg_id());
1242 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1243 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1244 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1245 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1246 return false;
1247 }
1248
1250
1251 template <class T> T findMother(T thePart) {
1252 auto partOriVert = thePart->production_vertex();
1253 if (!partOriVert) return nullptr;
1254
1255 long partPDG = thePart->pdg_id();
1256 long MotherPDG(0);
1257
1258 auto MothOriVert = partOriVert;
1259 MothOriVert = nullptr;
1260 T theMoth(nullptr);
1261
1262 size_t itr = 0;
1263 do {
1264 if (itr != 0) partOriVert = MothOriVert;
1265 for ( const auto& p : particles_in(partOriVert) ) {
1266 theMoth = p;
1267 if (!theMoth) continue;
1268 MotherPDG = theMoth->pdg_id();
1269 MothOriVert = theMoth->production_vertex();
1270 if (MotherPDG == partPDG) break;
1271 }
1272 itr++;
1273 if (itr > 100) {
1274 break;
1275 }
1276 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1277 MothOriVert != partOriVert);
1278 return theMoth;
1279 }
1280
1282
1283 template <class C, class T> T findMatching(C TruthContainer, T p) {
1284 T ptrPart = nullptr;
1285 if (!p) return ptrPart;
1286 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1287 for (T truthParticle : *TruthContainer) {
1288 if (HepMC::is_sim_descendant(p,truthParticle)) {
1289 ptrPart = truthParticle;
1290 break;
1291 }
1292 }
1293 }
1294 else {
1295 for (T truthParticle : TruthContainer) {
1296 if (HepMC::is_sim_descendant(p,truthParticle)) {
1297 ptrPart = truthParticle;
1298 break;
1299 }
1300 }
1301 }
1302 return ptrPart;
1303 }
1305
1306 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1307 auto prodVtx = thePart->production_vertex();
1308 if (!prodVtx) return;
1309 for (const auto& theMother: prodVtx->particles_in()) {
1310 if (!theMother) continue;
1311 allancestors.insert(theMother);
1312 findParticleAncestors(theMother, allancestors);
1313 }
1314 }
1315
1317
1318 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1319 auto endVtx = thePart->end_vertex();
1320 if (!endVtx) return;
1321 for (const auto& theDaughter: endVtx->particles_out()) {
1322 if (!theDaughter) continue;
1323 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1324 allstabledescendants.insert(theDaughter);
1325 }
1326 findParticleStableDescendants(theDaughter, allstabledescendants);
1327 }
1328 }
1329
1333
1334 template <class T> bool isHardScatteringVertex(T pVert) {
1335 if (pVert == nullptr) return false;
1336 T pV = pVert;
1337 int numOfPartIn(0);
1338 int pdg(0);
1339
1340 do {
1341 pVert = pV;
1342 auto incoming = pVert->particles_in();
1343 numOfPartIn = incoming.size();
1344 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1345 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1346
1347 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1348
1349 if (numOfPartIn == 2) {
1350 auto incoming = pVert->particles_in();
1351 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1352 }
1353 return false;
1354}
1355
1359
1360 template <class T, class U>
1361 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1362 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1363 auto vtx = p->production_vertex();
1364 if (!vtx) return false;
1365 bool fromHad = false;
1366 for ( const auto& parent : particles_in(vtx) ) {
1367 if (!parent) continue;
1368 // should this really go into parton-level territory?
1369 // probably depends where BSM particles are being decayed
1370 fromBSM |= isBSM(parent);
1371 if (!isPhysical(parent)) return false;
1372 fromTau |= isTau(parent);
1373 if (isHadron(parent)&&!isBeam(parent)) {
1374 if (!hadron) hadron = parent; // assumes linear hadron parentage
1375 return true;
1376 }
1377 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1378 }
1379 return fromHad;
1380 }
1381
1384
1385 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1386 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1387 decltype(thePart->end_vertex()) pVert(nullptr);
1388 if (EndVert != nullptr) {
1389 do {
1390 bool samePart = false;
1391 pVert = nullptr;
1392 auto outgoing = EndVert->particles_out();
1393 auto incoming = EndVert->particles_in();
1394 for (const auto& itrDaug: outgoing) {
1395 if (!itrDaug) continue;
1396 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1397 // brem on generator level for tau
1398 (outgoing.size() == 1 && incoming.size() == 1 &&
1400 itrDaug->pdg_id() == thePart->pdg_id()) {
1401 samePart = true;
1402 pVert = itrDaug->end_vertex();
1403 }
1404 }
1405 if (samePart) EndVert = pVert;
1406 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1407 }
1408 return EndVert;
1409 }
1410
1412
1413 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1414 if (!theVert) return {};
1415 decltype(theVert->particles_out()) finalStatePart;
1416 auto outgoing = theVert->particles_out();
1417 for (const auto& thePart: outgoing) {
1418 if (!thePart) continue;
1419 finalStatePart.push_back(thePart);
1420 if (isStable(thePart)) continue;
1421 V pVert = findSimulatedEndVertex(thePart);
1422 if (pVert == theVert) break; // to prevent Sherpa loop
1423 if (pVert != nullptr) {
1424 auto vecPart = findFinalStateParticles<V>(pVert);
1425 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1426 }
1427 }
1428 return finalStatePart;
1429 }
1430
1431}
1432#endif

◆ spin() [2/3]

template<>
double MC::spin ( const int & p)
inline

Definition at line 1150 of file HepMCHelpers.h.

1171{
1172inline
1173auto particles_in (const HepMC::GenVertex* p) {
1174 return std::ranges::subrange (p->particles_in_const_begin(),
1175 p->particles_in_const_end());
1176}
1177}
1178#endif
1179
1180namespace MC
1181{
1182 template <class VTX>
1183 auto particles_in (const VTX* p) { return p->particles_in(); }
1184 template <class VTX>
1185 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1186
1187 namespace Pythia8
1188 {
1190 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1191
1192 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1193
1194 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1195 }
1196
1197#include "AtlasPID.h"
1198
1200 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1201
1203 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1204
1206 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1207
1209 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1210
1212 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1213
1215 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1216
1218 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1219
1221 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1222
1224 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1225
1227 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1228
1232 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1233 const auto vertex = p->end_vertex();
1234 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1235 }
1236
1238 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1239
1241 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1242 const int apid = std::abs(p->pdg_id());
1243 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1244 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1245 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1246 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1247 return false;
1248 }
1249
1251
1252 template <class T> T findMother(T thePart) {
1253 auto partOriVert = thePart->production_vertex();
1254 if (!partOriVert) return nullptr;
1255
1256 long partPDG = thePart->pdg_id();
1257 long MotherPDG(0);
1258
1259 auto MothOriVert = partOriVert;
1260 MothOriVert = nullptr;
1261 T theMoth(nullptr);
1262
1263 size_t itr = 0;
1264 do {
1265 if (itr != 0) partOriVert = MothOriVert;
1266 for ( const auto& p : particles_in(partOriVert) ) {
1267 theMoth = p;
1268 if (!theMoth) continue;
1269 MotherPDG = theMoth->pdg_id();
1270 MothOriVert = theMoth->production_vertex();
1271 if (MotherPDG == partPDG) break;
1272 }
1273 itr++;
1274 if (itr > 100) {
1275 break;
1276 }
1277 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1278 MothOriVert != partOriVert);
1279 return theMoth;
1280 }
1281
1283
1284 template <class C, class T> T findMatching(C TruthContainer, T p) {
1285 T ptrPart = nullptr;
1286 if (!p) return ptrPart;
1287 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1288 for (T truthParticle : *TruthContainer) {
1289 if (HepMC::is_sim_descendant(p,truthParticle)) {
1290 ptrPart = truthParticle;
1291 break;
1292 }
1293 }
1294 }
1295 else {
1296 for (T truthParticle : TruthContainer) {
1297 if (HepMC::is_sim_descendant(p,truthParticle)) {
1298 ptrPart = truthParticle;
1299 break;
1300 }
1301 }
1302 }
1303 return ptrPart;
1304 }
1306
1307 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1308 auto prodVtx = thePart->production_vertex();
1309 if (!prodVtx) return;
1310 for (const auto& theMother: prodVtx->particles_in()) {
1311 if (!theMother) continue;
1312 allancestors.insert(theMother);
1313 findParticleAncestors(theMother, allancestors);
1314 }
1315 }
1316
1318
1319 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1320 auto endVtx = thePart->end_vertex();
1321 if (!endVtx) return;
1322 for (const auto& theDaughter: endVtx->particles_out()) {
1323 if (!theDaughter) continue;
1324 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1325 allstabledescendants.insert(theDaughter);
1326 }
1327 findParticleStableDescendants(theDaughter, allstabledescendants);
1328 }
1329 }
1330
1334
1335 template <class T> bool isHardScatteringVertex(T pVert) {
1336 if (pVert == nullptr) return false;
1337 T pV = pVert;
1338 int numOfPartIn(0);
1339 int pdg(0);
1340
1341 do {
1342 pVert = pV;
1343 auto incoming = pVert->particles_in();
1344 numOfPartIn = incoming.size();
1345 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1346 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1347
1348 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1349
1350 if (numOfPartIn == 2) {
1351 auto incoming = pVert->particles_in();
1352 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1353 }
1354 return false;
1355}
1356
1360
1361 template <class T, class U>
1362 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1363 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1364 auto vtx = p->production_vertex();
1365 if (!vtx) return false;
1366 bool fromHad = false;
1367 for ( const auto& parent : particles_in(vtx) ) {
1368 if (!parent) continue;
1369 // should this really go into parton-level territory?
1370 // probably depends where BSM particles are being decayed
1371 fromBSM |= isBSM(parent);
1372 if (!isPhysical(parent)) return false;
1373 fromTau |= isTau(parent);
1374 if (isHadron(parent)&&!isBeam(parent)) {
1375 if (!hadron) hadron = parent; // assumes linear hadron parentage
1376 return true;
1377 }
1378 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1379 }
1380 return fromHad;
1381 }
1382
1385
1386 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1387 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1388 decltype(thePart->end_vertex()) pVert(nullptr);
1389 if (EndVert != nullptr) {
1390 do {
1391 bool samePart = false;
1392 pVert = nullptr;
1393 auto outgoing = EndVert->particles_out();
1394 auto incoming = EndVert->particles_in();
1395 for (const auto& itrDaug: outgoing) {
1396 if (!itrDaug) continue;
1397 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1398 // brem on generator level for tau
1399 (outgoing.size() == 1 && incoming.size() == 1 &&
1401 itrDaug->pdg_id() == thePart->pdg_id()) {
1402 samePart = true;
1403 pVert = itrDaug->end_vertex();
1404 }
1405 }
1406 if (samePart) EndVert = pVert;
1407 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1408 }
1409 return EndVert;
1410 }
1411
1413
1414 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1415 if (!theVert) return {};
1416 decltype(theVert->particles_out()) finalStatePart;
1417 auto outgoing = theVert->particles_out();
1418 for (const auto& thePart: outgoing) {
1419 if (!thePart) continue;
1420 finalStatePart.push_back(thePart);
1421 if (isStable(thePart)) continue;
1422 V pVert = findSimulatedEndVertex(thePart);
1423 if (pVert == theVert) break; // to prevent Sherpa loop
1424 if (pVert != nullptr) {
1425 auto vecPart = findFinalStateParticles<V>(pVert);
1426 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1427 }
1428 }
1429 return finalStatePart;
1430 }
1431
1432}
1433#endif

◆ spin() [3/3]

template<class T>
double MC::spin ( const T & p)
inline

Definition at line 1148 of file HepMCHelpers.h.

1169{
1170inline
1171auto particles_in (const HepMC::GenVertex* p) {
1172 return std::ranges::subrange (p->particles_in_const_begin(),
1173 p->particles_in_const_end());
1174}
1175}
1176#endif
1177
1178namespace MC
1179{
1180 template <class VTX>
1181 auto particles_in (const VTX* p) { return p->particles_in(); }
1182 template <class VTX>
1183 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1184
1185 namespace Pythia8
1186 {
1188 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1189
1190 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1191
1192 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1193 }
1194
1195#include "AtlasPID.h"
1196
1198 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1199
1201 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1202
1204 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1205
1207 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1208
1210 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1211
1213 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1214
1216 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1217
1219 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1220
1222 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1223
1225 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1226
1230 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1231 const auto vertex = p->end_vertex();
1232 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1233 }
1234
1236 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1237
1239 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1240 const int apid = std::abs(p->pdg_id());
1241 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1242 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1243 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1244 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1245 return false;
1246 }
1247
1249
1250 template <class T> T findMother(T thePart) {
1251 auto partOriVert = thePart->production_vertex();
1252 if (!partOriVert) return nullptr;
1253
1254 long partPDG = thePart->pdg_id();
1255 long MotherPDG(0);
1256
1257 auto MothOriVert = partOriVert;
1258 MothOriVert = nullptr;
1259 T theMoth(nullptr);
1260
1261 size_t itr = 0;
1262 do {
1263 if (itr != 0) partOriVert = MothOriVert;
1264 for ( const auto& p : particles_in(partOriVert) ) {
1265 theMoth = p;
1266 if (!theMoth) continue;
1267 MotherPDG = theMoth->pdg_id();
1268 MothOriVert = theMoth->production_vertex();
1269 if (MotherPDG == partPDG) break;
1270 }
1271 itr++;
1272 if (itr > 100) {
1273 break;
1274 }
1275 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1276 MothOriVert != partOriVert);
1277 return theMoth;
1278 }
1279
1281
1282 template <class C, class T> T findMatching(C TruthContainer, T p) {
1283 T ptrPart = nullptr;
1284 if (!p) return ptrPart;
1285 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1286 for (T truthParticle : *TruthContainer) {
1287 if (HepMC::is_sim_descendant(p,truthParticle)) {
1288 ptrPart = truthParticle;
1289 break;
1290 }
1291 }
1292 }
1293 else {
1294 for (T truthParticle : TruthContainer) {
1295 if (HepMC::is_sim_descendant(p,truthParticle)) {
1296 ptrPart = truthParticle;
1297 break;
1298 }
1299 }
1300 }
1301 return ptrPart;
1302 }
1304
1305 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1306 auto prodVtx = thePart->production_vertex();
1307 if (!prodVtx) return;
1308 for (const auto& theMother: prodVtx->particles_in()) {
1309 if (!theMother) continue;
1310 allancestors.insert(theMother);
1311 findParticleAncestors(theMother, allancestors);
1312 }
1313 }
1314
1316
1317 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1318 auto endVtx = thePart->end_vertex();
1319 if (!endVtx) return;
1320 for (const auto& theDaughter: endVtx->particles_out()) {
1321 if (!theDaughter) continue;
1322 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1323 allstabledescendants.insert(theDaughter);
1324 }
1325 findParticleStableDescendants(theDaughter, allstabledescendants);
1326 }
1327 }
1328
1332
1333 template <class T> bool isHardScatteringVertex(T pVert) {
1334 if (pVert == nullptr) return false;
1335 T pV = pVert;
1336 int numOfPartIn(0);
1337 int pdg(0);
1338
1339 do {
1340 pVert = pV;
1341 auto incoming = pVert->particles_in();
1342 numOfPartIn = incoming.size();
1343 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1344 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1345
1346 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1347
1348 if (numOfPartIn == 2) {
1349 auto incoming = pVert->particles_in();
1350 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1351 }
1352 return false;
1353}
1354
1358
1359 template <class T, class U>
1360 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1361 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1362 auto vtx = p->production_vertex();
1363 if (!vtx) return false;
1364 bool fromHad = false;
1365 for ( const auto& parent : particles_in(vtx) ) {
1366 if (!parent) continue;
1367 // should this really go into parton-level territory?
1368 // probably depends where BSM particles are being decayed
1369 fromBSM |= isBSM(parent);
1370 if (!isPhysical(parent)) return false;
1371 fromTau |= isTau(parent);
1372 if (isHadron(parent)&&!isBeam(parent)) {
1373 if (!hadron) hadron = parent; // assumes linear hadron parentage
1374 return true;
1375 }
1376 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1377 }
1378 return fromHad;
1379 }
1380
1383
1384 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1385 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1386 decltype(thePart->end_vertex()) pVert(nullptr);
1387 if (EndVert != nullptr) {
1388 do {
1389 bool samePart = false;
1390 pVert = nullptr;
1391 auto outgoing = EndVert->particles_out();
1392 auto incoming = EndVert->particles_in();
1393 for (const auto& itrDaug: outgoing) {
1394 if (!itrDaug) continue;
1395 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1396 // brem on generator level for tau
1397 (outgoing.size() == 1 && incoming.size() == 1 &&
1399 itrDaug->pdg_id() == thePart->pdg_id()) {
1400 samePart = true;
1401 pVert = itrDaug->end_vertex();
1402 }
1403 }
1404 if (samePart) EndVert = pVert;
1405 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1406 }
1407 return EndVert;
1408 }
1409
1411
1412 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1413 if (!theVert) return {};
1414 decltype(theVert->particles_out()) finalStatePart;
1415 auto outgoing = theVert->particles_out();
1416 for (const auto& thePart: outgoing) {
1417 if (!thePart) continue;
1418 finalStatePart.push_back(thePart);
1419 if (isStable(thePart)) continue;
1420 V pVert = findSimulatedEndVertex(thePart);
1421 if (pVert == theVert) break; // to prevent Sherpa loop
1422 if (pVert != nullptr) {
1423 auto vecPart = findFinalStateParticles<V>(pVert);
1424 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1425 }
1426 }
1427 return finalStatePart;
1428 }
1429
1430}
1431#endif

◆ spin2() [1/3]

template<>
int MC::spin2 ( const DecodedPID & p)
inline

Definition at line 1109 of file HepMCHelpers.h.

1130 {
1131inline
1132auto particles_in (const HepMC::GenVertex* p) {
1133 return std::ranges::subrange (p->particles_in_const_begin(),
1134 p->particles_in_const_end());
1135}
1136}
1137#endif
1138
1139namespace MC
1140{
1141 template <class VTX>
1142 auto particles_in (const VTX* p) { return p->particles_in(); }
1143 template <class VTX>
1144 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1145
1146 namespace Pythia8
1147 {
1149 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1150
1151 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1152
1153 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1154 }
1155
1156#include "AtlasPID.h"
1157
1159 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1160
1162 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1163
1165 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1166
1168 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1169
1171 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1172
1174 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1175
1177 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1178
1180 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1181
1183 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1184
1186 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1187
1191 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1192 const auto vertex = p->end_vertex();
1193 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1194 }
1195
1197 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1198
1200 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1201 const int apid = std::abs(p->pdg_id());
1202 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1203 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1204 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1205 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1206 return false;
1207 }
1208
1210
1211 template <class T> T findMother(T thePart) {
1212 auto partOriVert = thePart->production_vertex();
1213 if (!partOriVert) return nullptr;
1214
1215 long partPDG = thePart->pdg_id();
1216 long MotherPDG(0);
1217
1218 auto MothOriVert = partOriVert;
1219 MothOriVert = nullptr;
1220 T theMoth(nullptr);
1221
1222 size_t itr = 0;
1223 do {
1224 if (itr != 0) partOriVert = MothOriVert;
1225 for ( const auto& p : particles_in(partOriVert) ) {
1226 theMoth = p;
1227 if (!theMoth) continue;
1228 MotherPDG = theMoth->pdg_id();
1229 MothOriVert = theMoth->production_vertex();
1230 if (MotherPDG == partPDG) break;
1231 }
1232 itr++;
1233 if (itr > 100) {
1234 break;
1235 }
1236 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1237 MothOriVert != partOriVert);
1238 return theMoth;
1239 }
1240
1242
1243 template <class C, class T> T findMatching(C TruthContainer, T p) {
1244 T ptrPart = nullptr;
1245 if (!p) return ptrPart;
1246 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1247 for (T truthParticle : *TruthContainer) {
1248 if (HepMC::is_sim_descendant(p,truthParticle)) {
1249 ptrPart = truthParticle;
1250 break;
1251 }
1252 }
1253 }
1254 else {
1255 for (T truthParticle : TruthContainer) {
1256 if (HepMC::is_sim_descendant(p,truthParticle)) {
1257 ptrPart = truthParticle;
1258 break;
1259 }
1260 }
1261 }
1262 return ptrPart;
1263 }
1265
1266 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1267 auto prodVtx = thePart->production_vertex();
1268 if (!prodVtx) return;
1269 for (const auto& theMother: prodVtx->particles_in()) {
1270 if (!theMother) continue;
1271 allancestors.insert(theMother);
1272 findParticleAncestors(theMother, allancestors);
1273 }
1274 }
1275
1277
1278 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1279 auto endVtx = thePart->end_vertex();
1280 if (!endVtx) return;
1281 for (const auto& theDaughter: endVtx->particles_out()) {
1282 if (!theDaughter) continue;
1283 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1284 allstabledescendants.insert(theDaughter);
1285 }
1286 findParticleStableDescendants(theDaughter, allstabledescendants);
1287 }
1288 }
1289
1293
1294 template <class T> bool isHardScatteringVertex(T pVert) {
1295 if (pVert == nullptr) return false;
1296 T pV = pVert;
1297 int numOfPartIn(0);
1298 int pdg(0);
1299
1300 do {
1301 pVert = pV;
1302 auto incoming = pVert->particles_in();
1303 numOfPartIn = incoming.size();
1304 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1305 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1306
1307 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1308
1309 if (numOfPartIn == 2) {
1310 auto incoming = pVert->particles_in();
1311 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1312 }
1313 return false;
1314}
1315
1319
1320 template <class T, class U>
1321 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1322 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1323 auto vtx = p->production_vertex();
1324 if (!vtx) return false;
1325 bool fromHad = false;
1326 for ( const auto& parent : particles_in(vtx) ) {
1327 if (!parent) continue;
1328 // should this really go into parton-level territory?
1329 // probably depends where BSM particles are being decayed
1330 fromBSM |= isBSM(parent);
1331 if (!isPhysical(parent)) return false;
1332 fromTau |= isTau(parent);
1333 if (isHadron(parent)&&!isBeam(parent)) {
1334 if (!hadron) hadron = parent; // assumes linear hadron parentage
1335 return true;
1336 }
1337 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1338 }
1339 return fromHad;
1340 }
1341
1344
1345 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1346 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1347 decltype(thePart->end_vertex()) pVert(nullptr);
1348 if (EndVert != nullptr) {
1349 do {
1350 bool samePart = false;
1351 pVert = nullptr;
1352 auto outgoing = EndVert->particles_out();
1353 auto incoming = EndVert->particles_in();
1354 for (const auto& itrDaug: outgoing) {
1355 if (!itrDaug) continue;
1356 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1357 // brem on generator level for tau
1358 (outgoing.size() == 1 && incoming.size() == 1 &&
1360 itrDaug->pdg_id() == thePart->pdg_id()) {
1361 samePart = true;
1362 pVert = itrDaug->end_vertex();
1363 }
1364 }
1365 if (samePart) EndVert = pVert;
1366 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1367 }
1368 return EndVert;
1369 }
1370
1372
1373 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1374 if (!theVert) return {};
1375 decltype(theVert->particles_out()) finalStatePart;
1376 auto outgoing = theVert->particles_out();
1377 for (const auto& thePart: outgoing) {
1378 if (!thePart) continue;
1379 finalStatePart.push_back(thePart);
1380 if (isStable(thePart)) continue;
1381 V pVert = findSimulatedEndVertex(thePart);
1382 if (pVert == theVert) break; // to prevent Sherpa loop
1383 if (pVert != nullptr) {
1384 auto vecPart = findFinalStateParticles<V>(pVert);
1385 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1386 }
1387 }
1388 return finalStatePart;
1389 }
1390
1391}
1392#endif

◆ spin2() [2/3]

template<>
int MC::spin2 ( const int & p)
inline

Definition at line 1146 of file HepMCHelpers.h.

1167{
1168inline
1169auto particles_in (const HepMC::GenVertex* p) {
1170 return std::ranges::subrange (p->particles_in_const_begin(),
1171 p->particles_in_const_end());
1172}
1173}
1174#endif
1175
1176namespace MC
1177{
1178 template <class VTX>
1179 auto particles_in (const VTX* p) { return p->particles_in(); }
1180 template <class VTX>
1181 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1182
1183 namespace Pythia8
1184 {
1186 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1187
1188 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1189
1190 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1191 }
1192
1193#include "AtlasPID.h"
1194
1196 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1197
1199 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1200
1202 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1203
1205 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1206
1208 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1209
1211 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1212
1214 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1215
1217 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1218
1220 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1221
1223 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1224
1228 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1229 const auto vertex = p->end_vertex();
1230 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1231 }
1232
1234 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1235
1237 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1238 const int apid = std::abs(p->pdg_id());
1239 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1240 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1241 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1242 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1243 return false;
1244 }
1245
1247
1248 template <class T> T findMother(T thePart) {
1249 auto partOriVert = thePart->production_vertex();
1250 if (!partOriVert) return nullptr;
1251
1252 long partPDG = thePart->pdg_id();
1253 long MotherPDG(0);
1254
1255 auto MothOriVert = partOriVert;
1256 MothOriVert = nullptr;
1257 T theMoth(nullptr);
1258
1259 size_t itr = 0;
1260 do {
1261 if (itr != 0) partOriVert = MothOriVert;
1262 for ( const auto& p : particles_in(partOriVert) ) {
1263 theMoth = p;
1264 if (!theMoth) continue;
1265 MotherPDG = theMoth->pdg_id();
1266 MothOriVert = theMoth->production_vertex();
1267 if (MotherPDG == partPDG) break;
1268 }
1269 itr++;
1270 if (itr > 100) {
1271 break;
1272 }
1273 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1274 MothOriVert != partOriVert);
1275 return theMoth;
1276 }
1277
1279
1280 template <class C, class T> T findMatching(C TruthContainer, T p) {
1281 T ptrPart = nullptr;
1282 if (!p) return ptrPart;
1283 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1284 for (T truthParticle : *TruthContainer) {
1285 if (HepMC::is_sim_descendant(p,truthParticle)) {
1286 ptrPart = truthParticle;
1287 break;
1288 }
1289 }
1290 }
1291 else {
1292 for (T truthParticle : TruthContainer) {
1293 if (HepMC::is_sim_descendant(p,truthParticle)) {
1294 ptrPart = truthParticle;
1295 break;
1296 }
1297 }
1298 }
1299 return ptrPart;
1300 }
1302
1303 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1304 auto prodVtx = thePart->production_vertex();
1305 if (!prodVtx) return;
1306 for (const auto& theMother: prodVtx->particles_in()) {
1307 if (!theMother) continue;
1308 allancestors.insert(theMother);
1309 findParticleAncestors(theMother, allancestors);
1310 }
1311 }
1312
1314
1315 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1316 auto endVtx = thePart->end_vertex();
1317 if (!endVtx) return;
1318 for (const auto& theDaughter: endVtx->particles_out()) {
1319 if (!theDaughter) continue;
1320 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1321 allstabledescendants.insert(theDaughter);
1322 }
1323 findParticleStableDescendants(theDaughter, allstabledescendants);
1324 }
1325 }
1326
1330
1331 template <class T> bool isHardScatteringVertex(T pVert) {
1332 if (pVert == nullptr) return false;
1333 T pV = pVert;
1334 int numOfPartIn(0);
1335 int pdg(0);
1336
1337 do {
1338 pVert = pV;
1339 auto incoming = pVert->particles_in();
1340 numOfPartIn = incoming.size();
1341 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1342 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1343
1344 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1345
1346 if (numOfPartIn == 2) {
1347 auto incoming = pVert->particles_in();
1348 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1349 }
1350 return false;
1351}
1352
1356
1357 template <class T, class U>
1358 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1359 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1360 auto vtx = p->production_vertex();
1361 if (!vtx) return false;
1362 bool fromHad = false;
1363 for ( const auto& parent : particles_in(vtx) ) {
1364 if (!parent) continue;
1365 // should this really go into parton-level territory?
1366 // probably depends where BSM particles are being decayed
1367 fromBSM |= isBSM(parent);
1368 if (!isPhysical(parent)) return false;
1369 fromTau |= isTau(parent);
1370 if (isHadron(parent)&&!isBeam(parent)) {
1371 if (!hadron) hadron = parent; // assumes linear hadron parentage
1372 return true;
1373 }
1374 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1375 }
1376 return fromHad;
1377 }
1378
1381
1382 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1383 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1384 decltype(thePart->end_vertex()) pVert(nullptr);
1385 if (EndVert != nullptr) {
1386 do {
1387 bool samePart = false;
1388 pVert = nullptr;
1389 auto outgoing = EndVert->particles_out();
1390 auto incoming = EndVert->particles_in();
1391 for (const auto& itrDaug: outgoing) {
1392 if (!itrDaug) continue;
1393 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1394 // brem on generator level for tau
1395 (outgoing.size() == 1 && incoming.size() == 1 &&
1397 itrDaug->pdg_id() == thePart->pdg_id()) {
1398 samePart = true;
1399 pVert = itrDaug->end_vertex();
1400 }
1401 }
1402 if (samePart) EndVert = pVert;
1403 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1404 }
1405 return EndVert;
1406 }
1407
1409
1410 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1411 if (!theVert) return {};
1412 decltype(theVert->particles_out()) finalStatePart;
1413 auto outgoing = theVert->particles_out();
1414 for (const auto& thePart: outgoing) {
1415 if (!thePart) continue;
1416 finalStatePart.push_back(thePart);
1417 if (isStable(thePart)) continue;
1418 V pVert = findSimulatedEndVertex(thePart);
1419 if (pVert == theVert) break; // to prevent Sherpa loop
1420 if (pVert != nullptr) {
1421 auto vecPart = findFinalStateParticles<V>(pVert);
1422 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1423 }
1424 }
1425 return finalStatePart;
1426 }
1427
1428}
1429#endif

◆ spin2() [3/3]

template<class T>
int MC::spin2 ( const T & p)
inline

Definition at line 1108 of file HepMCHelpers.h.

1129{
1130inline
1131auto particles_in (const HepMC::GenVertex* p) {
1132 return std::ranges::subrange (p->particles_in_const_begin(),
1133 p->particles_in_const_end());
1134}
1135}
1136#endif
1137
1138namespace MC
1139{
1140 template <class VTX>
1141 auto particles_in (const VTX* p) { return p->particles_in(); }
1142 template <class VTX>
1143 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1144
1145 namespace Pythia8
1146 {
1148 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1149
1150 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1151
1152 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1153 }
1154
1155#include "AtlasPID.h"
1156
1158 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1159
1161 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1162
1164 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1165
1167 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1168
1170 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1171
1173 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1174
1176 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1177
1179 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1180
1182 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1183
1185 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1186
1190 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1191 const auto vertex = p->end_vertex();
1192 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1193 }
1194
1196 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1197
1199 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1200 const int apid = std::abs(p->pdg_id());
1201 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1202 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1203 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1204 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1205 return false;
1206 }
1207
1209
1210 template <class T> T findMother(T thePart) {
1211 auto partOriVert = thePart->production_vertex();
1212 if (!partOriVert) return nullptr;
1213
1214 long partPDG = thePart->pdg_id();
1215 long MotherPDG(0);
1216
1217 auto MothOriVert = partOriVert;
1218 MothOriVert = nullptr;
1219 T theMoth(nullptr);
1220
1221 size_t itr = 0;
1222 do {
1223 if (itr != 0) partOriVert = MothOriVert;
1224 for ( const auto& p : particles_in(partOriVert) ) {
1225 theMoth = p;
1226 if (!theMoth) continue;
1227 MotherPDG = theMoth->pdg_id();
1228 MothOriVert = theMoth->production_vertex();
1229 if (MotherPDG == partPDG) break;
1230 }
1231 itr++;
1232 if (itr > 100) {
1233 break;
1234 }
1235 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1236 MothOriVert != partOriVert);
1237 return theMoth;
1238 }
1239
1241
1242 template <class C, class T> T findMatching(C TruthContainer, T p) {
1243 T ptrPart = nullptr;
1244 if (!p) return ptrPart;
1245 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1246 for (T truthParticle : *TruthContainer) {
1247 if (HepMC::is_sim_descendant(p,truthParticle)) {
1248 ptrPart = truthParticle;
1249 break;
1250 }
1251 }
1252 }
1253 else {
1254 for (T truthParticle : TruthContainer) {
1255 if (HepMC::is_sim_descendant(p,truthParticle)) {
1256 ptrPart = truthParticle;
1257 break;
1258 }
1259 }
1260 }
1261 return ptrPart;
1262 }
1264
1265 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1266 auto prodVtx = thePart->production_vertex();
1267 if (!prodVtx) return;
1268 for (const auto& theMother: prodVtx->particles_in()) {
1269 if (!theMother) continue;
1270 allancestors.insert(theMother);
1271 findParticleAncestors(theMother, allancestors);
1272 }
1273 }
1274
1276
1277 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1278 auto endVtx = thePart->end_vertex();
1279 if (!endVtx) return;
1280 for (const auto& theDaughter: endVtx->particles_out()) {
1281 if (!theDaughter) continue;
1282 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1283 allstabledescendants.insert(theDaughter);
1284 }
1285 findParticleStableDescendants(theDaughter, allstabledescendants);
1286 }
1287 }
1288
1292
1293 template <class T> bool isHardScatteringVertex(T pVert) {
1294 if (pVert == nullptr) return false;
1295 T pV = pVert;
1296 int numOfPartIn(0);
1297 int pdg(0);
1298
1299 do {
1300 pVert = pV;
1301 auto incoming = pVert->particles_in();
1302 numOfPartIn = incoming.size();
1303 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1304 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1305
1306 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1307
1308 if (numOfPartIn == 2) {
1309 auto incoming = pVert->particles_in();
1310 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1311 }
1312 return false;
1313}
1314
1318
1319 template <class T, class U>
1320 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1321 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1322 auto vtx = p->production_vertex();
1323 if (!vtx) return false;
1324 bool fromHad = false;
1325 for ( const auto& parent : particles_in(vtx) ) {
1326 if (!parent) continue;
1327 // should this really go into parton-level territory?
1328 // probably depends where BSM particles are being decayed
1329 fromBSM |= isBSM(parent);
1330 if (!isPhysical(parent)) return false;
1331 fromTau |= isTau(parent);
1332 if (isHadron(parent)&&!isBeam(parent)) {
1333 if (!hadron) hadron = parent; // assumes linear hadron parentage
1334 return true;
1335 }
1336 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1337 }
1338 return fromHad;
1339 }
1340
1343
1344 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1345 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1346 decltype(thePart->end_vertex()) pVert(nullptr);
1347 if (EndVert != nullptr) {
1348 do {
1349 bool samePart = false;
1350 pVert = nullptr;
1351 auto outgoing = EndVert->particles_out();
1352 auto incoming = EndVert->particles_in();
1353 for (const auto& itrDaug: outgoing) {
1354 if (!itrDaug) continue;
1355 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1356 // brem on generator level for tau
1357 (outgoing.size() == 1 && incoming.size() == 1 &&
1359 itrDaug->pdg_id() == thePart->pdg_id()) {
1360 samePart = true;
1361 pVert = itrDaug->end_vertex();
1362 }
1363 }
1364 if (samePart) EndVert = pVert;
1365 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1366 }
1367 return EndVert;
1368 }
1369
1371
1372 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1373 if (!theVert) return {};
1374 decltype(theVert->particles_out()) finalStatePart;
1375 auto outgoing = theVert->particles_out();
1376 for (const auto& thePart: outgoing) {
1377 if (!thePart) continue;
1378 finalStatePart.push_back(thePart);
1379 if (isStable(thePart)) continue;
1380 V pVert = findSimulatedEndVertex(thePart);
1381 if (pVert == theVert) break; // to prevent Sherpa loop
1382 if (pVert != nullptr) {
1383 auto vecPart = findFinalStateParticles<V>(pVert);
1384 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1385 }
1386 }
1387 return finalStatePart;
1388 }
1389
1390}
1391#endif

◆ strangeness() [1/3]

template<>
int MC::strangeness ( const DecodedPID & p)
inline

Definition at line 788 of file HepMCHelpers.h.

809 {
810inline
811auto particles_in (const HepMC::GenVertex* p) {
812 return std::ranges::subrange (p->particles_in_const_begin(),
813 p->particles_in_const_end());
814}
815}
816#endif
817
818namespace MC
819{
820 template <class VTX>
821 auto particles_in (const VTX* p) { return p->particles_in(); }
822 template <class VTX>
823 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
824
825 namespace Pythia8
826 {
828 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
829
830 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
831
832 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
833 }
834
835#include "AtlasPID.h"
836
838 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
839
841 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
842
844 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
845
847 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
848
850 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
851
853 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
854
856 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
857
859 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
860
862 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
863
865 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
866
870 template <class T> inline bool isStableOrSimDecayed(const T& p) {
871 const auto vertex = p->end_vertex();
872 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
873 }
874
876 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
877
879 template <class T> inline bool isSpecialNonInteracting(const T& p) {
880 const int apid = std::abs(p->pdg_id());
881 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
882 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
883 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
884 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
885 return false;
886 }
887
889
890 template <class T> T findMother(T thePart) {
891 auto partOriVert = thePart->production_vertex();
892 if (!partOriVert) return nullptr;
893
894 long partPDG = thePart->pdg_id();
895 long MotherPDG(0);
896
897 auto MothOriVert = partOriVert;
898 MothOriVert = nullptr;
899 T theMoth(nullptr);
900
901 size_t itr = 0;
902 do {
903 if (itr != 0) partOriVert = MothOriVert;
904 for ( const auto& p : particles_in(partOriVert) ) {
905 theMoth = p;
906 if (!theMoth) continue;
907 MotherPDG = theMoth->pdg_id();
908 MothOriVert = theMoth->production_vertex();
909 if (MotherPDG == partPDG) break;
910 }
911 itr++;
912 if (itr > 100) {
913 break;
914 }
915 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
916 MothOriVert != partOriVert);
917 return theMoth;
918 }
919
921
922 template <class C, class T> T findMatching(C TruthContainer, T p) {
923 T ptrPart = nullptr;
924 if (!p) return ptrPart;
925 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
926 for (T truthParticle : *TruthContainer) {
927 if (HepMC::is_sim_descendant(p,truthParticle)) {
928 ptrPart = truthParticle;
929 break;
930 }
931 }
932 }
933 else {
934 for (T truthParticle : TruthContainer) {
935 if (HepMC::is_sim_descendant(p,truthParticle)) {
936 ptrPart = truthParticle;
937 break;
938 }
939 }
940 }
941 return ptrPart;
942 }
944
945 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
946 auto prodVtx = thePart->production_vertex();
947 if (!prodVtx) return;
948 for (const auto& theMother: prodVtx->particles_in()) {
949 if (!theMother) continue;
950 allancestors.insert(theMother);
951 findParticleAncestors(theMother, allancestors);
952 }
953 }
954
956
957 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
958 auto endVtx = thePart->end_vertex();
959 if (!endVtx) return;
960 for (const auto& theDaughter: endVtx->particles_out()) {
961 if (!theDaughter) continue;
962 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
963 allstabledescendants.insert(theDaughter);
964 }
965 findParticleStableDescendants(theDaughter, allstabledescendants);
966 }
967 }
968
972
973 template <class T> bool isHardScatteringVertex(T pVert) {
974 if (pVert == nullptr) return false;
975 T pV = pVert;
976 int numOfPartIn(0);
977 int pdg(0);
978
979 do {
980 pVert = pV;
981 auto incoming = pVert->particles_in();
982 numOfPartIn = incoming.size();
983 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
984 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
985
986 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
987
988 if (numOfPartIn == 2) {
989 auto incoming = pVert->particles_in();
990 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
991 }
992 return false;
993}
994
998
999 template <class T, class U>
1000 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1001 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1002 auto vtx = p->production_vertex();
1003 if (!vtx) return false;
1004 bool fromHad = false;
1005 for ( const auto& parent : particles_in(vtx) ) {
1006 if (!parent) continue;
1007 // should this really go into parton-level territory?
1008 // probably depends where BSM particles are being decayed
1009 fromBSM |= isBSM(parent);
1010 if (!isPhysical(parent)) return false;
1011 fromTau |= isTau(parent);
1012 if (isHadron(parent)&&!isBeam(parent)) {
1013 if (!hadron) hadron = parent; // assumes linear hadron parentage
1014 return true;
1015 }
1016 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1017 }
1018 return fromHad;
1019 }
1020
1023
1024 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1025 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1026 decltype(thePart->end_vertex()) pVert(nullptr);
1027 if (EndVert != nullptr) {
1028 do {
1029 bool samePart = false;
1030 pVert = nullptr;
1031 auto outgoing = EndVert->particles_out();
1032 auto incoming = EndVert->particles_in();
1033 for (const auto& itrDaug: outgoing) {
1034 if (!itrDaug) continue;
1035 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1036 // brem on generator level for tau
1037 (outgoing.size() == 1 && incoming.size() == 1 &&
1039 itrDaug->pdg_id() == thePart->pdg_id()) {
1040 samePart = true;
1041 pVert = itrDaug->end_vertex();
1042 }
1043 }
1044 if (samePart) EndVert = pVert;
1045 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1046 }
1047 return EndVert;
1048 }
1049
1051
1052 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1053 if (!theVert) return {};
1054 decltype(theVert->particles_out()) finalStatePart;
1055 auto outgoing = theVert->particles_out();
1056 for (const auto& thePart: outgoing) {
1057 if (!thePart) continue;
1058 finalStatePart.push_back(thePart);
1059 if (isStable(thePart)) continue;
1060 V pVert = findSimulatedEndVertex(thePart);
1061 if (pVert == theVert) break; // to prevent Sherpa loop
1062 if (pVert != nullptr) {
1063 auto vecPart = findFinalStateParticles<V>(pVert);
1064 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1065 }
1066 }
1067 return finalStatePart;
1068 }
1069
1070}
1071#endif

◆ strangeness() [2/3]

template<>
int MC::strangeness ( const int & p)
inline

Definition at line 822 of file HepMCHelpers.h.

843{
844inline
845auto particles_in (const HepMC::GenVertex* p) {
846 return std::ranges::subrange (p->particles_in_const_begin(),
847 p->particles_in_const_end());
848}
849}
850#endif
851
852namespace MC
853{
854 template <class VTX>
855 auto particles_in (const VTX* p) { return p->particles_in(); }
856 template <class VTX>
857 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
858
859 namespace Pythia8
860 {
862 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
863
864 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
865
866 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
867 }
868
869#include "AtlasPID.h"
870
872 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
873
875 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
876
878 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
879
881 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
882
884 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
885
887 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
888
890 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
891
893 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
894
896 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
897
899 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
900
904 template <class T> inline bool isStableOrSimDecayed(const T& p) {
905 const auto vertex = p->end_vertex();
906 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
907 }
908
910 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
911
913 template <class T> inline bool isSpecialNonInteracting(const T& p) {
914 const int apid = std::abs(p->pdg_id());
915 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
916 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
917 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
918 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
919 return false;
920 }
921
923
924 template <class T> T findMother(T thePart) {
925 auto partOriVert = thePart->production_vertex();
926 if (!partOriVert) return nullptr;
927
928 long partPDG = thePart->pdg_id();
929 long MotherPDG(0);
930
931 auto MothOriVert = partOriVert;
932 MothOriVert = nullptr;
933 T theMoth(nullptr);
934
935 size_t itr = 0;
936 do {
937 if (itr != 0) partOriVert = MothOriVert;
938 for ( const auto& p : particles_in(partOriVert) ) {
939 theMoth = p;
940 if (!theMoth) continue;
941 MotherPDG = theMoth->pdg_id();
942 MothOriVert = theMoth->production_vertex();
943 if (MotherPDG == partPDG) break;
944 }
945 itr++;
946 if (itr > 100) {
947 break;
948 }
949 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
950 MothOriVert != partOriVert);
951 return theMoth;
952 }
953
955
956 template <class C, class T> T findMatching(C TruthContainer, T p) {
957 T ptrPart = nullptr;
958 if (!p) return ptrPart;
959 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
960 for (T truthParticle : *TruthContainer) {
961 if (HepMC::is_sim_descendant(p,truthParticle)) {
962 ptrPart = truthParticle;
963 break;
964 }
965 }
966 }
967 else {
968 for (T truthParticle : TruthContainer) {
969 if (HepMC::is_sim_descendant(p,truthParticle)) {
970 ptrPart = truthParticle;
971 break;
972 }
973 }
974 }
975 return ptrPart;
976 }
978
979 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
980 auto prodVtx = thePart->production_vertex();
981 if (!prodVtx) return;
982 for (const auto& theMother: prodVtx->particles_in()) {
983 if (!theMother) continue;
984 allancestors.insert(theMother);
985 findParticleAncestors(theMother, allancestors);
986 }
987 }
988
990
991 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
992 auto endVtx = thePart->end_vertex();
993 if (!endVtx) return;
994 for (const auto& theDaughter: endVtx->particles_out()) {
995 if (!theDaughter) continue;
996 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
997 allstabledescendants.insert(theDaughter);
998 }
999 findParticleStableDescendants(theDaughter, allstabledescendants);
1000 }
1001 }
1002
1006
1007 template <class T> bool isHardScatteringVertex(T pVert) {
1008 if (pVert == nullptr) return false;
1009 T pV = pVert;
1010 int numOfPartIn(0);
1011 int pdg(0);
1012
1013 do {
1014 pVert = pV;
1015 auto incoming = pVert->particles_in();
1016 numOfPartIn = incoming.size();
1017 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1018 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1019
1020 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1021
1022 if (numOfPartIn == 2) {
1023 auto incoming = pVert->particles_in();
1024 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1025 }
1026 return false;
1027}
1028
1032
1033 template <class T, class U>
1034 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1035 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1036 auto vtx = p->production_vertex();
1037 if (!vtx) return false;
1038 bool fromHad = false;
1039 for ( const auto& parent : particles_in(vtx) ) {
1040 if (!parent) continue;
1041 // should this really go into parton-level territory?
1042 // probably depends where BSM particles are being decayed
1043 fromBSM |= isBSM(parent);
1044 if (!isPhysical(parent)) return false;
1045 fromTau |= isTau(parent);
1046 if (isHadron(parent)&&!isBeam(parent)) {
1047 if (!hadron) hadron = parent; // assumes linear hadron parentage
1048 return true;
1049 }
1050 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1051 }
1052 return fromHad;
1053 }
1054
1057
1058 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1059 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1060 decltype(thePart->end_vertex()) pVert(nullptr);
1061 if (EndVert != nullptr) {
1062 do {
1063 bool samePart = false;
1064 pVert = nullptr;
1065 auto outgoing = EndVert->particles_out();
1066 auto incoming = EndVert->particles_in();
1067 for (const auto& itrDaug: outgoing) {
1068 if (!itrDaug) continue;
1069 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1070 // brem on generator level for tau
1071 (outgoing.size() == 1 && incoming.size() == 1 &&
1073 itrDaug->pdg_id() == thePart->pdg_id()) {
1074 samePart = true;
1075 pVert = itrDaug->end_vertex();
1076 }
1077 }
1078 if (samePart) EndVert = pVert;
1079 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1080 }
1081 return EndVert;
1082 }
1083
1085
1086 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1087 if (!theVert) return {};
1088 decltype(theVert->particles_out()) finalStatePart;
1089 auto outgoing = theVert->particles_out();
1090 for (const auto& thePart: outgoing) {
1091 if (!thePart) continue;
1092 finalStatePart.push_back(thePart);
1093 if (isStable(thePart)) continue;
1094 V pVert = findSimulatedEndVertex(thePart);
1095 if (pVert == theVert) break; // to prevent Sherpa loop
1096 if (pVert != nullptr) {
1097 auto vecPart = findFinalStateParticles<V>(pVert);
1098 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1099 }
1100 }
1101 return finalStatePart;
1102 }
1103
1104}
1105#endif

◆ strangeness() [3/3]

template<class T>
int MC::strangeness ( const T & p)
inline

Definition at line 787 of file HepMCHelpers.h.

808{
809inline
810auto particles_in (const HepMC::GenVertex* p) {
811 return std::ranges::subrange (p->particles_in_const_begin(),
812 p->particles_in_const_end());
813}
814}
815#endif
816
817namespace MC
818{
819 template <class VTX>
820 auto particles_in (const VTX* p) { return p->particles_in(); }
821 template <class VTX>
822 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
823
824 namespace Pythia8
825 {
827 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
828
829 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
830
831 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
832 }
833
834#include "AtlasPID.h"
835
837 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
838
840 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
841
843 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
844
846 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
847
849 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
850
852 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
853
855 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
856
858 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
859
861 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
862
864 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
865
869 template <class T> inline bool isStableOrSimDecayed(const T& p) {
870 const auto vertex = p->end_vertex();
871 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
872 }
873
875 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
876
878 template <class T> inline bool isSpecialNonInteracting(const T& p) {
879 const int apid = std::abs(p->pdg_id());
880 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
881 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
882 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
883 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
884 return false;
885 }
886
888
889 template <class T> T findMother(T thePart) {
890 auto partOriVert = thePart->production_vertex();
891 if (!partOriVert) return nullptr;
892
893 long partPDG = thePart->pdg_id();
894 long MotherPDG(0);
895
896 auto MothOriVert = partOriVert;
897 MothOriVert = nullptr;
898 T theMoth(nullptr);
899
900 size_t itr = 0;
901 do {
902 if (itr != 0) partOriVert = MothOriVert;
903 for ( const auto& p : particles_in(partOriVert) ) {
904 theMoth = p;
905 if (!theMoth) continue;
906 MotherPDG = theMoth->pdg_id();
907 MothOriVert = theMoth->production_vertex();
908 if (MotherPDG == partPDG) break;
909 }
910 itr++;
911 if (itr > 100) {
912 break;
913 }
914 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
915 MothOriVert != partOriVert);
916 return theMoth;
917 }
918
920
921 template <class C, class T> T findMatching(C TruthContainer, T p) {
922 T ptrPart = nullptr;
923 if (!p) return ptrPart;
924 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
925 for (T truthParticle : *TruthContainer) {
926 if (HepMC::is_sim_descendant(p,truthParticle)) {
927 ptrPart = truthParticle;
928 break;
929 }
930 }
931 }
932 else {
933 for (T truthParticle : TruthContainer) {
934 if (HepMC::is_sim_descendant(p,truthParticle)) {
935 ptrPart = truthParticle;
936 break;
937 }
938 }
939 }
940 return ptrPart;
941 }
943
944 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
945 auto prodVtx = thePart->production_vertex();
946 if (!prodVtx) return;
947 for (const auto& theMother: prodVtx->particles_in()) {
948 if (!theMother) continue;
949 allancestors.insert(theMother);
950 findParticleAncestors(theMother, allancestors);
951 }
952 }
953
955
956 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
957 auto endVtx = thePart->end_vertex();
958 if (!endVtx) return;
959 for (const auto& theDaughter: endVtx->particles_out()) {
960 if (!theDaughter) continue;
961 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
962 allstabledescendants.insert(theDaughter);
963 }
964 findParticleStableDescendants(theDaughter, allstabledescendants);
965 }
966 }
967
971
972 template <class T> bool isHardScatteringVertex(T pVert) {
973 if (pVert == nullptr) return false;
974 T pV = pVert;
975 int numOfPartIn(0);
976 int pdg(0);
977
978 do {
979 pVert = pV;
980 auto incoming = pVert->particles_in();
981 numOfPartIn = incoming.size();
982 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
983 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
984
985 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
986
987 if (numOfPartIn == 2) {
988 auto incoming = pVert->particles_in();
989 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
990 }
991 return false;
992}
993
997
998 template <class T, class U>
999 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1000 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1001 auto vtx = p->production_vertex();
1002 if (!vtx) return false;
1003 bool fromHad = false;
1004 for ( const auto& parent : particles_in(vtx) ) {
1005 if (!parent) continue;
1006 // should this really go into parton-level territory?
1007 // probably depends where BSM particles are being decayed
1008 fromBSM |= isBSM(parent);
1009 if (!isPhysical(parent)) return false;
1010 fromTau |= isTau(parent);
1011 if (isHadron(parent)&&!isBeam(parent)) {
1012 if (!hadron) hadron = parent; // assumes linear hadron parentage
1013 return true;
1014 }
1015 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1016 }
1017 return fromHad;
1018 }
1019
1022
1023 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1024 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1025 decltype(thePart->end_vertex()) pVert(nullptr);
1026 if (EndVert != nullptr) {
1027 do {
1028 bool samePart = false;
1029 pVert = nullptr;
1030 auto outgoing = EndVert->particles_out();
1031 auto incoming = EndVert->particles_in();
1032 for (const auto& itrDaug: outgoing) {
1033 if (!itrDaug) continue;
1034 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1035 // brem on generator level for tau
1036 (outgoing.size() == 1 && incoming.size() == 1 &&
1038 itrDaug->pdg_id() == thePart->pdg_id()) {
1039 samePart = true;
1040 pVert = itrDaug->end_vertex();
1041 }
1042 }
1043 if (samePart) EndVert = pVert;
1044 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1045 }
1046 return EndVert;
1047 }
1048
1050
1051 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1052 if (!theVert) return {};
1053 decltype(theVert->particles_out()) finalStatePart;
1054 auto outgoing = theVert->particles_out();
1055 for (const auto& thePart: outgoing) {
1056 if (!thePart) continue;
1057 finalStatePart.push_back(thePart);
1058 if (isStable(thePart)) continue;
1059 V pVert = findSimulatedEndVertex(thePart);
1060 if (pVert == theVert) break; // to prevent Sherpa loop
1061 if (pVert != nullptr) {
1062 auto vecPart = findFinalStateParticles<V>(pVert);
1063 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1064 }
1065 }
1066 return finalStatePart;
1067 }
1068
1069}
1070#endif

◆ threeCharge()

template<class T>
double MC::threeCharge ( const T & p)
inline

Definition at line 1004 of file HepMCHelpers.h.

1025{
1026inline
1027auto particles_in (const HepMC::GenVertex* p) {
1028 return std::ranges::subrange (p->particles_in_const_begin(),
1029 p->particles_in_const_end());
1030}
1031}
1032#endif
1033
1034namespace MC
1035{
1036 template <class VTX>
1037 auto particles_in (const VTX* p) { return p->particles_in(); }
1038 template <class VTX>
1039 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
1040
1041 namespace Pythia8
1042 {
1044 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
1045
1046 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
1047
1048 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
1049 }
1050
1051#include "AtlasPID.h"
1052
1054 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
1055
1057 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
1058
1060 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
1061
1063 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
1064
1066 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
1067
1069 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
1070
1072 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
1073
1075 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
1076
1078 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
1079
1081 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
1082
1086 template <class T> inline bool isStableOrSimDecayed(const T& p) {
1087 const auto vertex = p->end_vertex();
1088 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
1089 }
1090
1092 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
1093
1095 template <class T> inline bool isSpecialNonInteracting(const T& p) {
1096 const int apid = std::abs(p->pdg_id());
1097 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
1098 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
1099 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
1100 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
1101 return false;
1102 }
1103
1105
1106 template <class T> T findMother(T thePart) {
1107 auto partOriVert = thePart->production_vertex();
1108 if (!partOriVert) return nullptr;
1109
1110 long partPDG = thePart->pdg_id();
1111 long MotherPDG(0);
1112
1113 auto MothOriVert = partOriVert;
1114 MothOriVert = nullptr;
1115 T theMoth(nullptr);
1116
1117 size_t itr = 0;
1118 do {
1119 if (itr != 0) partOriVert = MothOriVert;
1120 for ( const auto& p : particles_in(partOriVert) ) {
1121 theMoth = p;
1122 if (!theMoth) continue;
1123 MotherPDG = theMoth->pdg_id();
1124 MothOriVert = theMoth->production_vertex();
1125 if (MotherPDG == partPDG) break;
1126 }
1127 itr++;
1128 if (itr > 100) {
1129 break;
1130 }
1131 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
1132 MothOriVert != partOriVert);
1133 return theMoth;
1134 }
1135
1137
1138 template <class C, class T> T findMatching(C TruthContainer, T p) {
1139 T ptrPart = nullptr;
1140 if (!p) return ptrPart;
1141 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
1142 for (T truthParticle : *TruthContainer) {
1143 if (HepMC::is_sim_descendant(p,truthParticle)) {
1144 ptrPart = truthParticle;
1145 break;
1146 }
1147 }
1148 }
1149 else {
1150 for (T truthParticle : TruthContainer) {
1151 if (HepMC::is_sim_descendant(p,truthParticle)) {
1152 ptrPart = truthParticle;
1153 break;
1154 }
1155 }
1156 }
1157 return ptrPart;
1158 }
1160
1161 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
1162 auto prodVtx = thePart->production_vertex();
1163 if (!prodVtx) return;
1164 for (const auto& theMother: prodVtx->particles_in()) {
1165 if (!theMother) continue;
1166 allancestors.insert(theMother);
1167 findParticleAncestors(theMother, allancestors);
1168 }
1169 }
1170
1172
1173 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
1174 auto endVtx = thePart->end_vertex();
1175 if (!endVtx) return;
1176 for (const auto& theDaughter: endVtx->particles_out()) {
1177 if (!theDaughter) continue;
1178 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
1179 allstabledescendants.insert(theDaughter);
1180 }
1181 findParticleStableDescendants(theDaughter, allstabledescendants);
1182 }
1183 }
1184
1188
1189 template <class T> bool isHardScatteringVertex(T pVert) {
1190 if (pVert == nullptr) return false;
1191 T pV = pVert;
1192 int numOfPartIn(0);
1193 int pdg(0);
1194
1195 do {
1196 pVert = pV;
1197 auto incoming = pVert->particles_in();
1198 numOfPartIn = incoming.size();
1199 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
1200 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
1201
1202 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
1203
1204 if (numOfPartIn == 2) {
1205 auto incoming = pVert->particles_in();
1206 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
1207 }
1208 return false;
1209}
1210
1214
1215 template <class T, class U>
1216 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
1217 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
1218 auto vtx = p->production_vertex();
1219 if (!vtx) return false;
1220 bool fromHad = false;
1221 for ( const auto& parent : particles_in(vtx) ) {
1222 if (!parent) continue;
1223 // should this really go into parton-level territory?
1224 // probably depends where BSM particles are being decayed
1225 fromBSM |= isBSM(parent);
1226 if (!isPhysical(parent)) return false;
1227 fromTau |= isTau(parent);
1228 if (isHadron(parent)&&!isBeam(parent)) {
1229 if (!hadron) hadron = parent; // assumes linear hadron parentage
1230 return true;
1231 }
1232 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1233 }
1234 return fromHad;
1235 }
1236
1239
1240 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1241 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1242 decltype(thePart->end_vertex()) pVert(nullptr);
1243 if (EndVert != nullptr) {
1244 do {
1245 bool samePart = false;
1246 pVert = nullptr;
1247 auto outgoing = EndVert->particles_out();
1248 auto incoming = EndVert->particles_in();
1249 for (const auto& itrDaug: outgoing) {
1250 if (!itrDaug) continue;
1251 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1252 // brem on generator level for tau
1253 (outgoing.size() == 1 && incoming.size() == 1 &&
1255 itrDaug->pdg_id() == thePart->pdg_id()) {
1256 samePart = true;
1257 pVert = itrDaug->end_vertex();
1258 }
1259 }
1260 if (samePart) EndVert = pVert;
1261 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1262 }
1263 return EndVert;
1264 }
1265
1267
1268 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1269 if (!theVert) return {};
1270 decltype(theVert->particles_out()) finalStatePart;
1271 auto outgoing = theVert->particles_out();
1272 for (const auto& thePart: outgoing) {
1273 if (!thePart) continue;
1274 finalStatePart.push_back(thePart);
1275 if (isStable(thePart)) continue;
1276 V pVert = findSimulatedEndVertex(thePart);
1277 if (pVert == theVert) break; // to prevent Sherpa loop
1278 if (pVert != nullptr) {
1279 auto vecPart = findFinalStateParticles<V>(pVert);
1280 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1281 }
1282 }
1283 return finalStatePart;
1284 }
1285
1286}
1287#endif

Variable Documentation

◆ B0

const int MC::B0 = 511
static

Definition at line 123 of file HepMCHelpers.h.

◆ BCPLUS

const int MC::BCPLUS = 541
static

Definition at line 124 of file HepMCHelpers.h.

◆ BPRIME

const int MC::BPRIME = 7
static

Definition at line 71 of file HepMCHelpers.h.

◆ BQUARK

const int MC::BQUARK = 5
static

Definition at line 69 of file HepMCHelpers.h.

◆ COMPOSITEGLUON

const int MC::COMPOSITEGLUON = 9
static

Definition at line 87 of file HepMCHelpers.h.

◆ CQUARK

const int MC::CQUARK = 4
static

Definition at line 68 of file HepMCHelpers.h.

◆ D0

const int MC::D0 = 421
static

Definition at line 120 of file HepMCHelpers.h.

◆ DARKPHOTON

const int MC::DARKPHOTON = 60000
static

PDG Ids for Mavtop madgraph UFO model found under DarkX.

The mavtop is a vector-like top partner with coupling to a dark photon. Theory paper: https://arxiv.org/abs/1904.05893 Pheno paper: https://arxiv.org/pdf/2112.08425

Definition at line 107 of file HepMCHelpers.h.

◆ double_spin

const std::array<int,TABLESIZE> MC::double_spin
static
Initial value:
= {
+0, +1, +1, +1, +1, +1, +1, +1, +1, +0,
+0, +1, +1, +1, +1, +1, +1, +1, +1, +0,
+2, +2, +2, +2, +2, +0, +0, +0, +0, +0,
+0, +0, +2, +2, +2, +0, +0, +0, +0, +4,
+0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
+0, +0, +1, +2, +0, +2, +0, +1, +2, +0,
+0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
+0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
+0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
+0, +0, +0, +0, +0, +0, +0, +0, +0, +0
}

Definition at line 51 of file HepMCHelpers.h.

52
54 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
55
57 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
58
60 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
61
bool isSUSY(const T &p)
Definition AtlasPID.h:623
bool isMuon(const T &p)
Definition AtlasPID.h:205

◆ DPLUS

const int MC::DPLUS = 411
static

Definition at line 118 of file HepMCHelpers.h.

◆ DQUARK

const int MC::DQUARK = 1
static

Definition at line 65 of file HepMCHelpers.h.

◆ DSPLUS

const int MC::DSPLUS = 431
static

Definition at line 121 of file HepMCHelpers.h.

◆ DSTAR

const int MC::DSTAR = 413
static

Definition at line 119 of file HepMCHelpers.h.

◆ ELECTRON

const int MC::ELECTRON = 11
static

Definition at line 75 of file HepMCHelpers.h.

◆ GEANTINO0

const int MC::GEANTINO0 = 999
static

Definition at line 160 of file HepMCHelpers.h.

◆ GEANTINOPLUS

const int MC::GEANTINOPLUS = 998
static

PDG rule 10: Codes 81–100 are reserved for generator-specific pseudoparticles and concepts.

Codes 901–930, 1901–1930, 2901–2930, and 3901–3930 are for additional components of Standard Modelparton distribution functions, where the latter three ranges are intended to distinguish left/right/ longitudinal components. Codes 998 and 999 are reserved for GEANT tracking purposes.

Definition at line 159 of file HepMCHelpers.h.

◆ GLUON

const int MC::GLUON = 21
static

Definition at line 85 of file HepMCHelpers.h.

◆ GRAVITON

const int MC::GRAVITON = 39
static

Definition at line 99 of file HepMCHelpers.h.

◆ HELIUM

const int MC::HELIUM = 1000020040
static

Definition at line 145 of file HepMCHelpers.h.

◆ HIGGS2

const int MC::HIGGS2 = 35
static

Definition at line 95 of file HepMCHelpers.h.

◆ HIGGS3

const int MC::HIGGS3 = 36
static

Definition at line 96 of file HepMCHelpers.h.

◆ HIGGS4

const int MC::HIGGS4 = 40
static

Definition at line 100 of file HepMCHelpers.h.

◆ HIGGSBOSON

const int MC::HIGGSBOSON = 25
static

Definition at line 91 of file HepMCHelpers.h.

◆ HIGGSPLUS

const int MC::HIGGSPLUS = 37
static

Definition at line 97 of file HepMCHelpers.h.

◆ HIGGSPLUSPLUS

const int MC::HIGGSPLUSPLUS = 38
static

Definition at line 98 of file HepMCHelpers.h.

◆ is_strange

const std::array<int,10> MC::is_strange
static
Initial value:
= {
+0, +0, +0, -1, +0, +0, +0, +0, +0, +0 }

Definition at line 785 of file HepMCHelpers.h.

806 {
807inline
808auto particles_in (const HepMC::GenVertex* p) {
809 return std::ranges::subrange (p->particles_in_const_begin(),
810 p->particles_in_const_end());
811}
812}
813#endif
814
815namespace MC
816{
817 template <class VTX>
818 auto particles_in (const VTX* p) { return p->particles_in(); }
819 template <class VTX>
820 auto particles_in (const std::shared_ptr<VTX>& p) { return p->particles_in(); }
821
822 namespace Pythia8
823 {
825 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
826
827 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
828
829 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
830 }
831
832#include "AtlasPID.h"
833
835 template <class T> inline bool isInteracting(const T& p) { return isStrongInteracting<T>(p) || isEMInteracting<T>(p) || isGeantino<T>(p); }
836
838 template <class T> inline bool isChargedNonShowering(const T& p) { return (isMuon<T>(p) || isSUSY<T>(p)); }
839
841 template <class T> inline bool isBeam(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 4;}
842
844 template <class T> inline bool isDecayed(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 2;}
845
847 template <class T> inline bool isStable(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1;}
848
850 template <class T> inline bool isFinalState(const T& p) { return HepMC::status(p)%HepMC::SIM_STATUS_THRESHOLD == 1 && !p->end_vertex();}
851
853 template <class T> inline bool isPhysical(const T& p) { return isStable<T>(p) || isDecayed<T>(p); }
854
856 template <class T> inline bool isGenStable(const T& p) { return isStable<T>(p) && !HepMC::is_simulation_particle<T>(p);}
857
859 template <class T> inline bool isSimStable(const T& p) { return isStable<T>(p) && !p->end_vertex() && HepMC::is_simulation_particle<T>(p);}
860
862 template <class T> inline bool isSimInteracting(const T& p) { return isGenStable<T>(p) && isInteracting<T>(p);}
863
867 template <class T> inline bool isStableOrSimDecayed(const T& p) {
868 const auto vertex = p->end_vertex();
869 return ( isStable<T>(p) || (isDecayed<T>(p) && (!vertex || HepMC::is_simulation_vertex(vertex))));
870 }
871
873 template <class T> inline bool isZeroEnergyPhoton(const T& p) { return isPhoton<T>(p) && p->e() == 0;}
874
876 template <class T> inline bool isSpecialNonInteracting(const T& p) {
877 const int apid = std::abs(p->pdg_id());
878 if (apid == NU_E || apid == NU_MU || apid == NU_TAU) return true; //< neutrinos
879 if (apid == 1000022 || apid == 1000024 || apid == 5100022) return true; // SUSY & KK photon and Z partners
880 if (apid == GRAVITON || apid == 1000039 || apid == 5000039) return true; //< gravitons: standard, SUSY and KK
881 if (apid == 9000001 || apid == 9000002 || apid == 9000003 || apid == 9000004 || apid == 9000005 || apid == 9000006) return true; //< exotic particles from monotop model
882 return false;
883 }
884
886
887 template <class T> T findMother(T thePart) {
888 auto partOriVert = thePart->production_vertex();
889 if (!partOriVert) return nullptr;
890
891 long partPDG = thePart->pdg_id();
892 long MotherPDG(0);
893
894 auto MothOriVert = partOriVert;
895 MothOriVert = nullptr;
896 T theMoth(nullptr);
897
898 size_t itr = 0;
899 do {
900 if (itr != 0) partOriVert = MothOriVert;
901 for ( const auto& p : particles_in(partOriVert) ) {
902 theMoth = p;
903 if (!theMoth) continue;
904 MotherPDG = theMoth->pdg_id();
905 MothOriVert = theMoth->production_vertex();
906 if (MotherPDG == partPDG) break;
907 }
908 itr++;
909 if (itr > 100) {
910 break;
911 }
912 } while (MothOriVert != nullptr && MotherPDG == partPDG && !HepMC::is_simulation_particle(thePart) &&
913 MothOriVert != partOriVert);
914 return theMoth;
915 }
916
918
919 template <class C, class T> T findMatching(C TruthContainer, T p) {
920 T ptrPart = nullptr;
921 if (!p) return ptrPart;
922 if constexpr (std::is_pointer_v<C> || HepMC::is_smart_ptr_v<C>){ //C is ptr
923 for (T truthParticle : *TruthContainer) {
924 if (HepMC::is_sim_descendant(p,truthParticle)) {
925 ptrPart = truthParticle;
926 break;
927 }
928 }
929 }
930 else {
931 for (T truthParticle : TruthContainer) {
932 if (HepMC::is_sim_descendant(p,truthParticle)) {
933 ptrPart = truthParticle;
934 break;
935 }
936 }
937 }
938 return ptrPart;
939 }
941
942 template <class T> void findParticleAncestors(T thePart, std::set<T>& allancestors) {
943 auto prodVtx = thePart->production_vertex();
944 if (!prodVtx) return;
945 for (const auto& theMother: prodVtx->particles_in()) {
946 if (!theMother) continue;
947 allancestors.insert(theMother);
948 findParticleAncestors(theMother, allancestors);
949 }
950 }
951
953
954 template <class T> void findParticleStableDescendants(T thePart, std::set<T>& allstabledescendants) {
955 auto endVtx = thePart->end_vertex();
956 if (!endVtx) return;
957 for (const auto& theDaughter: endVtx->particles_out()) {
958 if (!theDaughter) continue;
959 if (isStable(theDaughter) && !HepMC::is_simulation_particle(theDaughter)) {
960 allstabledescendants.insert(theDaughter);
961 }
962 findParticleStableDescendants(theDaughter, allstabledescendants);
963 }
964 }
965
969
970 template <class T> bool isHardScatteringVertex(T pVert) {
971 if (pVert == nullptr) return false;
972 T pV = pVert;
973 int numOfPartIn(0);
974 int pdg(0);
975
976 do {
977 pVert = pV;
978 auto incoming = pVert->particles_in();
979 numOfPartIn = incoming.size();
980 pdg = numOfPartIn && incoming.front() != nullptr ? incoming.front()->pdg_id() : 0;
981 pV = numOfPartIn && incoming.front() != nullptr ? incoming.front()->production_vertex() : nullptr;
982
983 } while (numOfPartIn == 1 && (std::abs(pdg) < 81 || std::abs(pdg) > 100) && pV != nullptr);
984
985 if (numOfPartIn == 2) {
986 auto incoming = pVert->particles_in();
987 if (incoming.at(0) && incoming.at(1) && (std::abs(incoming.at(0)->pdg_id()) < 7 || incoming.at(0)->pdg_id() == 21) && (std::abs(incoming.at(1)->pdg_id()) < 7 || incoming.at(1)->pdg_id() == 21)) return true;
988 }
989 return false;
990}
991
995
996 template <class T, class U>
997 bool isFromHadron(T p, U hadron, bool &fromTau, bool &fromBSM) {
998 if (isHadron(p)&&!isBeam(p)) return true; // trivial case
999 auto vtx = p->production_vertex();
1000 if (!vtx) return false;
1001 bool fromHad = false;
1002 for ( const auto& parent : particles_in(vtx) ) {
1003 if (!parent) continue;
1004 // should this really go into parton-level territory?
1005 // probably depends where BSM particles are being decayed
1006 fromBSM |= isBSM(parent);
1007 if (!isPhysical(parent)) return false;
1008 fromTau |= isTau(parent);
1009 if (isHadron(parent)&&!isBeam(parent)) {
1010 if (!hadron) hadron = parent; // assumes linear hadron parentage
1011 return true;
1012 }
1013 fromHad |= isFromHadron(parent, hadron, fromTau, fromBSM);
1014 }
1015 return fromHad;
1016 }
1017
1020
1021 template <class T> auto findSimulatedEndVertex(T thePart) -> decltype(thePart->end_vertex()) {
1022 decltype(thePart->end_vertex()) EndVert = thePart->end_vertex();
1023 decltype(thePart->end_vertex()) pVert(nullptr);
1024 if (EndVert != nullptr) {
1025 do {
1026 bool samePart = false;
1027 pVert = nullptr;
1028 auto outgoing = EndVert->particles_out();
1029 auto incoming = EndVert->particles_in();
1030 for (const auto& itrDaug: outgoing) {
1031 if (!itrDaug) continue;
1032 if ((( HepMC::is_same_generator_particle(itrDaug,thePart)) ||
1033 // brem on generator level for tau
1034 (outgoing.size() == 1 && incoming.size() == 1 &&
1036 itrDaug->pdg_id() == thePart->pdg_id()) {
1037 samePart = true;
1038 pVert = itrDaug->end_vertex();
1039 }
1040 }
1041 if (samePart) EndVert = pVert;
1042 } while (pVert != nullptr && pVert != EndVert); // pVert!=EndVert to prevent Sherpa loop
1043 }
1044 return EndVert;
1045 }
1046
1048
1049 template <class V> auto findFinalStateParticles(V theVert) -> decltype(theVert->particles_out()) {
1050 if (!theVert) return {};
1051 decltype(theVert->particles_out()) finalStatePart;
1052 auto outgoing = theVert->particles_out();
1053 for (const auto& thePart: outgoing) {
1054 if (!thePart) continue;
1055 finalStatePart.push_back(thePart);
1056 if (isStable(thePart)) continue;
1057 V pVert = findSimulatedEndVertex(thePart);
1058 if (pVert == theVert) break; // to prevent Sherpa loop
1059 if (pVert != nullptr) {
1060 auto vecPart = findFinalStateParticles<V>(pVert);
1061 finalStatePart.insert(finalStatePart.end(),vecPart.begin(),vecPart.end());
1062 }
1063 }
1064 return finalStatePart;
1065 }
1066
1067}
1068#endif

◆ JPSI

const int MC::JPSI = 443
static

Definition at line 122 of file HepMCHelpers.h.

◆ K0

const int MC::K0 = 311
static

Definition at line 116 of file HepMCHelpers.h.

◆ K0L

const int MC::K0L = 130
static

Definition at line 113 of file HepMCHelpers.h.

◆ K0S

const int MC::K0S = 310
static

Definition at line 115 of file HepMCHelpers.h.

◆ KPLUS

const int MC::KPLUS = 321
static

Definition at line 117 of file HepMCHelpers.h.

◆ LAMBDA0

const int MC::LAMBDA0 = 3122
static

Definition at line 127 of file HepMCHelpers.h.

◆ LAMBDAB0

const int MC::LAMBDAB0 = 5122
static

Definition at line 129 of file HepMCHelpers.h.

◆ LAMBDACPLUS

const int MC::LAMBDACPLUS = 4122
static

Definition at line 128 of file HepMCHelpers.h.

◆ LEAD

const int MC::LEAD = 1000822080
static

Definition at line 142 of file HepMCHelpers.h.

◆ LEPTOQUARK

const int MC::LEPTOQUARK = 42
static

Definition at line 101 of file HepMCHelpers.h.

◆ LPRIME

const int MC::LPRIME = 17
static

Definition at line 82 of file HepMCHelpers.h.

◆ MAVTOP

const int MC::MAVTOP = 60001
static

Definition at line 108 of file HepMCHelpers.h.

◆ MUON

const int MC::MUON = 13
static

Definition at line 78 of file HepMCHelpers.h.

◆ NEON

const int MC::NEON = 1000100200
static

Definition at line 144 of file HepMCHelpers.h.

◆ NEUTRON

const int MC::NEUTRON = 2112
static

Definition at line 126 of file HepMCHelpers.h.

◆ NU_E

const int MC::NU_E = 12
static

Definition at line 77 of file HepMCHelpers.h.

◆ NU_MU

const int MC::NU_MU = 14
static

Definition at line 79 of file HepMCHelpers.h.

◆ NU_TAU

const int MC::NU_TAU = 16
static

Definition at line 81 of file HepMCHelpers.h.

◆ NUPRIME

const int MC::NUPRIME = 18
static

Definition at line 83 of file HepMCHelpers.h.

◆ ODDERON

const int MC::ODDERON = 9990
static

Definition at line 151 of file HepMCHelpers.h.

◆ OXYGEN

const int MC::OXYGEN = 1000080160
static

Definition at line 143 of file HepMCHelpers.h.

◆ PHOTON

const int MC::PHOTON = 22
static

Definition at line 88 of file HepMCHelpers.h.

◆ PI0

const int MC::PI0 = 111
static

Definition at line 112 of file HepMCHelpers.h.

◆ PIMINUS

const int MC::PIMINUS = -PIPLUS
static

Definition at line 111 of file HepMCHelpers.h.

◆ PIPLUS

const int MC::PIPLUS = 211
static

Definition at line 110 of file HepMCHelpers.h.

◆ POMERON

const int MC::POMERON = 990
static

PDG rule 8: The pomeron and odderon trajectories and a generic reggeon trajectory of states in QCD areassigned codes 990, 9990, and 110 respectively.

Definition at line 150 of file HepMCHelpers.h.

◆ POSITRON

const int MC::POSITRON = -ELECTRON
static

Definition at line 76 of file HepMCHelpers.h.

◆ PROTON

const int MC::PROTON = 2212
static

Definition at line 125 of file HepMCHelpers.h.

◆ PSI2S

const int MC::PSI2S = 20443
static

Definition at line 130 of file HepMCHelpers.h.

◆ QUARK_LIMIT

const int MC::QUARK_LIMIT = BPRIME
static

Definition at line 73 of file HepMCHelpers.h.

◆ REGGEON

const int MC::REGGEON = 110
static

Definition at line 152 of file HepMCHelpers.h.

◆ RH_NU_E

const int MC::RH_NU_E = 9900012
static

PDG Rule 12: Generator defined PDG ID values for right handed neutrinos and corresponding W+ boson from a Left-Right symmetric Standard Model extension.

(Defined for some MadGraph+Pythia8 samples and referenced in MCTruthClassifierGen.cxx)

Definition at line 137 of file HepMCHelpers.h.

◆ RH_NU_MU

const int MC::RH_NU_MU = 9900014
static

Definition at line 138 of file HepMCHelpers.h.

◆ RH_NU_TAU

const int MC::RH_NU_TAU = 9900016
static

Definition at line 139 of file HepMCHelpers.h.

◆ SQUARK

const int MC::SQUARK = 3
static

Definition at line 67 of file HepMCHelpers.h.

◆ TABLESIZE

const int MC::TABLESIZE = 100
static

Definition at line 35 of file HepMCHelpers.h.

◆ TAU

const int MC::TAU = 15
static

Definition at line 80 of file HepMCHelpers.h.

◆ TPRIME

const int MC::TPRIME = 8
static

Definition at line 72 of file HepMCHelpers.h.

◆ TQUARK

const int MC::TQUARK = 6
static

Definition at line 70 of file HepMCHelpers.h.

◆ triple_charge

const std::array<int,TABLESIZE> MC::triple_charge
static
Initial value:
= {
+0, -1, +2, -1, +2, -1, +2, -1, +2, +0,
+0, -3, +0, -3, +0, -3, +0, -3, +0, +0,
+0, +0, +0, +0, +3, +0, +0, +0, +0, +0,
+0, +0, +0, +0, +3, +0, +0, +3, +6, +0,
+0, +0, -1, +0, +0, +0, +0, +0, +0, +0,
+0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
+0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
+0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
+0, +0, +0, +0, +0, +0, +0, +0, +0, +0,
+0, +0, +0, +0, +0, +0, +0, +0, +0, +0
}

Definition at line 36 of file HepMCHelpers.h.

36 { return p->particles_in(); }
37
38 namespace Pythia8
39 {
41 template <class T> inline bool isConditionA(const T& p) { return p->status() == 62 || p->status() == 52 || p->status() == 21 || p->status() == 22;}
42
43 template <class T> inline bool isConditionB(const T& p) { return p->status() == 23;}
44
45 template <class T> inline bool isConditionC(const T& p) { return p->status() > 30 && p->status() < 40;}
46 }
47
Author: James Monk (jmonk@cern.ch)

◆ UQUARK

const int MC::UQUARK = 2
static

Definition at line 66 of file HepMCHelpers.h.

◆ WBOSON_LRSM

const int MC::WBOSON_LRSM = 9900024
static

Definition at line 140 of file HepMCHelpers.h.

◆ WPLUSBOSON

const int MC::WPLUSBOSON = 24
static

Definition at line 90 of file HepMCHelpers.h.

◆ WPLUSPRIME

const int MC::WPLUSPRIME = 34
static

Definition at line 94 of file HepMCHelpers.h.

◆ Z0BOSON

const int MC::Z0BOSON = 23
static

Definition at line 89 of file HepMCHelpers.h.

◆ ZDBLPRIME

const int MC::ZDBLPRIME = 33
static

Definition at line 93 of file HepMCHelpers.h.

◆ ZPRIME

const int MC::ZPRIME = 32
static

Definition at line 92 of file HepMCHelpers.h.