ATLAS Offline Software
Loading...
Searching...
No Matches
MCTruthClassifier Class Reference

#include <MCTruthClassifier.h>

Inheritance diagram for MCTruthClassifier:
Collaboration diagram for MCTruthClassifier:

Public Member Functions

 MCTruthClassifier (const std::string &type)
virtual ~MCTruthClassifier ()=default
virtual StatusCode initialize () override
 Dummy implementation of the initialisation function.
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleTruthClassifier (const xAOD::TruthParticle *, MCTruthPartClassifier::Info *info=nullptr) const override final
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleHepMCTruthClassifier (const HepMcParticleLink &theLink, MCTruthPartClassifier::Info *info=nullptr) const override final
virtual const xAOD::TruthParticlegetGenPart (const xAOD::TrackParticle *, MCTruthPartClassifier::Info *info=nullptr) const override final
virtual const xAOD::TruthParticleegammaClusMatch (const xAOD::CaloCluster *, bool, MCTruthPartClassifier::Info *info) const override final
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleTruthClassifier (const xAOD::TrackParticle *, MCTruthPartClassifier::Info *info=nullptr) const override final
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleTruthClassifier (const xAOD::Electron *, MCTruthPartClassifier::Info *info=nullptr) const override final
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleTruthClassifier (const xAOD::Photon *, MCTruthPartClassifier::Info *info=nullptr) const override final
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleTruthClassifier (const xAOD::Muon *, MCTruthPartClassifier::Info *info=nullptr) const override final
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleTruthClassifier (const xAOD::CaloCluster *, MCTruthPartClassifier::Info *info=nullptr) const override final
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleTruthClassifier (const xAOD::Jet *, bool DR, MCTruthPartClassifier::Info *info=nullptr) const override final
virtual void print () const
 Print the state of the tool.
ServiceHandle< StoreGateSvc > & evtStore ()
 The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.
const ServiceHandle< StoreGateSvc > & detStore () const
 The standard StoreGateSvc/DetectorStore Returns (kind of) a pointer to the StoreGateSvc.
virtual StatusCode sysInitialize () override
 Perform system initialization for an algorithm.
virtual StatusCode sysStart () override
 Handle START transition.
virtual std::vector< Gaudi::DataHandle * > inputHandles () const override
 Return this algorithm's input handles.
virtual std::vector< Gaudi::DataHandle * > outputHandles () const override
 Return this algorithm's output handles.
Gaudi::Details::PropertyBase & declareProperty (Gaudi::Property< T, V, H > &t)
void updateVHKA (Gaudi::Details::PropertyBase &)
MsgStream & msg () const
bool msgLvl (const MSG::Level lvl) const
Additional helper functions, not directly mimicking Athena
template<class T>
const T * getProperty (const std::string &name) const
 Get one of the tool's properties.
const std::string & msg_level_name () const __attribute__((deprecated))
 A deprecated function for getting the message level's name.
const std::string & getName (const void *ptr) const
 Get the name of an object that is / should be in the event store.
SG::sgkey_t getKey (const void *ptr) const
 Get the (hashed) key of an object that is in the event store.

Protected Member Functions

void renounceArray (SG::VarHandleKeyArray &handlesArray)
 remove all handles from I/O resolution
std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > renounce (T &h)
void extraDeps_update_handler (Gaudi::Details::PropertyBase &ExtraDeps)
 Add StoreName to extra input/output deps as needed.

Private Types

typedef ServiceHandle< StoreGateSvcStoreGateSvc_t

Private Member Functions

double detEta (double x, double y) const
double detPhi (double x, double y) const
bool TruthLoopDetectionMethod1 (const xAOD::TruthVertex *childOrigVtx, const xAOD::TruthParticle *parent) const
bool TruthLoopDetectionMethod2 (const xAOD::TruthParticle *child, const xAOD::TruthParticle *parent) const
bool TruthLoopDetectionMethod3 (const xAOD::TruthVertex *childOrigVtx, const xAOD::TruthParticle *parent) const
MCTruthPartClassifier::ParticleOrigin defOrigOfElectron (const xAOD::TruthParticleContainer &xTruthParticleContainer, const xAOD::TruthParticle *, bool &isPrompt, MCTruthPartClassifier::Info &info) const
MCTruthPartClassifier::ParticleOrigin defOrigOfMuon (const xAOD::TruthParticleContainer &xTruthParticleContainer, const xAOD::TruthParticle *, bool &isPrompt, MCTruthPartClassifier::Info &info) const
MCTruthPartClassifier::ParticleOrigin defOrigOfTau (const xAOD::TruthParticleContainer &xTruthParticleContainer, const xAOD::TruthParticle *, int motherPDG, MCTruthPartClassifier::Info &info) const
MCTruthPartClassifier::ParticleOrigin defOrigOfPhoton (const xAOD::TruthParticleContainer &xTruthParticleContainer, const xAOD::TruthParticle *, bool &isPrompt, MCTruthPartClassifier::Info &info) const
MCTruthPartClassifier::ParticleOrigin defOrigOfNeutrino (const xAOD::TruthParticleContainer &xTruthParticleContainer, const xAOD::TruthParticle *, bool &isPrompt, MCTruthPartClassifier::Info &info) const
bool genPartToCalo (const EventContext &ctx, const xAOD::CaloCluster *clus, const xAOD::TruthParticle *thePart, bool isFwrdEle, double &dRmatch, bool &isNarrowCone, const CaloDetDescrManager &caloDDMgr) const
double fracParticleInJet (const xAOD::TruthParticle *, const xAOD::Jet *, bool DR, bool nparts) const
void findJetConstituents (const xAOD::Jet *, std::set< const xAOD::TruthParticle * > &constituents, bool DR) const
Gaudi::Details::PropertyBase & declareGaudiProperty (Gaudi::Property< T, V, H > &hndl, const SG::VarHandleKeyType &)
 specialization for handling Gaudi::Property<SG::VarHandleKey>

Private Attributes

SG::ReadHandleKey< xAOD::TruthParticleContainerm_truthParticleContainerKey {this,"xAODTruthParticleContainerName","TruthParticles","ReadHandleKey for xAOD::TruthParticleContainer"}
ToolHandle< Trk::IParticleCaloExtensionToolm_caloExtensionTool {this,"ParticleCaloExtensionTool",""}
SG::ReadCondHandleKey< CaloDetDescrManagerm_caloMgrKey {this,"CaloDetDescrManager",""}
ToolHandle< xAOD::ITruthParticlesInConeToolm_truthInConeTool {this,"TruthInConeTool","xAOD::TruthParticlesInConeTool/TruthParticlesInConeTool"}
bool m_FwdElectronUseG4Sel
float m_FwdElectronTruthExtrEtaCut
float m_FwdElectronTruthExtrEtaWindowCut
float m_partExtrConeEta
float m_partExtrConePhi
bool m_useCaching
float m_phtClasConePhi
float m_phtClasConeEta
float m_phtdRtoTrCut
float m_fwrdEledRtoTrCut
bool m_ROICone
float m_pTChargePartCut
float m_pTNeutralPartCut
bool m_inclG4part
SG::ReadHandleKey< xAODTruthParticleLinkVectorm_truthLinkVecReadHandleKey {this,"xAODTruthLinkVector","xAODTruthLinks", "ReadHandleKey for xAODTruthParticleLinkVector"}
float m_deltaRMatchCut
float m_deltaPhiMatchCut
int m_NumOfSiHitsCut
float m_jetPartDRMatch
StoreGateSvc_t m_evtStore
 Pointer to StoreGate (event store by default)
StoreGateSvc_t m_detStore
 Pointer to StoreGate (detector store by default)
std::vector< SG::VarHandleKeyArray * > m_vhka
bool m_varHandleArraysDeclared

Detailed Description

Definition at line 55 of file MCTruthClassifier.h.

Member Typedef Documentation

◆ StoreGateSvc_t

typedef ServiceHandle<StoreGateSvc> AthCommonDataStore< AthCommonMsg< AlgTool > >::StoreGateSvc_t
privateinherited

Definition at line 388 of file AthCommonDataStore.h.

Constructor & Destructor Documentation

◆ MCTruthClassifier()

MCTruthClassifier::MCTruthClassifier ( const std::string & type)
inline

Definition at line 60 of file MCTruthClassifier.h.

60 : asg::AsgTool(type) {
61#if !defined(XAOD_ANALYSIS) && !defined(GENERATIONBASE)
62 declareProperty("FwdElectronUseG4Sel", m_FwdElectronUseG4Sel = true,
63 "Use Geant4 selection for forward electrons calo clusters");
64 declareProperty("FwdElectronTruthExtrEtaCut",
66 "Cut on the eta of the truth Particles to be extrapolated "
67 "for Fwd electrons");
69 "FwdElectronTruthExtrEtaWindowCut",
71 "Cut on the delta eta of the truth Particles to be extrapolated for "
72 "Fwd electrons and the current FwdElectron");
73 declareProperty("partExtrConePhi", m_partExtrConePhi = 0.4);
74 declareProperty("partExtrConeEta", m_partExtrConeEta = 0.2);
75 declareProperty("phtClasConePhi", m_phtClasConePhi = 0.05);
76 declareProperty("phtClasConeEta", m_phtClasConeEta = 0.025);
77 declareProperty("useCaching", m_useCaching = true);
78 declareProperty("phtdRtoTrCut", m_phtdRtoTrCut = 0.1);
79 declareProperty("fwrdEledRtoTrCut", m_fwrdEledRtoTrCut = 0.15);
80 declareProperty("ROICone", m_ROICone = false);
81 //AV: those below are needed in egammaClusMatch
82 declareProperty("pTChargePartCut", m_pTChargePartCut = 1.0);
83 declareProperty("pTNeutralPartCut", m_pTNeutralPartCut = 0.);
84 declareProperty("inclG4part", m_inclG4part = false);
85#endif
86#ifndef GENERATIONBASE
87 declareProperty("deltaRMatchCut", m_deltaRMatchCut = 0.2);
88 declareProperty("deltaPhiMatchCut", m_deltaPhiMatchCut = 0.2);
89 declareProperty("NumOfSiHitsCut", m_NumOfSiHitsCut = 3);
90 declareProperty("jetPartDRMatch", m_jetPartDRMatch = 0.4);
91#endif
92 }
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
float m_FwdElectronTruthExtrEtaWindowCut

◆ ~MCTruthClassifier()

virtual MCTruthClassifier::~MCTruthClassifier ( )
virtualdefault

Member Function Documentation

◆ declareGaudiProperty()

Gaudi::Details::PropertyBase & AthCommonDataStore< AthCommonMsg< AlgTool > >::declareGaudiProperty ( Gaudi::Property< T, V, H > & hndl,
const SG::VarHandleKeyType &  )
inlineprivateinherited

specialization for handling Gaudi::Property<SG::VarHandleKey>

Definition at line 156 of file AthCommonDataStore.h.

158 {
160 hndl.value(),
161 hndl.documentation());
162
163 }

◆ declareProperty()

Gaudi::Details::PropertyBase & AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty ( Gaudi::Property< T, V, H > & t)
inlineinherited

Definition at line 145 of file AthCommonDataStore.h.

145 {
146 typedef typename SG::HandleClassifier<T>::type htype;
148 }
Gaudi::Details::PropertyBase & declareGaudiProperty(Gaudi::Property< T, V, H > &hndl, const SG::VarHandleKeyType &)
specialization for handling Gaudi::Property<SG::VarHandleKey>

◆ defOrigOfElectron()

ParticleOrigin MCTruthClassifier::defOrigOfElectron ( const xAOD::TruthParticleContainer & xTruthParticleContainer,
const xAOD::TruthParticle * thePart,
bool & isPrompt,
MCTruthPartClassifier::Info & info ) const
private

Definition at line 247 of file MCTruthClassifierGen.cxx.

251{
252 ATH_MSG_DEBUG("Executing DefOrigOfElectron ");
253
254 // Find the first copy of this particle stored in the xAOD::TruthParticleContainer (i.e. the particle prior to any interactions)
255 const xAOD::TruthParticle* thePriPart = MC::findMatching(xTruthParticleContainer, thePart);
256 if (!thePriPart) return NonDefined;
257 if (!MC::isElectron(thePriPart)) return NonDefined;
258
259 //-- to define electron outcome status
260 info.particleOutCome = defOutComeOfElectron(thePriPart);
261
262 const xAOD::TruthVertex* partProdVtx = thePriPart->hasProdVtx() ? thePriPart->prodVtx() : nullptr;
263 if (!partProdVtx) return NonDefined;
264
265 if (partProdVtx->nIncomingParticles() > 1) ATH_MSG_DEBUG("DefOrigOfElectron:: electron has more than one parent.");
266
267 const xAOD::TruthParticle* ancestor = MC::findMother(thePriPart);
268 info.setMotherProperties(ancestor);
269 if (!ancestor) { return NonDefined; } // After this point "ancestor" cannot be nullptr
270
271 // Start of method 1 of protecting against loops
272 bool samePart = TruthLoopDetectionMethod1(partProdVtx, ancestor);
273 // to resolve Sherpa loop
274 // End of method 1 of protecting against loops
275
276 if ((MC::isMuon(ancestor) || MC::isTau(ancestor) || MC::isW(ancestor)) && ancestor->hasProdVtx() && !samePart) {
277 int pPDG(0);
278 const xAOD::TruthParticle* ancestorParent{};
279 do {
280 pPDG = 0; // reset pPDG
281 ancestorParent = MC::findMother(ancestor);
282 // Start of method 2 of protecting against loops
283 // to prevent Sherpa loop
284 if (ancestor == ancestorParent) { break; }
285 if (TruthLoopDetectionMethod2(ancestor,ancestorParent)) {
286 ancestorParent = ancestor;
287 break;
288 }
289 // End of method 2 of protecting against loops
290 // FIXME why are slightly different criteria used in method 1 and method 2???
291 if (ancestorParent) {
292 pPDG = ancestorParent->pdgId(); // Only set pPDG in the case that we aren't in a loop.
293 if (MC::isMuon(pPDG) || MC::isTau(pPDG) || MC::isW(pPDG)) { // There will be another iteration so set ancestor to ancestorParent
294 ancestor = ancestorParent; // ancestorParent is not nullptr here
295 }
296 }
297 } while ((MC::isMuon(pPDG) || MC::isTau(pPDG) || MC::isW(pPDG)));
298
299 if (MC::isMuon(pPDG) || MC::isTau(pPDG) || MC::isW(pPDG) || MC::isZ(pPDG) || MC::isHiggs(pPDG) ||
300 MC::isMSSMHiggs(pPDG) || MC::isHeavyBoson(pPDG) || MC::isTop(pPDG) || // MSSM Higgs bosons, Heavy bosons( Z', Z'', W'+)
301 std::abs(pPDG) == MC::WBOSON_LRSM || MC::isNeutrinoRH(pPDG) || // Left-right symmetric model WBoson || Right-handed neutrino (Pythia-specific)
302 MC::isSUSY(pPDG)) {
303 ancestor = ancestorParent; // ancestorParent is not nullptr here
304 }
305 }
306
307 info.setMotherProperties(ancestor);
308 const int ancestorPDG = ancestor->pdgId();
309 const xAOD::TruthVertex* ancestorProdVtx = ancestor->hasProdVtx() ? ancestor->prodVtx() : nullptr;
310 partProdVtx = ancestor->decayVtx();
311 const int numOfParents = partProdVtx->nIncomingParticles();
312 const int numberOfChildren = partProdVtx->nOutgoingParticles();
313
314 // Determine decay products
315 auto DP = DecayProducts(partProdVtx);
316 const int NumOfPhot = DP.pd(MC::PHOTON);
317 const int NumOfEl = DP.pd(MC::ELECTRON);
318 const int NumOfPos = DP.pd(MC::POSITRON);
319 const int NumOfquark = DP.apd({MC::DQUARK,MC::UQUARK,MC::SQUARK,MC::CQUARK,MC::BQUARK,MC::TQUARK});
320 const int NumOfgluon = DP.apd(MC::GLUON);
321 const int NumOfElNeut = DP.apd(MC::NU_E);
322 const int NumOfLQ = DP.apd(MC::LEPTOQUARK);
323 const int NumOfMuPl = DP.pd(-MC::MUON);
324 const int NumOfMuMin = DP.pd(MC::MUON);
325 const int NumOfMuNeut = DP.apd(MC::NU_MU);
326 const int NumOfTau = DP.apd(MC::TAU);
327 const int NumOfTauNeut = DP.apd(MC::NU_TAU);
328
329 samePart = false;
330 int NumOfNucFr(0);
331 const bool possibleNuclearFragment = (numOfParents == 1 && (MC::isPhoton(ancestorPDG) || MC::isElectron(ancestorPDG) || MC::isMuon(ancestorPDG) || std::abs(ancestorPDG) == MC::PIPLUS));
332 for (const auto& aChild: partProdVtx->particles_out()) {
333 if (!aChild) continue;
334 const int childPDG = aChild->pdgId();
335 if (std::abs(childPDG) == std::abs(ancestorPDG) && HepMC::is_same_generator_particle(aChild, ancestor )) samePart = true;
336 if (possibleNuclearFragment &&
337 (MC::isNucleus(childPDG) || childPDG == 0 || childPDG == MC::PROTON || childPDG == MC::NEUTRON || // FIXME Do we really expect particles with PDG_ID = 0 in the truth record?
338 std::abs(childPDG) == MC::PIPLUS || std::abs(childPDG) == MC::PI0))
339 NumOfNucFr++;
340 }
341 // End of section determining decay products
342
343 if (MC::isPhoton(ancestorPDG) && ancestorProdVtx) {
344 if (ancestorProdVtx->nIncomingParticles() > 1) { ATH_MSG_DEBUG("DefOrigOfElectron:: photon has more than one parent."); }
345 for (const auto& photonParent: ancestorProdVtx->particles_in()) {
346 if (!photonParent) continue;
347 info.photonMother = photonParent; // FIXME Just taking the first valid particle...
348 }
349 }
350
351 if ((MC::isPhoton(ancestorPDG) && numberOfChildren == 2 && NumOfEl == 1 && NumOfPos == 1) || (MC::isPhoton(ancestorPDG) && numberOfChildren == 1 && (NumOfEl == 1 || NumOfPos == 1))) return PhotonConv;
352
353 // e,gamma,pi+Nuclear->NuclearFragments+nuclons+e
354 if ((numOfParents == 1 && (MC::isPhoton(ancestorPDG) || MC::isElectron(ancestorPDG) || MC::isTau(ancestorPDG))) && numberOfChildren > 1 && NumOfNucFr != 0) return ElMagProc;
355
356 if (numOfParents == 1 && std::abs(ancestorPDG) == MC::PIPLUS && numberOfChildren > 2 && NumOfNucFr != 0) return ElMagProc;
357
358 // nuclear photo fission
359 if (MC::isPhoton(ancestorPDG) && numberOfChildren > 4 && NumOfNucFr != 0) return ElMagProc;
360
361 // unknown process el(pos)->el+pos??
362 if (MC::isElectron(ancestorPDG) && numberOfChildren == 2 && NumOfEl == 1 && NumOfPos == 1) return ElMagProc;
363
364 // unknown process el->el+el??
365 if (ancestorPDG == MC::ELECTRON && numberOfChildren == 2 && NumOfEl == 2 && NumOfPos == 0) return ElMagProc;
366
367 // unknown process pos->pos+pos??
368 if (ancestorPDG == MC::POSITRON && numberOfChildren == 2 && NumOfEl == 0 && NumOfPos == 2) return ElMagProc;
369
370 // unknown process pos/el->pos/el??
371 if (MC::isElectron(ancestorPDG) && !MC::isDecayed(ancestor) && ancestorPDG == thePriPart->pdgId() && numberOfChildren == 1 && !samePart) return ElMagProc;
372
373 // pi->pi+e+/e-; mu->mu+e+/e- ;
374 // gamma+ atom->gamma(the same) + e (compton scattering)
375 if (numberOfChildren == 2 && (NumOfEl == 1 || NumOfPos == 1) && !MC::isElectron(ancestorPDG) && samePart) return ElMagProc;
376
377 if ((ancestorPDG == MC::PI0 && numberOfChildren == 3 && NumOfPhot == 1 && NumOfEl == 1 && NumOfPos == 1) ||
378 (ancestorPDG == MC::PI0 && numberOfChildren == 4 && NumOfPhot == 0 && NumOfEl == 2 && NumOfPos == 2))
379 return DalitzDec;
380
381 // Quark weak decay
382 if (MC::isSMQuark(ancestorPDG) && numOfParents == 1 && numberOfChildren == 3 && NumOfquark == 1 && NumOfElNeut == 1) return QuarkWeakDec;
383
384 if (MC::isMuon(ancestorPDG) && NumOfNucFr != 0) return ElMagProc;
385
386 if (MC::isTop(ancestorPDG)) return top;
387
388 if (MC::isW(ancestorPDG) && ancestorProdVtx && ancestorProdVtx->nIncomingParticles() != 0) {
389
390 const xAOD::TruthVertex* prodVert = ancestorProdVtx;
391 const xAOD::TruthParticle* ptrPart{};
392 do {
393 ptrPart = prodVert->incomingParticle(0); // FIXME just taking the first one
394 prodVert = ptrPart->hasProdVtx() ? ptrPart->prodVtx() : nullptr;
395 } while (MC::isW(ptrPart) && prodVert);
396
397 if (prodVert && prodVert->nIncomingParticles() == 1) {
398 if (std::abs(ptrPart->pdgId()) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
399 if (std::abs(ptrPart->pdgId()) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
400 if (std::abs(ptrPart->pdgId()) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
401 }
402 return WBoson;
403 }
404 if (MC::isW(ancestorPDG)) return WBoson;
405 if (MC::isZ(ancestorPDG)) return ZBoson;
406
407 // MadGraphPythia ZWW*->lllnulnu
408 if (numOfParents == 1 && numberOfChildren > 4 && (MC::isSMQuark(ancestorPDG) || MC::isGluon(ancestorPDG))) {
409
410 const xAOD::TruthParticle* thePartToCheck = thePriPart;
411 const xAOD::TruthParticle* theParent = thePriPart->hasProdVtx() ? thePriPart->prodVtx()->incomingParticle(0) : nullptr; // FIXME just taking the first one
412 if (theParent && MC::isElectron(theParent) && MC::isDecayed(theParent)) { thePartToCheck = theParent; }
413
414 bool isZboson = false;
415 bool isWboson = false;
416 bool skipnext = false;
417
418 for (unsigned int ipOut = 0; ipOut + 1 < partProdVtx->nOutgoingParticles(); ++ipOut) {
419 const xAOD::TruthParticle* aChild = partProdVtx->outgoingParticle(ipOut);
420 if (!aChild) continue;
421 const xAOD::TruthParticle* theNextChild = nullptr;
422 for (unsigned int ipOut1 = ipOut + 1; ipOut1 < partProdVtx->nOutgoingParticles(); ipOut1++) {
423 theNextChild = partProdVtx->outgoingParticle(ipOut1);
424 if (theNextChild) break;
425 }
426 if (!theNextChild) continue;
427 if (skipnext) {
428 skipnext = false;
429 continue;
430 }
431
432 if (MC::isElectron(aChild) && MC::isElectron(theNextChild)) {
433 // Zboson
434 if (thePartToCheck == aChild || thePartToCheck == theNextChild) {
435 isZboson = true;
436 break;
437 }
438 skipnext = true;
439 } else if (MC::isElectron(aChild) && std::abs(theNextChild->pdgId()) == MC::NU_E) {
440 // WBoson
441 if (thePartToCheck == aChild || thePartToCheck == theNextChild) {
442 isWboson = true;
443 break;
444 }
445 skipnext = true;
446 }
447 }
448 if (isWboson) return WBoson;
449 if (isZboson) return ZBoson;
450 }
451 if (numOfParents == 2) {
452 //--Sherpa Z->ee
453 if ((numberOfChildren - NumOfquark - NumOfgluon) == 2 && NumOfEl == 1 && NumOfPos == 1) return ZBoson;
454
455 //--Sherpa W->enu ??
456 if ((numberOfChildren - NumOfquark - NumOfgluon) == 2 && (NumOfEl == 1 || NumOfPos == 1) && NumOfElNeut == 1) return WBoson;
457
458 const int pdg1 = partProdVtx->incomingParticle(0)->pdgId();
459 const int pdg2 = partProdVtx->incomingParticle(1)->pdgId();
460 //--Sherpa ZZ,ZW
461 if ((numberOfChildren - NumOfquark - NumOfgluon) == 4 &&
462 (NumOfEl + NumOfPos + NumOfMuPl + NumOfMuMin + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 4) &&
463 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return DiBoson;
464
465 //--Sherpa VVV -- Note, have to allow for prompt photon radiation or these get lost
466 if ((numberOfChildren - NumOfquark - NumOfgluon - NumOfPhot) == 6 &&
467 (NumOfEl + NumOfPos + NumOfMuPl + NumOfMuMin + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 6) &&
468 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return MultiBoson;
469 }
470
471 // New Sherpa Z->ee
472 if (partProdVtx == ancestorProdVtx) {
473 int NumOfEleLoop = 0;
474 int NumOfLepLoop = 0;
475 int NumOfEleNeuLoop = 0;
476 for (const auto *const pout: partProdVtx->particles_out()) {
477 if (!pout) continue;
478 for (const auto *const pin: partProdVtx->particles_in()) {
479 if (!pin) continue;
480 if (!HepMC::is_same_particle(pout,pin)) continue;
481 if (MC::isElectron(pout)) NumOfEleLoop++;
482 if (std::abs(pout->pdgId()) == MC::NU_E) NumOfEleNeuLoop++;
483 if (MC::isSMLepton(pout)) NumOfLepLoop++;
484 break; // break out of inner loop after having found two matching particles
485 }
486 }
487 if (NumOfEleLoop == 2 && NumOfEleNeuLoop == 0) return ZBoson;
488 if (NumOfEleLoop == 1 && NumOfEleNeuLoop == 1) return WBoson;
489 if ((NumOfEleLoop == 4 && NumOfEleNeuLoop == 0) || (NumOfEleLoop == 3 && NumOfEleNeuLoop == 1) ||
490 (NumOfEleLoop == 2 && NumOfEleNeuLoop == 2)) return DiBoson;
491 if (NumOfLepLoop == 4) return DiBoson;
492 }
493
494 //-- McAtNLo
495
496 if (MC::isHiggs(ancestorPDG)) return Higgs;
497
498 if (MC::isMSSMHiggs(ancestorPDG)) return HiggsMSSM; // MSSM Higgs bosons
499
500 if (MC::isHeavyBoson(ancestorPDG)) return HeavyBoson; // Heavy bosons( Z', Z'', W'+)
501
502 if (MC::isMuon(ancestorPDG)) return Mu;
503 if (MC::isTau(ancestorPDG)) {
504 const ParticleOrigin tauOrig = defOrigOfTau(xTruthParticleContainer, ancestor, ancestorPDG, info);
505 const ParticleType tautype = defTypeOfTau(tauOrig);
506 return (tautype == IsoTau)?tauOrig:TauLep;
507 }
508
509 if (std::abs(ancestorPDG) == MC::WBOSON_LRSM) return WBosonLRSM; // Left-right symmetric model WBoson (Pythia-specific)
510 if (std::abs(ancestorPDG) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
511 if (std::abs(ancestorPDG) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
512 if (std::abs(ancestorPDG) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
513 if (MC::isLeptoQuark(ancestorPDG) || NumOfLQ != 0) return LQ;
514 if (MC::isSUSY(ancestorPDG)) return SUSY;
515 if (MC::isBSM(ancestorPDG)) return OtherBSM;
516
517 const ParticleType pType = defTypeOfHadron(ancestorPDG);
518 if ((pType == BBbarMesonPart || pType == CCbarMesonPart) && ancestorProdVtx && MC::isHardScatteringVertex(ancestorProdVtx)) isPrompt = true;
519 return convHadronTypeToOrig(pType, ancestorPDG);
520}
#define ATH_MSG_DEBUG(x)
ParticleType
Definition TruthClasses.h:8
@ CCbarMesonPart
@ IsoTau
@ BBbarMesonPart
ParticleOrigin
@ MultiBoson
@ SUSY
@ DalitzDec
@ NuRTau
@ DiBoson
@ ZBoson
@ top
@ HeavyBoson
@ ElMagProc
@ PhotonConv
@ NuRMu
@ QuarkWeakDec
@ LQ
@ Higgs
@ Mu
@ WBoson
@ WBosonLRSM
@ OtherBSM
@ HiggsMSSM
@ NuREle
@ TauLep
@ NonDefined
bool TruthLoopDetectionMethod1(const xAOD::TruthVertex *childOrigVtx, const xAOD::TruthParticle *parent) const
bool TruthLoopDetectionMethod2(const xAOD::TruthParticle *child, const xAOD::TruthParticle *parent) const
MCTruthPartClassifier::ParticleOrigin defOrigOfTau(const xAOD::TruthParticleContainer &xTruthParticleContainer, const xAOD::TruthParticle *, int motherPDG, MCTruthPartClassifier::Info &info) const
int pdgId() const
PDG ID code.
const TruthVertex_v1 * decayVtx() const
The decay vertex of this particle.
bool hasProdVtx() const
Check for a production vertex on this particle.
const TruthVertex_v1 * prodVtx() const
The production vertex of this particle.
const TruthParticle_v1 * outgoingParticle(size_t index) const
Get one of the outgoing particles.
const TruthParticle_v1 * incomingParticle(size_t index) const
Get one of the incoming particles.
std::vector< const TruthParticle * > particles_out() const
Get the outgoing particles.
size_t nOutgoingParticles() const
Get the number of outgoing particles.
size_t nIncomingParticles() const
Get the number of incoming particles.
std::vector< const TruthParticle * > particles_in() const
Get the incoming particles.
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_same_particle(const T1 &p1, const T2 &p2)
Method to establish if two particles in the GenEvent actually represent the same particle.
ParticleOutCome defOutComeOfElectron(T thePart)
ParticleOrigin convHadronTypeToOrig(ParticleType pType, int motherPDG)
ParticleType defTypeOfTau(ParticleOrigin TauOrig)
ParticleType defTypeOfHadron(int pdg)
int isPrompt(const unsigned int classify, bool allow_prompt_tau_decays=true)
static const int PI0
static const int UQUARK
T findMatching(C TruthContainer, T p)
Function to find a particle in container.
bool isNeutrinoRH(const T &p)
PDG Rule 12: APID: Helper function for right-handed neutrino states These are generator defined PDG I...
bool isZ(const T &p)
static const int SQUARK
static const int NEUTRON
static const int DQUARK
static const int MUON
bool isHardScatteringVertex(T pVert)
Function to classify the vertex as hard scattering vertex.
bool isSMLepton(const T &p)
APID: the fourth generation leptons are not standard model leptons.
static const int CQUARK
bool isPhoton(const T &p)
bool isW(const T &p)
static const int PHOTON
static const int RH_NU_TAU
static const int WBOSON_LRSM
static const int TQUARK
static const int TAU
static const int GLUON
bool isElectron(const T &p)
static const int ELECTRON
static const int PIPLUS
bool isSMQuark(const T &p)
bool isTop(const T &p)
static const int POSITRON
bool isMuon(const T &p)
bool isSUSY(const T &p)
static const int NU_MU
bool isMSSMHiggs(const T &p)
APID: Additional Higgs bosons for MSSM (Used in MCTruthClassifier)
bool isDecayed(const T &p)
Identify if the particle decayed.
bool isQuark(const T &p)
PDG rule 2: Quarks and leptons are numbered consecutively starting from 1 and 11 respectively; to do ...
T findMother(T thePart)
Function to get a mother of particle. MCTruthClassifier legacy.
static const int NU_E
static const int BQUARK
bool isHiggs(const T &p)
APID: HIGGS boson is only one particle.
static const int LEPTOQUARK
static const int NU_TAU
bool isNucleus(const T &p)
PDG rule 16 Nuclear codes are given as 10-digit numbers ±10LZZZAAAI.
static const int RH_NU_MU
bool isGluon(const T &p)
bool isHeavyBoson(const T &p)
APID: Additional "Heavy"/"prime" versions of W and Z bosons (Used in MCTruthClassifier)
bool isLeptoQuark(const T &p)
PDG rule 11c: “One-of-a-kind” exotic particles are assigned numbers in the range 41–80.
static const int RH_NU_E
PDG Rule 12: Generator defined PDG ID values for right handed neutrinos and corresponding W+ boson fr...
bool isTau(const T &p)
static const int PROTON
bool isBSM(const T &p)
APID: graviton and all Higgs extensions are BSM.
pout(output, newline=True)
Definition calibdata.py:129
TruthVertex_v1 TruthVertex
Typedef to implementation.
Definition TruthVertex.h:15
TruthParticle_v1 TruthParticle
Typedef to implementation.

◆ defOrigOfMuon()

ParticleOrigin MCTruthClassifier::defOrigOfMuon ( const xAOD::TruthParticleContainer & xTruthParticleContainer,
const xAOD::TruthParticle * thePart,
bool & isPrompt,
MCTruthPartClassifier::Info & info ) const
private

Definition at line 523 of file MCTruthClassifierGen.cxx.

527{
528 ATH_MSG_DEBUG("Executing DefOrigOfMuon ");
529
530 // Find the first copy of this particle stored in the xAOD::TruthParticleContainer (i.e. the particle prior to any interactions)
531 const xAOD::TruthParticle* thePriPart = MC::findMatching(xTruthParticleContainer, thePart);
532 if (!thePriPart) return NonDefined;
533 if (!MC::isMuon(thePriPart)) return NonDefined;
534
535 //-- to define muon outcome status
536 info.particleOutCome = defOutComeOfMuon(thePriPart);
537
538 const xAOD::TruthVertex* partProdVtx = thePriPart->hasProdVtx() ? thePriPart->prodVtx() : nullptr;
539 if (!partProdVtx) return NonDefined;
540
541 if (partProdVtx->nIncomingParticles() > 1) ATH_MSG_DEBUG("DefOrigOfMuon:: muon has more than one parent.");
542
543 const xAOD::TruthParticle* ancestor = MC::findMother(thePriPart);
544 info.setMotherProperties(ancestor);
545 if (!ancestor) { return NonDefined; } // ancestor is not a nullptr beyond this point
546
547 // "method 1" for finding Sherpa loops from defOrigOfElectron not used here. Why?
548
549 if ((MC::isTau(ancestor)|| MC::isW(ancestor)) && ancestor->hasProdVtx()) {
550 int pPDG(0);
551 const xAOD::TruthParticle* ancestorParent{};
552 do {
553 pPDG = 0;
554 ancestorParent = MC::findMother(ancestor);
555 // Start of method 2 of protecting against loops
556 // to prevent Sherpa loop
557 if (ancestor == ancestorParent) { break; }
558 if (TruthLoopDetectionMethod2(ancestor,ancestorParent)) {
559 ancestorParent = ancestor;
560 break;
561 }
562 // End of method 2 of protecting against loops
563
564 if (ancestorParent) {
565 pPDG = ancestorParent->pdgId();// Only set pPDG in the case that we aren't in a loop.
566 if (MC::isMuon(pPDG) || MC::isTau(pPDG) || MC::isW(pPDG)) { // FIXME should this be (MC::isTau(pPDG) || MC::isW(pPDG)) ???
567 // There will be another iteration so set ancestor to ancestorParent
568 ancestor = ancestorParent; // ancestorParent is not nullptr here
569 }
570 }
571 } while ((MC::isMuon(pPDG) || MC::isTau(pPDG) || MC::isW(pPDG))); // FIXME should this be (MC::isTau(pPDG) || MC::isW(pPDG)) ???
572
573 if (MC::isTau(pPDG) || MC::isW(pPDG) || MC::isZ(pPDG) || MC::isHiggs(pPDG) ||
574 MC::isMSSMHiggs(pPDG) || MC::isHeavyBoson(pPDG) || MC::isTop(pPDG) || // MSSM Higgs bosons, Heavy bosons( Z', Z'', W'+)
575 std::abs(pPDG) == MC::WBOSON_LRSM || MC::isNeutrinoRH(pPDG) || // Left-right symmetric model WBoson || Right-handed neutrino (Pythia-specific)
576 MC::isSUSY(pPDG)) {
577 ancestor = ancestorParent; // ancestorParent is not nullptr here
578 }
579 }
580
581 info.setMotherProperties(ancestor);
582 const int ancestorPDG = ancestor->pdgId();
583 const xAOD::TruthVertex* ancestorProdVtx = ancestor->hasProdVtx() ? ancestor->prodVtx() : nullptr;
584 partProdVtx = ancestor->decayVtx();
585 const int numOfParents = partProdVtx->nIncomingParticles();
586 const int numberOfChildren = partProdVtx->nOutgoingParticles();
587
588 // Determine decay products
589 auto DP = DecayProducts(partProdVtx);
590 const int NumOfPhot = DP.pd(MC::PHOTON);
591 const int NumOfEl = DP.pd(MC::ELECTRON);
592 const int NumOfPos = DP.pd(MC::POSITRON);
593 const int NumOfElNeut = DP.apd(MC::NU_E);
594 const int NumOfMuNeut = DP.apd(MC::NU_MU);
595 const int NumOfLQ = DP.apd(MC::LEPTOQUARK);
596 const int NumOfquark = DP.apd({MC::DQUARK,MC::UQUARK,MC::SQUARK,MC::CQUARK,MC::BQUARK,MC::TQUARK});
597 const int NumOfgluon = DP.apd(MC::GLUON);
598 const int NumOfMuPl = DP.pd(-MC::MUON);
599 const int NumOfMuMin = DP.pd(MC::MUON);
600 const int NumOfTau = DP.apd(MC::TAU);
601 const int NumOfTauNeut = DP.apd(MC::NU_TAU);
602 // End of section determining decay products
603
604 if (std::abs(ancestorPDG) == MC::PIPLUS && numberOfChildren == 2 && NumOfMuNeut == 1) return PionDecay;
605 if (std::abs(ancestorPDG) == MC::KPLUS && numberOfChildren == 2 && NumOfMuNeut == 1) return KaonDecay;
606 if (MC::isTau(ancestorPDG)) {
607 const ParticleOrigin tauOrig = defOrigOfTau(xTruthParticleContainer, ancestor, ancestorPDG, info);
608 const ParticleType tautype = defTypeOfTau(tauOrig);
609 return (tautype == IsoTau)?tauOrig:TauLep;
610 }
611
612 if (MC::isTop(ancestorPDG)) return top;
613 // Quark weak decay
614 if (MC::isSMQuark(ancestorPDG) && numOfParents == 1 && numberOfChildren == 3 && NumOfquark == 1 && NumOfMuNeut == 1) return QuarkWeakDec;
615
616 if (MC::isW(ancestorPDG) && ancestorProdVtx && ancestorProdVtx->nIncomingParticles() != 0) {
617 const xAOD::TruthVertex* prodVert = ancestorProdVtx;
618 const xAOD::TruthParticle* itrP;
619 do {
620 itrP = prodVert->incomingParticle(0); // FIXME just taking the first one
621 prodVert = itrP->hasProdVtx() ? itrP->prodVtx() : nullptr;
622 } while (MC::isW(itrP) && prodVert);
623
624 if (prodVert && prodVert->nIncomingParticles() == 1) {
625 if (std::abs(itrP->pdgId()) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
626 if (std::abs(itrP->pdgId()) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
627 if (std::abs(itrP->pdgId()) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
628 }
629 return WBoson;
630 }
631 if (MC::isW(ancestorPDG)) return WBoson;
632 if (MC::isZ(ancestorPDG)) return ZBoson;
633 if (MC::isPhoton(ancestorPDG) && numberOfChildren == 2 && NumOfMuMin == 1 && NumOfMuPl == 1) return PhotonConv;
634 //-- Exotics
635
636 // MadGraphPythia ZWW*->lllnulnu
637 if (numOfParents == 1 && numberOfChildren > 4 && (MC::isSMQuark(ancestorPDG) || MC::isGluon(ancestorPDG))) {
638 bool isZboson = false;
639 bool isWboson = false;
640 bool skipnext = false;
641 for (unsigned int ipOut = 0; ipOut + 1 < partProdVtx->nOutgoingParticles(); ipOut++) {
642 if (skipnext) {
643 skipnext = false;
644 continue;
645 }
646 const xAOD::TruthParticle* aChild = partProdVtx->outgoingParticle(ipOut);
647 if (!aChild) continue;
648 const xAOD::TruthParticle* theNextChild{};
649 for (unsigned int ipOut1 = ipOut + 1; ipOut1 < partProdVtx->nOutgoingParticles(); ipOut1++) {
650 theNextChild = partProdVtx->outgoingParticle(ipOut1);
651 if (theNextChild) break;
652 }
653 if (!theNextChild) continue;
654 if (MC::isMuon(aChild) && MC::isMuon(theNextChild)) {
655 // Zboson
656 if (thePriPart == aChild || thePriPart == theNextChild) {
657 isZboson = true;
658 break;
659 }
660 skipnext = true;
661 } else if (MC::isMuon(aChild) && std::abs(theNextChild->pdgId()) == MC::NU_MU) {
662 // WBoson
663 if (thePriPart == aChild || thePriPart == theNextChild) {
664 isWboson = true;
665 break;
666 }
667 skipnext = true;
668 }
669 }
670 if (isWboson) return WBoson;
671 if (isZboson) return ZBoson;
672 }
673 if (numOfParents == 2 ) {
674 //--Sherpa Z->mumu
675 if ((numberOfChildren - NumOfquark - NumOfgluon) == 2 && NumOfMuPl == 1 && NumOfMuMin == 1) return ZBoson;
676
677 //--Sherpa W->munu ??
678 // if(numOfParents==2&&(numberOfChildren-NumOfquark-NumOfgluon)==2&&(NumOfEl==1||NumOfPos==1)&&NumOfElNeut==1) return WBoson;
679 if ((numberOfChildren - NumOfquark - NumOfgluon) == 2 && (NumOfMuPl == 1 || NumOfMuMin == 1) && NumOfMuNeut == 1) return WBoson;
680
681 const int pdg1 = partProdVtx->incomingParticle(0)->pdgId();
682 const int pdg2 = partProdVtx->incomingParticle(1)->pdgId();
683 //--Sherpa ZZ,ZW
684 if ((numberOfChildren - NumOfquark - NumOfgluon) == 4 &&
685 (NumOfEl + NumOfPos + NumOfMuPl + NumOfMuMin + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 4) &&
686 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return DiBoson;
687
688 //--Sherpa VVV -- Note, have to allow for prompt photon radiation or these get lost
689 if ((numberOfChildren - NumOfquark - NumOfgluon - NumOfPhot) == 6 &&
690 (NumOfEl + NumOfPos + NumOfMuPl + NumOfMuMin + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 6) &&
691 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return MultiBoson;
692 }
693
694 //--New Sherpa Z->mumu
695 if (partProdVtx == ancestorProdVtx) {
696 int NumOfMuLoop = 0;
697 int NumOfMuNeuLoop = 0;
698 int NumOfLepLoop = 0;
699 for (const auto & pout: partProdVtx->particles_out()) {
700 if (!pout) continue;
701 for (const auto & pin: partProdVtx->particles_in()) {
702 if (!pin) continue;
703 if (HepMC::is_same_particle(pout,pin)) {
704 if (MC::isMuon(pout)) NumOfMuLoop++;
705 if (std::abs(pout->pdg_id()) == MC::NU_MU) NumOfMuNeuLoop++;
706 if (MC::isSMLepton(pout)) NumOfLepLoop++;
707 break; // break out of inner loop after having found two matching particles
708 }
709 }
710 }
711 if (NumOfMuLoop == 2 && NumOfMuNeuLoop == 0) return ZBoson;
712 if (NumOfMuLoop == 1 && NumOfMuNeuLoop == 1) return WBoson;
713 if ((NumOfMuLoop == 4 && NumOfMuNeuLoop == 0) || (NumOfMuLoop == 3 && NumOfMuNeuLoop == 1) ||
714 (NumOfMuLoop == 2 && NumOfMuNeuLoop == 2)) return DiBoson;
715 if (NumOfLepLoop == 4) return DiBoson;
716 }
717
718 //-- McAtNLo
719
720 if (MC::isHiggs(ancestorPDG)) return Higgs;
721
722 if (MC::isMSSMHiggs(ancestorPDG)) return HiggsMSSM; // MSSM Higgs bosons
723
724 if (MC::isHeavyBoson(ancestorPDG)) return HeavyBoson; // Heavy bosons( Z', Z'', W'+)
725
726 if (std::abs(ancestorPDG) == MC::WBOSON_LRSM) return WBosonLRSM; // Left-right symmetric model WBoson (Pythia-specific)
727 if (std::abs(ancestorPDG) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
728 if (std::abs(ancestorPDG) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
729 if (std::abs(ancestorPDG) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
730 if (MC::isLeptoQuark(ancestorPDG) || NumOfLQ != 0) return LQ;
731 if (MC::isSUSY(ancestorPDG)) return SUSY;
732 if (MC::isBSM(ancestorPDG)) return OtherBSM;
733
734 const ParticleType pType = defTypeOfHadron(ancestorPDG);
735 if ((pType == BBbarMesonPart || pType == CCbarMesonPart) && ancestorProdVtx && MC::isHardScatteringVertex(ancestorProdVtx)) isPrompt = true;
736
737 return convHadronTypeToOrig(pType, ancestorPDG);
738}
@ PionDecay
@ KaonDecay
ParticleOutCome defOutComeOfMuon(T thePart)
static const int KPLUS

◆ defOrigOfNeutrino()

ParticleOrigin MCTruthClassifier::defOrigOfNeutrino ( const xAOD::TruthParticleContainer & xTruthParticleContainer,
const xAOD::TruthParticle * thePart,
bool & isPrompt,
MCTruthPartClassifier::Info & info ) const
private

Definition at line 1177 of file MCTruthClassifierGen.cxx.

1181{
1182 ATH_MSG_DEBUG("Executing DefOrigOfNeutrino ");
1183
1184 const int nuFlav = std::abs(thePart->pdgId());
1185 // Find the first copy of this particle stored in the xAOD::TruthParticleContainer (i.e. the particle prior to any interactions)
1186 const xAOD::TruthParticle* thePriPart = MC::findMatching(xTruthParticleContainer, thePart);
1187 if (!thePriPart) return NonDefined;
1188 if (std::abs(thePriPart->pdgId()) != nuFlav) return NonDefined; // FIXME should this be if (!MC::isSMNeutrino(thePriPart) || abs(thePriPart->pdgId()) != nuFlav) return NonDefined; // (Use MC::isNeutrino if 4th generation neutrinos OK)
1189
1190 //-- to define neutrino outcome status
1191 info.particleOutCome = NonInteract;
1192
1193 const xAOD::TruthVertex* partProdVtx = thePriPart->hasProdVtx() ? thePriPart->prodVtx() : nullptr;
1194 if (!partProdVtx) return NonDefined;
1195
1196 if (partProdVtx->nIncomingParticles() > 1) ATH_MSG_DEBUG("DefOrigOfNeutrino:: neutrino has more than one parent.");
1197
1198 const xAOD::TruthParticle* ancestor = MC::findMother(thePriPart);
1199 info.setMotherProperties(ancestor);
1200 if (!ancestor) { return NonDefined; } // ancestor is not a nullptr beyond this point
1201
1202 // Start of method 3 of protecting against loops
1203 // to resolve Sherpa loop
1204 bool samePart = TruthLoopDetectionMethod1(partProdVtx, ancestor);
1205 // End of method 3 of protecting against loops
1206
1207 if ((std::abs(ancestor->pdgId()) == nuFlav || MC::isTau(ancestor) || MC::isW(ancestor)) && ancestor->hasProdVtx() && !samePart) {
1208 int pPDG(0);
1209 const xAOD::TruthParticle* ancestorParent{};
1210 do {
1211 pPDG = 0;
1212 ancestorParent = MC::findMother(ancestor);
1213 // Start of method 2 of protecting against loops
1214 // to prevent Sherpa loop
1215 if (TruthLoopDetectionMethod2(ancestor,ancestorParent)) {
1216 ancestorParent = ancestor;
1217 break;
1218 }
1219 //
1220 if (ancestorParent) {
1221 pPDG = ancestorParent->pdgId(); // FIXME difference in behaviour compared to defOrigOfElectron/Muon pPDG set even if we are in a loop
1222 }
1223 // to prevent Sherpa loop
1224 if (ancestor == ancestorParent) { break; }
1225 // End of method 2 of protecting against Sherpa loops
1226 if (std::abs(pPDG) == nuFlav || MC::isTau(pPDG) || MC::isW(pPDG) ) {
1227 // There will be another iteration so set ancestor to ancestorParent
1228 ancestor = ancestorParent; // ancestorParent is not a nullptr
1229 info.setMotherProperties(ancestor); // FIXME difference in behaviour compared to MCTruthClassifier::defOrigOfElectron/Muon
1230 }
1231
1232 } while ((std::abs(pPDG) == nuFlav || MC::isTau(pPDG) || MC::isW(pPDG)));
1233
1234 if (std::abs(pPDG) == nuFlav || MC::isTau(pPDG) || MC::isW(pPDG) || MC::isZ(pPDG) || MC::isHiggs(pPDG) ||
1235 MC::isMSSMHiggs(pPDG) || MC::isHeavyBoson(pPDG) || MC::isTop(pPDG) || // MSSM Higgs bosons, Heavy bosons( Z', Z'', W'+)
1236 std::abs(pPDG) == MC::WBOSON_LRSM || MC::isNeutrinoRH(pPDG) || // Left-right symmetric model WBoson || Right-handed neutrino (Pythia-specific)
1237 MC::isSUSY(pPDG)) {
1238 ancestor = ancestorParent; // ancestorParent is not nullptr here
1239 info.setMotherProperties(ancestor);
1240 }
1241 }
1242 //if ancestor is still nullptr, we have a problem
1243 if (!ancestor) return NonDefined; // FIXME it should not be possible for ancestor to be nullptr at this point???
1244
1245 info.setMotherProperties(ancestor);
1246 const int ancestorPDG = ancestor->pdgId();
1247 partProdVtx = ancestor->decayVtx();
1248 const xAOD::TruthVertex* ancestorProdVtx = ancestor->hasProdVtx() ? ancestor->prodVtx() : nullptr;
1249 const int numOfParents = partProdVtx->nIncomingParticles();
1250 const int numberOfChildren = partProdVtx->nOutgoingParticles();
1251
1252 // Determine decay products
1253 auto DP = DecayProducts(partProdVtx);
1254 const int NumOfPhot = DP.pd(MC::PHOTON);
1255 const int NumOfquark = DP.apd({MC::DQUARK,MC::UQUARK,MC::SQUARK,MC::CQUARK,MC::BQUARK,MC::TQUARK});
1256 const int NumOfgluon = DP.apd(MC::GLUON);
1257 const int NumOfLQ = DP.apd(MC::LEPTOQUARK);
1258 const int NumOfElNeut = DP.apd(MC::NU_E);
1259 const int NumOfMuNeut = DP.apd(MC::NU_MU);
1260 const int NumOfTauNeut = DP.apd(MC::NU_TAU);
1261 const int NumOfEl = DP.apd(MC::ELECTRON);
1262 const int NumOfMu = DP.apd(MC::MUON);
1263 const int NumOfTau = DP.apd(MC::TAU);
1264
1265 samePart = false;
1266 for (const auto& aChild: partProdVtx->particles_out()) {
1267 if (!aChild) continue;
1268 if (aChild->pdgId() == ancestorPDG && HepMC::is_same_generator_particle(aChild,ancestor)) {
1269 samePart = true;
1270 break;
1271 }
1272 }
1273 // End of section determining decay products
1274
1275 // Quark weak decay
1276 if (MC::isQuark(ancestorPDG) && numOfParents == 1 && numberOfChildren == 3 && NumOfquark == 1 && (NumOfEl == 1 || NumOfMu == 1 || NumOfTau == 1)) return QuarkWeakDec;
1277 if (MC::isTop(ancestorPDG)) return top;
1278
1279 if (MC::isW(ancestorPDG) && ancestorProdVtx && ancestorProdVtx->nIncomingParticles() != 0) {
1280 const xAOD::TruthVertex* prodVert = ancestorProdVtx;
1281 const xAOD::TruthParticle* ptrPart;
1282 do {
1283 ptrPart = prodVert->incomingParticle(0); // FIXME just taking the first one
1284 prodVert = ptrPart->hasProdVtx() ? ptrPart->prodVtx() : nullptr;
1285 } while (MC::isW(ptrPart) && prodVert);
1286
1287 if (prodVert && prodVert->nIncomingParticles() == 1) {
1288 if (std::abs(ptrPart->pdgId()) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
1289 if (std::abs(ptrPart->pdgId()) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
1290 if (std::abs(ptrPart->pdgId()) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
1291 }
1292 return WBoson;
1293 }
1294 if (MC::isW(ancestorPDG)) return WBoson;
1295 if (MC::isZ(ancestorPDG)) return ZBoson;
1296
1297 //-- Exotics
1298
1299 // MadGraphPythia ZWW*->lllnulnu or ZWW*->nunulnulnu (don't even know if the latter is generated)
1300 if (numOfParents == 1 && numberOfChildren > 4 && (MC::isSMQuark(ancestorPDG) || MC::isGluon(ancestorPDG))) {
1301
1302 const xAOD::TruthParticle* thePartToCheck = thePriPart;
1303 const xAOD::TruthParticle* theParent = thePriPart->hasProdVtx() ? thePriPart->prodVtx()->incomingParticle(0) : nullptr; // FIXME just taking the first one
1304
1305 if (MC::isElectron(theParent) && MC::isDecayed(theParent)) { thePartToCheck = theParent; }
1306 bool isZboson = false;
1307 bool isWboson = false;
1308 bool skipnext = false;
1309
1310 for (unsigned int ipOut = 0; ipOut + 1 < partProdVtx->nOutgoingParticles(); ++ipOut) {
1311 const xAOD::TruthParticle* aChild = partProdVtx->outgoingParticle(ipOut);
1312 if (!aChild) continue;
1313 const xAOD::TruthParticle* theNextChild{};
1314 for (unsigned int ipOut1 = ipOut + 1; ipOut1 < partProdVtx->nOutgoingParticles(); ipOut1++) {
1315 theNextChild = partProdVtx->outgoingParticle(ipOut1);
1316 if (theNextChild) break;
1317 }
1318 if (!theNextChild) continue;
1319
1320 if (skipnext) {
1321 skipnext = false;
1322 continue;
1323 }
1324
1325 const int apdgID1 = std::abs(aChild->pdgId());
1326 const int apdgID2 = std::abs(theNextChild->pdgId());
1327 if (apdgID1 == apdgID2 && MC::isSMNeutrino(apdgID1)) {
1328 // Zboson
1329 if (thePartToCheck == aChild || thePartToCheck == theNextChild) {
1330 isZboson = true;
1331 break;
1332 }
1333 skipnext = true;
1334 } else if ((apdgID1 == MC::ELECTRON && apdgID2 == MC::NU_E) ||
1335 (apdgID1 == MC::NU_E && apdgID2 == MC::ELECTRON) ||
1336 (apdgID1 == MC::MUON && apdgID2 == MC::NU_MU) ||
1337 (apdgID1 == MC::NU_MU && apdgID2 == MC::MUON) ||
1338 (apdgID1 == MC::TAU && apdgID2 == MC::NU_TAU) ||
1339 (apdgID1 == MC::NU_TAU && apdgID2 == MC::TAU)
1340 ) {
1341 // WBoson
1342 if (thePartToCheck == aChild || thePartToCheck == theNextChild) {
1343 isWboson = true;
1344 break;
1345 }
1346 skipnext = true;
1347 }
1348 }
1349 if (isWboson) return WBoson;
1350 if (isZboson) return ZBoson;
1351 }
1352
1353 if (numOfParents == 2) {
1354 //--Sherpa Z->nunu
1355 if ( (numberOfChildren - NumOfquark - NumOfgluon) == 2 && (NumOfElNeut == 2 || NumOfMuNeut == 2 || NumOfTauNeut == 2)) return ZBoson;
1356
1357 //--Sherpa W->enu ??
1358 if ((numberOfChildren - NumOfquark - NumOfgluon) == 2 && ((NumOfEl == 1 && NumOfElNeut == 1) || (NumOfMu == 1 && NumOfMuNeut == 1) || (NumOfTau == 1 && NumOfTauNeut == 1))) return WBoson;
1359
1360 const int pdg1 = partProdVtx->incomingParticle(0)->pdgId();
1361 const int pdg2 = partProdVtx->incomingParticle(1)->pdgId();
1362 //--Sherpa ZZ,ZW
1363 if ( (numberOfChildren - NumOfquark - NumOfgluon) == 4 && (NumOfEl + NumOfMu + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 4) &&
1364 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return DiBoson;
1365
1366 //--Sherpa VVV -- Note, have to allow for prompt photon radiation or these get lost
1367 if ((numberOfChildren - NumOfquark - NumOfgluon - NumOfPhot) == 6 && (NumOfEl + NumOfMu + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 6) &&
1368 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return MultiBoson;
1369 }
1370
1371 // New Sherpa Z->nunu
1372 if (partProdVtx == ancestorProdVtx) {
1373 int NumOfLepLoop = 0;
1374 int NumOfNeuLoop = 0;
1375 for (const auto *const pout: partProdVtx->particles_out()) {
1376 if (!pout) continue;
1377 for (const auto *const pin: partProdVtx->particles_in()) {
1378 if (!pin) continue;
1379 if (HepMC::is_same_particle(pin,pout)) continue;
1380 const int apdgid = std::abs(pout->pdgId());
1381 if (MC::isSMLepton(apdgid)) {
1382 if (MC::isSMNeutrino(apdgid)) { NumOfNeuLoop++; }
1383 else { NumOfLepLoop++; }
1384 }
1385 break; // break out of inner loop after having found two matching particles
1386 }
1387 }
1388 if (NumOfNeuLoop == 2 && NumOfLepLoop == 0) return ZBoson;
1389 if (NumOfNeuLoop == 1 && NumOfLepLoop == 1) return WBoson;
1390 if (NumOfNeuLoop + NumOfLepLoop == 4) return DiBoson;
1391 }
1392
1393 //-- McAtNLo
1394
1395 if (MC::isHiggs(ancestorPDG)) return Higgs;
1396 if (MC::isMSSMHiggs(ancestorPDG)) return HiggsMSSM; // MSSM Higgs bosons
1397 if (MC::isHeavyBoson(ancestorPDG)) return HeavyBoson; // Heavy bosons( Z', Z'', W'+)
1398
1399 if (MC::isTau(ancestorPDG)) {
1400 const ParticleOrigin tauOrig = defOrigOfTau(xTruthParticleContainer, ancestor, ancestorPDG, info);
1401 const ParticleType tautype = defTypeOfTau(tauOrig);
1402 return (tautype == IsoTau)?tauOrig:TauLep;
1403 }
1404
1405 if (std::abs(ancestorPDG) == MC::WBOSON_LRSM) return WBosonLRSM; // Left-right symmetric model WBoson (Pythia-specific)
1406 if (std::abs(ancestorPDG) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
1407 if (std::abs(ancestorPDG) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
1408 if (std::abs(ancestorPDG) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
1409 if (MC::isLeptoQuark(ancestorPDG) || NumOfLQ != 0) return LQ;
1410 if (MC::isSUSY(ancestorPDG)) return SUSY;
1411 if (MC::isBSM(ancestorPDG)) return OtherBSM;
1412
1413 const ParticleType pType = defTypeOfHadron(ancestorPDG);
1414 if ((pType == BBbarMesonPart || pType == CCbarMesonPart) && ancestorProdVtx && MC::isHardScatteringVertex(ancestorProdVtx)) isPrompt = true;
1415
1416 return convHadronTypeToOrig(pType, ancestorPDG);
1417}
@ NonInteract
bool isSMNeutrino(const T &p)

◆ defOrigOfPhoton()

ParticleOrigin MCTruthClassifier::defOrigOfPhoton ( const xAOD::TruthParticleContainer & xTruthParticleContainer,
const xAOD::TruthParticle * thePart,
bool & isPrompt,
MCTruthPartClassifier::Info & info ) const
private

Definition at line 914 of file MCTruthClassifierGen.cxx.

918{
919 if (!thePart) return NonDefined; // FIXME Why is this extra protection needed for this function and not the others?
920 ATH_MSG_DEBUG("Executing DefOrigOfPhoton ");
921
922 info.resetMotherProperties();
923 info.photonMother = nullptr;
924
925 // Find the first copy of this particle stored in the xAOD::TruthParticleContainer (i.e. the particle prior to any interactions)
926 const xAOD::TruthParticle* thePriPart = MC::findMatching(xTruthParticleContainer, thePart);
927 if (!thePriPart) return NonDefined;
928 if (!MC::isPhoton(thePriPart)) return NonDefined;
929
930 const xAOD::TruthVertex* partProdVtx = thePriPart->hasProdVtx() ? thePriPart->prodVtx() : nullptr;
931
932 //-- to define photon outcome status
933 info.particleOutCome = defOutComeOfPhoton(thePriPart);
934
935 if (!partProdVtx) return NonDefined;
936
937 int numOfParents = partProdVtx->nIncomingParticles();
938 if (partProdVtx->nIncomingParticles() > 1) ATH_MSG_DEBUG("DefOrigOfPhoton:: photon has more than one parent.");
939
940 const xAOD::TruthParticle* ancestor = MC::findMother(thePriPart);
941 info.setMotherProperties(ancestor);
942 if (!ancestor) { return NonDefined; } // ancestor is not a nullptr beyond this point
943
944 int ancestorPDG = ancestor->pdgId();
945 // "method 1" for finding Sherpa loops from defOrigOfElectron not used here. Why?
946 const xAOD::TruthVertex* ancestorProdVtx = ancestor->hasProdVtx() ? ancestor->prodVtx() : nullptr;
947
948 partProdVtx = ancestor->decayVtx(); // FIXME how often does this line actually change the pointer???
949 numOfParents = partProdVtx->nIncomingParticles();
950
951 const int numberOfChildren = partProdVtx->nOutgoingParticles();
952
953 // Determine decay products
954 auto DP = DecayProducts(partProdVtx);
955 const int NumOfEl = DP.pd(MC::ELECTRON);
956 const int NumOfPos = DP.pd(MC::POSITRON);
957 const int NumOfMu = DP.apd(MC::MUON);
958 const int NumOfTau = DP.apd(MC::TAU);
959 const int NumOfLQ = DP.apd(MC::LEPTOQUARK);
960 const int NumOfLep = NumOfEl + NumOfPos + NumOfMu + NumOfTau;
961 const int NumOfNeut = DP.apd({MC::NU_E,MC::NU_MU,MC::NU_TAU});
962 const int NumOfPht = DP.pd(MC::PHOTON);
963
964 int childPDG(0);
965 int NumOfPartons(0);
966 int NumOfNucFr(0);
967 const bool possibleNuclearFragment = (numOfParents == 1 && (MC::isPhoton(ancestorPDG) || MC::isElectron(ancestorPDG) || std::abs(ancestorPDG) == MC::PIPLUS));
968 const xAOD::TruthParticle* child{};
969 for (const auto& pout: partProdVtx->particles_out()) {
970 if (!pout) continue;
971 childPDG = pout->pdg_id();
972 if (possibleNuclearFragment &&
973 (MC::isNucleus(childPDG) || childPDG == 0 || childPDG == MC::PROTON || childPDG == MC::NEUTRON)) { // FIXME Do we really expect particles with PDG_ID = 0 in the truth record?
974 NumOfNucFr++;
975 }
976 if (std::abs(childPDG) < MC::ELECTRON ||
977 (std::abs(childPDG) > MC::NU_TAU && std::abs(childPDG) < 43 && !MC::isPhoton(childPDG))) {
978 // FIXME Too loose? This definition picks up 4th generation quarks and leptons as well as all gauge bosons and leptoquarks.
979 // Suggest MC::isSMQuark(childPDG) || (MC::isBoson(childPDG) && !MC::isPhoton(childPDG))
980 // or maybe even MC::isSMQuark(childPDG) || MC::isGluon(childPDG)
981 // AKA const int NumOfPartons = DP.apd({MC::DQUARK,MC::UQUARK,MC::SQUARK,MC::CQUARK,MC::BQUARK,MC::TQUARK,MC::GLUON});
982 NumOfPartons++;
983 }
984 if (childPDG == ancestorPDG) {
985 child = pout;
986 }
987 }
988 // End of section determining decay products
989
990 bool foundISR = false;
991 bool foundFSR = false;
992 if (numOfParents == 1 && numberOfChildren == 2 && child && HepMC::is_same_generator_particle(child, ancestor)) return BremPhot;
993 if (numOfParents == 1 && numberOfChildren == 2 && MC::isElectron(ancestorPDG) && NumOfPht == 2) return ElMagProc;
994
995 // decay of W,Z and Higgs to lepton with FSR generated by Pythia
996 if (numOfParents == 1 && numberOfChildren == 2 && (MC::isElectron(ancestorPDG) || MC::isMuon(ancestorPDG) || MC::isTau(ancestorPDG)) &&
997 !(child && HepMC::is_same_generator_particle(child, ancestor)) && ancestorProdVtx &&
998 ancestorProdVtx->nIncomingParticles() == 1) {
999 int itr = 0;
1000 int PartPDG = 0;
1001 const xAOD::TruthVertex* prodVert = ancestorProdVtx;
1002 const xAOD::TruthVertex* Vert{};
1003 do {
1004 Vert = prodVert;
1005 for (const auto & pin: Vert->particles_in()) {
1006 if (!pin) continue;
1007 PartPDG = std::abs(pin->pdgId());
1008 prodVert = pin->prodVtx();
1009 if (MC::isZ(PartPDG) || MC::isW(PartPDG) || MC::isHiggs(PartPDG)) foundFSR = true;
1010 }
1011 itr++;
1012 if (itr > 100) { // FIXME Improve loop detection here?
1013 ATH_MSG_WARNING("DefOrigOfPhoton:: infinite while");
1014 break;
1015 }
1016 } while (prodVert && std::abs(ancestorPDG) == PartPDG);
1017
1018 if (foundFSR) return FSRPhot;
1019 }
1020
1021 // Nucl reaction
1022 // gamma+Nuclear=>gamma+Nucl.Fr+Nuclons+pions
1023 // e+Nuclear=>e+gamma+Nucl.Fr+Nuclons+pions
1024 // pi+Nuclear=>gamma+Nucl.Fr+Nuclons+pions
1025
1026 if ((numOfParents == 1 && (MC::isPhoton(ancestorPDG) || MC::isElectron(ancestorPDG)) && numberOfChildren > 2 && NumOfNucFr != 0) ||
1027 (numOfParents == 1 && std::abs(ancestorPDG) == MC::PIPLUS && numberOfChildren > 10 && NumOfNucFr != 0) ||
1028 (numOfParents == 1 && MC::isPhoton(ancestorPDG) && numberOfChildren > 10 && MC::isStable(ancestor)) ||
1029 (numOfParents == 1 && MC::isNucleus(ancestorPDG) && std::abs(ancestorPDG) != MC::PROTON)) // FIXME vetoing protons here to preserve previous behaviour
1030 return NucReact;
1031
1032 if (MC::isMuon(ancestorPDG) && NumOfMu == 0) return Mu;
1033 if (MC::isTau(ancestorPDG) && NumOfTau == 0) return TauLep;
1034
1035 if (numOfParents == 1 && ancestor->status() == 3) return (foundISR)? ISRPhot:UndrPhot; // FIXME foundISR is always false at this point
1036
1037 //-- to find initial and final state raiation and underline photons
1038 //-- SUSY
1039 if (numOfParents == 1 && (MC::isSMQuark(ancestorPDG) || MC::isGluon(ancestorPDG)) &&
1040 (numberOfChildren != NumOfPht + NumOfPartons || !MC::Pythia8::isConditionA(ancestor))) {
1041 for (const auto& pout: partProdVtx->particles_out()) {
1042 if (!pout) continue;
1043 if (ancestorPDG != pout->pdgId()) continue;
1044 const xAOD::TruthVertex* Vrtx = pout->decayVtx();
1045 if (!Vrtx) continue;
1046 if (Vrtx->nOutgoingParticles() != 1 && Vrtx->nIncomingParticles() == 1) continue;
1047 if (!Vrtx->outgoingParticle(0)) continue;
1048 if (Vrtx->outgoingParticle(0)->pdgId() == 91) foundISR = true; // Herwig "cluster"
1049 }
1050 return (foundISR)?ISRPhot:UndrPhot;
1051 }
1052
1053 //-- to find final state radiation
1054 //-- Exotics
1055
1056 // FSR from Photos
1057 //-- Exotics- CompHep
1058 if (numOfParents == 2 && ((MC::isElectron(ancestorPDG) && NumOfEl == 1 && NumOfPos == 1) || (MC::isMuon(ancestorPDG) && NumOfMu == 2) || (MC::isTau(ancestorPDG) && NumOfTau == 2))) {
1059 if (std::abs(partProdVtx->incomingParticle(0)->pdgId()) == std::abs(partProdVtx->incomingParticle(1)->pdgId())) return FSRPhot;
1060 }
1061
1062 if (numOfParents == 2 && NumOfLep == 1 && NumOfNeut == 1 && (MC::isElectron(ancestorPDG) || std::abs(ancestorPDG) == MC::NU_E)) return FSRPhot;
1063
1064 //-- Exotics - CompHep
1065 if (MC::isElectron(ancestorPDG) && numOfParents == 1 && numberOfChildren == 2 && (NumOfEl == 1 || NumOfPos == 1) && NumOfPht == 1 &&
1066 !( child && HepMC::is_same_generator_particle(child, ancestor)) && !HepMC::is_simulation_particle(child) && !HepMC::is_simulation_particle(ancestor))
1067 return FSRPhot;
1068
1069 // FSR from Photos
1070 if (MC::isZ(ancestorPDG) && ((NumOfEl + NumOfPos == 2 || NumOfEl + NumOfPos == 4) || (NumOfMu == 2 || NumOfMu == 4) || (NumOfTau == 2 || NumOfTau == 4)) && NumOfPht > 0) return FSRPhot;
1071
1072 if (NumOfPht > 0 && (std::abs(ancestorPDG) == MC::WBOSON_LRSM || MC::isNeutrinoRH(ancestorPDG))) return FSRPhot; // Left-right symmetric model WBoson || Right-handed neutrinos (Pythia-specific)
1073
1074 if (numOfParents == 2 && NumOfLQ == 1) return FSRPhot;
1075
1076 //--- other process
1077
1078 if (MC::isZ(ancestorPDG)) return ZBoson;
1079 if (MC::isW(ancestorPDG)) {
1080
1081 if (NumOfLep == 1 && NumOfNeut == 1 && numberOfChildren == NumOfLep + NumOfNeut + NumOfPht) return FSRPhot;
1082
1083 if (ancestorProdVtx && ancestorProdVtx->nIncomingParticles() != 0) {
1084 const xAOD::TruthVertex* prodVert = ancestorProdVtx;
1085 const xAOD::TruthParticle* itrP;
1086 do {
1087 itrP = prodVert->incomingParticle(0); // FIXME just taking the first one
1088 prodVert = itrP->hasProdVtx() ? itrP->prodVtx() : nullptr;
1089 } while (MC::isW(itrP) && prodVert);
1090
1091 if (prodVert && prodVert->nIncomingParticles() == 1 ) {
1092 if ( MC::isTau(itrP)) return TauLep;
1093 if ( MC::isMuon(itrP)) return Mu;
1094 if ( std::abs(itrP->pdgId()) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
1095 if ( std::abs(itrP->pdgId()) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
1096 if ( std::abs(itrP->pdgId()) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
1097 }
1098 } else
1099 return WBoson;
1100 }
1101
1102 // MadGraphPythia ZWW*->lllnulnu
1103 if (numOfParents == 1 && numberOfChildren > 4 && (MC::isSMQuark(ancestorPDG) || MC::isGluon(ancestorPDG))) {
1104 bool isZboson = false;
1105 bool isWboson = false;
1106 bool skipnext = false;
1107 for (unsigned int ipOut = 0; ipOut + 1 < partProdVtx->nOutgoingParticles(); ipOut++) {
1108 if (skipnext) {
1109 skipnext = false;
1110 continue;
1111 }
1112 const xAOD::TruthParticle* aChild = partProdVtx->outgoingParticle(ipOut);
1113 if (!aChild) continue;
1114 const xAOD::TruthParticle* theNextChild{};
1115 for (unsigned int ipOut1 = ipOut + 1; ipOut1 < partProdVtx->nOutgoingParticles(); ipOut1++) {
1116 theNextChild = partProdVtx->outgoingParticle(ipOut1);
1117 if (theNextChild) break;
1118 }
1119 if (!theNextChild) continue;
1120 if (MC::isTau(aChild) && MC::isTau(theNextChild)) {
1121 // Zboson
1122 if (thePriPart == aChild || thePriPart == theNextChild) {
1123 isZboson = true;
1124 break;
1125 }
1126 skipnext = true;
1127 } else if (MC::isTau(aChild) && std::abs(theNextChild->pdgId()) == MC::NU_TAU) {
1128 // WBoson
1129 if (thePriPart == aChild || thePriPart == theNextChild) {
1130 isWboson = true;
1131 break;
1132 }
1133 skipnext = true;
1134 }
1135 }
1136 if (isWboson) return WBoson;
1137 if (isZboson) return ZBoson;
1138 }
1139
1140 //--Sherpa ZZ,ZW+FSR
1141 if (numOfParents == 4 && (numberOfChildren - NumOfPht) == 4 && (NumOfLep + NumOfNeut == 4)) {
1142 if (MC::isSMLepton(partProdVtx->incomingParticle(0))&&MC::isSMLepton(partProdVtx->incomingParticle(1))
1143 && MC::isSMLepton(partProdVtx->incomingParticle(2))&&MC::isSMLepton(partProdVtx->incomingParticle(3)))
1144 return FSRPhot;
1145 }
1146
1147 //--New Sherpa single photon
1148 if (partProdVtx == ancestorProdVtx) {
1149 for (const auto *const pout: partProdVtx->particles_out()) {
1150 if (!pout) continue;
1151 for (const auto *const pin: partProdVtx->particles_in()) {
1152 if (!pin) continue;
1153 if (!HepMC::is_same_particle(pout,pin)) continue;
1154 if (MC::isPhoton(pout)) return SinglePhot;
1155 break; // break out of inner loop after having found two matching particles
1156 }
1157 }
1158 }
1159
1160 if (MC::isHiggs(ancestorPDG)) return Higgs;
1161 if (std::abs(ancestorPDG) == MC::PI0) return PiZero;
1162 if (MC::isMSSMHiggs(ancestorPDG)) return HiggsMSSM; // MSSM Higgs bosons
1163 if (MC::isHeavyBoson(ancestorPDG) || std::abs(ancestorPDG) == 5100039 ) return HeavyBoson; // Heavy Bosons (Z' Z'' W'+) + KK excited graviton
1164
1165 if (MC::isSUSY(ancestorPDG)) return SUSY;
1166 if (MC::isBSM(ancestorPDG)) return OtherBSM;
1167
1168 // Pythia8 gamma+jet samples
1169 if (MC::Pythia8::isConditionA(ancestor) && MC::isStable(thePriPart) && NumOfPht == 1 && numberOfChildren == (NumOfPht + NumOfPartons)) return PromptPhot;
1170
1171 const ParticleType pType = defTypeOfHadron(ancestorPDG);
1172 if ((pType == BBbarMesonPart || pType == CCbarMesonPart) && ancestorProdVtx && MC::isHardScatteringVertex(ancestorProdVtx)) isPrompt = true;
1173 return convHadronTypeToOrig(pType, ancestorPDG);
1174}
#define ATH_MSG_WARNING(x)
@ UndrPhot
@ BremPhot
@ ISRPhot
@ PiZero
@ PromptPhot
@ FSRPhot
@ NucReact
@ SinglePhot
int status() const
Status code.
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...
ParticleOutCome defOutComeOfPhoton(T thePart)
bool isConditionA(const T &p)
To be understood.
bool isStable(const T &p)
Identify if the particle is stable, i.e. has not decayed.

◆ defOrigOfTau()

ParticleOrigin MCTruthClassifier::defOrigOfTau ( const xAOD::TruthParticleContainer & xTruthParticleContainer,
const xAOD::TruthParticle * thePart,
int motherPDG,
MCTruthPartClassifier::Info & info ) const
private

Definition at line 741 of file MCTruthClassifierGen.cxx.

745{
746 ATH_MSG_DEBUG("Executing DefOrigOfTau ");
747
748 // Find the first copy of this particle stored in the xAOD::TruthParticleContainer (i.e. the particle prior to any interactions)
749 const xAOD::TruthParticle* thePriPart = MC::findMatching(xTruthParticleContainer, thePart);
750 if (!thePriPart) return NonDefined;
751 if (!MC::isTau(thePriPart)) return NonDefined;
752
753 //-- to define tau outcome status
754 if (MC::isPhysical(thePriPart)) info.particleOutCome = defOutComeOfTau(thePriPart); // FIXME why do we need the additional check on MC::isPhysical here c.f. defOrigOfElectron and defOrigOfMuon?
755
756 const xAOD::TruthVertex* partProdVtx = thePriPart->hasProdVtx() ? thePriPart->prodVtx() : nullptr;
757 if (!partProdVtx) return NonDefined;
758
759 if (partProdVtx->nIncomingParticles() > 1) ATH_MSG_DEBUG("DefOrigOfTau:: tau has more than one parent.");
760
761 const xAOD::TruthParticle* ancestor = MC::findMother(thePriPart);
762 info.setMotherProperties(ancestor);
763 if (!ancestor) { return NonDefined; } // ancestor is not a nullptr beyond this point
764
765 // "method 1" for finding Sherpa loops from defOrigOfElectron not used here. Why?
766
767 // Difference from defOrigOfElectron and defOrigOfMuon - no loop through ancestor particles
768
769 if (MC::isW(ancestorPDGin) && ancestor->hasProdVtx()) { // FIXME ancestorPDGin here could in principle be inconsistent with ancestorProdVtx
770 const xAOD::TruthParticle* ancestorParent = MC::findMother(ancestor);
771 if (ancestorParent && MC::isTop(ancestorParent->pdgId())) {
772 ancestor = ancestorParent; //...so ancestor cannot be nullptr
773 }
774 }
775
776 const int ancestorPDG = ancestor->pdgId();
777 info.setMotherProperties(ancestor);
778 const xAOD::TruthVertex* ancestorProdVtx = ancestor->hasProdVtx() ? ancestor->prodVtx() : nullptr;
779 partProdVtx = ancestor->decayVtx();
780 if (!partProdVtx) return NonDefined; // FIXME not sure this could ever be true?
781 const int numOfParents = partProdVtx->nIncomingParticles();
782
783 // Determine decay products
784 auto DP = DecayProducts(partProdVtx);
785 const int numberOfChildren = DP.size();
786 const int NumOfPhot = DP.pd(MC::PHOTON);
787 const int NumOfEl = DP.pd(MC::ELECTRON);
788 const int NumOfPos = DP.pd(MC::POSITRON);
789 const int NumOfElNeut = DP.apd(MC::NU_E);
790 const int NumOfMuNeut = DP.apd(MC::NU_MU);
791 /* const int NumOfLQ = DP.apd(MC::LEPTOQUARK); */ // FIXME Leptoquarks not an option?
792 const int NumOfquark = DP.apd({MC::DQUARK,MC::UQUARK,MC::SQUARK,MC::CQUARK,MC::BQUARK,MC::TQUARK});
793 const int NumOfgluon = DP.apd(MC::GLUON);
794 const int NumOfMuPl = DP.pd(-MC::MUON);
795 const int NumOfMuMin = DP.pd(MC::MUON);
796 const int NumOfTau = DP.apd(MC::TAU);
797 const int NumOfTauNeut = DP.apd(MC::NU_TAU);
798 // End of section determining decay products
799
800 if (MC::isTop(ancestorPDG)) return top;
801 if (MC::isW(ancestorPDG) && ancestorProdVtx && ancestorProdVtx->nIncomingParticles() != 0) {
802 const xAOD::TruthVertex* prodVert = ancestorProdVtx;
803 const xAOD::TruthParticle* itrP;
804 do {
805 itrP = prodVert->incomingParticle(0); // FIXME just taking the first one
806 prodVert = itrP->hasProdVtx() ? itrP->prodVtx() : nullptr;
807 } while (MC::isW(itrP) && prodVert);
808
809 if (prodVert && prodVert->nIncomingParticles() == 1 ) {
810 if (std::abs(itrP->pdgId()) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
811 if (std::abs(itrP->pdgId()) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
812 if (std::abs(itrP->pdgId()) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
813 }
814 return WBoson;
815 }
816 if (MC::isW(ancestorPDG)) { return WBoson;}
817 if (MC::isZ(ancestorPDG)) { return ZBoson;}
818 if (numOfParents == 1 && numberOfChildren > 4 && (MC::isSMQuark(ancestorPDG) || MC::isGluon(ancestorPDG))) {
819 bool isZboson = false;
820 bool isWboson = false;
821 bool skipnext = false;
822 for (unsigned int ipOut = 0; ipOut + 1 < partProdVtx->nOutgoingParticles(); ipOut++) {
823 if (skipnext) {
824 skipnext = false;
825 continue;
826 }
827 const xAOD::TruthParticle* aChild = partProdVtx->outgoingParticle(ipOut);
828 if (!aChild) continue;
829 const xAOD::TruthParticle* theNextChild{};
830 for (unsigned int ipOut1 = ipOut + 1; ipOut1 < partProdVtx->nOutgoingParticles(); ipOut1++) {
831 theNextChild = partProdVtx->outgoingParticle(ipOut1);
832 if (theNextChild) break;
833 }
834 if (!theNextChild) {
835 continue;
836 }
837 if (MC::isTau(aChild) && MC::isTau(theNextChild)) {
838 // Zboson
839 if (thePriPart == aChild || thePriPart == theNextChild) {
840 isZboson = true;
841 break;
842 }
843 skipnext = true;
844 } else if (MC::isTau(aChild) && std::abs(theNextChild->pdgId()) == MC::NU_TAU) {
845 // WBoson
846 if (thePriPart == aChild || thePriPart == theNextChild) {
847 isWboson = true;
848 break;
849 }
850 skipnext = true;
851 }
852 }
853 if (isWboson) return WBoson;
854 if (isZboson) return ZBoson;
855 }
856 if (numOfParents == 2 ) {
857 const int pdg1 = partProdVtx->incomingParticle(0)->pdgId();
858 const int pdg2 = partProdVtx->incomingParticle(1)->pdgId();
859 //--Sherpa Z->tautau
860 if ((numberOfChildren - NumOfquark - NumOfgluon) == 2 && NumOfTau == 2 && (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return ZBoson; // FIXME Why the extra checks on incoming particles compared to Z->ee, Z->mumu and Z->nunu?
861
862 //--Sherpa W->taunu new
863 if ((numberOfChildren - NumOfquark - NumOfgluon) == 2 && NumOfTau == 1 && NumOfTauNeut == 1) return WBoson;
864
865 //--Sherpa ZZ,ZW
866 if ((numberOfChildren - NumOfquark - NumOfgluon) == 4 &&
867 (NumOfEl + NumOfPos + NumOfMuPl + NumOfMuMin + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 4) &&
868 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return DiBoson;
869
870 //--Sherpa VVV -- Note, have to allow for prompt photon radiation or these get lost
871 if ((numberOfChildren - NumOfquark - NumOfgluon - NumOfPhot) == 6 &&
872 (NumOfEl + NumOfPos + NumOfMuPl + NumOfMuMin + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 6) &&
873 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return MultiBoson;
874 }
875
876 // New Sherpa Z->tautau
877 if (partProdVtx == ancestorProdVtx) {
878 int NumOfTauLoop = 0;
879 int NumOfTauNeuLoop = 0;
880 int NumOfLepLoop = 0;
881 for ( const auto *const pout: partProdVtx->particles_out()) {
882 if (!pout) continue;
883 for (const auto *const pin: partProdVtx->particles_in()) {
884 if (!pin) continue;
885 if (!HepMC::is_same_particle(pout,pin)) continue;
886 if (MC::isTau(pout)) NumOfTauLoop++;
887 if (std::abs(pout->pdgId()) == MC::NU_TAU) NumOfTauNeuLoop++;
888 if (MC::isSMLepton(pout)) NumOfLepLoop++;
889 break; // break out of inner loop after having found two matching particles
890 }
891 }
892 if (NumOfTauLoop == 2 && NumOfTauNeuLoop == 0) return ZBoson;
893 if (NumOfTauLoop == 1 && NumOfTauNeuLoop == 1) return WBoson;
894 if ((NumOfTauLoop == 4 && NumOfTauNeuLoop == 0) || (NumOfTauLoop == 3 && NumOfTauNeuLoop == 1) || (NumOfTauLoop == 2 && NumOfTauNeuLoop == 2)) return DiBoson;
895 if (NumOfLepLoop == 4) return DiBoson;
896 }
897
898 //-- McAtNLo
899
900 if (MC::isHiggs(ancestorPDG)) return Higgs;
901 if (MC::isMSSMHiggs(ancestorPDG)) return HiggsMSSM; // MSSM Higgs bosons
902 if (MC::isHeavyBoson(ancestorPDG)) return HeavyBoson; // Heavy bosons( Z', Z'', W'+)
903 if (std::abs(ancestorPDG) == MC::WBOSON_LRSM) return WBosonLRSM; // Left-right symmetric model WBoson (Pythia-specific)
904 if (std::abs(ancestorPDG) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
905 if (MC::isSUSY(ancestorPDG)) return SUSY;
906 if (MC::isBSM(ancestorPDG)) return OtherBSM;
907 if (std::abs(ancestorPDG) == MC::JPSI) return JPsi;
908
909 const ParticleType pType = defTypeOfHadron(ancestorPDG);
910 return convHadronTypeToOrig(pType, ancestorPDG);
911}
@ JPsi
ParticleOutCome defOutComeOfTau(T thePart)
static const int JPSI
bool isPhysical(const T &p)
Identify if the particle is physical, i.e. is stable or decayed.

◆ detEta()

double MCTruthClassifier::detEta ( double x,
double y ) const
inlineprivate

Definition at line 159 of file MCTruthClassifier.h.

159{ return std::abs(x - y); }
#define y
#define x

◆ detPhi()

double MCTruthClassifier::detPhi ( double x,
double y ) const
inlineprivate

Definition at line 160 of file MCTruthClassifier.h.

160 {
161 double det = x - y;
162 if (det > M_PI) det = det - 2. * M_PI;
163 if (det < -M_PI) det = det + 2. * M_PI;
164 return std::abs(det);
165 }
#define M_PI

◆ detStore()

const ServiceHandle< StoreGateSvc > & AthCommonDataStore< AthCommonMsg< AlgTool > >::detStore ( ) const
inlineinherited

The standard StoreGateSvc/DetectorStore Returns (kind of) a pointer to the StoreGateSvc.

Definition at line 95 of file AthCommonDataStore.h.

◆ egammaClusMatch()

const xAOD::TruthParticle * MCTruthClassifier::egammaClusMatch ( const xAOD::CaloCluster * clus,
bool isFwrdEle,
MCTruthPartClassifier::Info * info ) const
finaloverridevirtual

Implements IMCTruthClassifier.

Definition at line 44 of file MCTruthClassifierAthena.cxx.

45{
46 ATH_MSG_DEBUG("Executing egammaClusMatch ");
47 const xAOD::TruthParticle* theMatchPart = nullptr;
48 const EventContext& ctx = info ? info->eventContext : Gaudi::Hive::currentContext();
49 // retrieve collection and get a pointer
50 SG::ReadHandle<xAOD::TruthParticleContainer> truthParticleContainerReadHandle(m_truthParticleContainerKey, ctx);
51
52 if (!truthParticleContainerReadHandle.isValid()) {
53 ATH_MSG_WARNING( " Invalid ReadHandle for xAOD::TruthParticleContainer with key: " << truthParticleContainerReadHandle.key());
54 return theMatchPart;
55 }
56
57 SG::ReadCondHandle<CaloDetDescrManager> caloMgrHandle{ m_caloMgrKey, ctx };
58 if (!caloMgrHandle.isValid()) {
59 ATH_MSG_WARNING(" Invalid ReadCondHandle for CaloDetDescrManager with key: " << m_caloMgrKey.key());
60 return theMatchPart;
61 }
62
63 const CaloDetDescrManager* caloDDMgr = *caloMgrHandle;
64 const xAOD::TruthParticle* theEgamma(nullptr);
65 const xAOD::TruthParticle* theLeadingPartInCone(nullptr);
66 const xAOD::TruthParticle* theBestPartOutCone(nullptr);
67 const xAOD::TruthParticle* theBestPartdR(nullptr);
68 double LeadingPhtPT(0);
69 double LeadingPartPT(0);
70 double LeadingPhtdR(999.);
71 double LeadingPartdR(999.);
72 double BestPartdR(999.);
73 double etaClus = clus->etaBE(2);
74 double phiClus = clus->phiBE(2);
75 if (etaClus < -900) {
76 etaClus = clus->eta();
77 }
78 if (phiClus < -900) {
79 phiClus = clus->phi();
80 }
81 std::vector<const xAOD::TruthParticle*> tps;
82 if (!m_truthInConeTool->particlesInCone(ctx, etaClus, phiClus, 0.5, tps)) {
83 ATH_MSG_WARNING("Truth Particle in Cone failed");
84 return theMatchPart;
85 }
86
87 for (const auto* const thePart : tps) {
88 // loop over the stable particle
89 if (!MC::isStable(thePart)) continue;
90 // excluding G4 particle
91 if ((!isFwrdEle || (isFwrdEle && m_FwdElectronUseG4Sel)) && HepMC::is_simulation_particle(thePart)) continue;
92 long iParticlePDG = thePart->pdgId();
93 // excluding neutrino
94 if (std::abs(iParticlePDG) == 12 || std::abs(iParticlePDG) == 14 || std::abs(iParticlePDG) == 16) continue;
95 double pt = thePart->pt() / Athena::Units::GeV;
96 double q = thePart?thePart->charge():0.0;
97 // exclude charged particles with pT<1 GeV
98 if (q != 0 && pt < m_pTChargePartCut) continue;
99 if (q == 0 && pt < m_pTNeutralPartCut) continue;
100
101 // eleptical cone for extrapolations m_partExtrConePhi X m_partExtrConeEta
102 if (!isFwrdEle && m_ROICone && std::hypot( detPhi(phiClus, thePart->phi())/m_partExtrConePhi, detEta(etaClus, thePart->eta())/m_partExtrConeEta) > 1.0) {
103 continue;
104 }
105 // Also check if the clus and true have different sign , i they need both to be <0 or >0
106 if (isFwrdEle && // It is forward and
107 (((etaClus < 0) - (thePart->eta() < 0) != 0)
108 // The truth eta has different sign wrt to the fwd electron
109 || (std::fabs(thePart->eta()) < m_FwdElectronTruthExtrEtaCut) // or the truth is less than 2.4 (default cut)
110 || (std::fabs(thePart->eta() - etaClus) > m_FwdElectronTruthExtrEtaWindowCut) // or if the delta Eta between el and truth is > 0.15
111 ) // then do no extrapolate this truth Particle for this fwd electron
112 ) {
113 continue;
114 }
115 double dR(-999.);
116 bool isNCone = false;
117 bool isExt = genPartToCalo(ctx, clus, thePart, isFwrdEle, dR, isNCone, *caloDDMgr);
118 if (!isExt) continue;
119 theMatchPart = MC::findMatching(truthParticleContainerReadHandle.ptr(), thePart);
120 if (info) {
121 info->egPartPtr.push_back(thePart);
122 info->egPartdR.push_back(dR);
123 info->egPartClas.push_back(particleTruthClassifier(theMatchPart, info));
124 }
125 // Gen particles Not forward
126 if (!isFwrdEle) {
127 // the leading photon or electron inside narrow eleptical cone
128 // m_phtClasConePhi X m_phtClasConeEta
129 if ((iParticlePDG == 22 || std::abs(iParticlePDG) == 11) && isNCone && pt > LeadingPhtPT) {
130 theEgamma = thePart;
131 LeadingPhtPT = pt;
132 LeadingPhtdR = dR;
133 }
134 // leading particle (excluding photon and electron) inside narrow eleptic
135 // cone m_phtClasConePhi X m_phtClasConeEta
136 if ((iParticlePDG != 22 && std::abs(iParticlePDG) != 11) && isNCone && pt > LeadingPartPT) {
137 theLeadingPartInCone = thePart;
138 LeadingPartPT = pt;
139 LeadingPartdR = dR;
140 };
141 // the best dR matched particle outside narrow eleptic cone cone
142 // m_phtClasConePhi X m_phtClasConeEta
143 if (!isNCone && dR < BestPartdR) {
144 theBestPartOutCone = thePart;
145 BestPartdR = dR;
146 };
147 } else {
148 if (dR < BestPartdR) {
149 theBestPartdR = thePart;
150 BestPartdR = dR;
151 };
152 }
153 }
154
155 if (theEgamma != nullptr) {
156 theMatchPart = MC::findMatching(truthParticleContainerReadHandle.ptr(), theEgamma);
157 if (info) info->deltaRMatch = LeadingPhtdR;
158 } else if (theLeadingPartInCone != nullptr) {
159 theMatchPart = MC::findMatching(truthParticleContainerReadHandle.ptr(),theLeadingPartInCone);
160 if (info) info->deltaRMatch = LeadingPartdR;
161 } else if (theBestPartOutCone != nullptr) {
162 theMatchPart = MC::findMatching(truthParticleContainerReadHandle.ptr(),theBestPartOutCone);
163 if (info) info->deltaRMatch = BestPartdR;
164 } else if (isFwrdEle && theBestPartdR != nullptr) {
165 theMatchPart = MC::findMatching(truthParticleContainerReadHandle.ptr(),theBestPartdR );
166 if (info) info->deltaRMatch = BestPartdR;
167 } else {
168 theMatchPart = nullptr;
169 }
170 if (isFwrdEle || theMatchPart != nullptr || !m_inclG4part) return theMatchPart;
171
172 // additional loop over G4 particles,
173 for (const auto* const thePart : tps) {
174 if (!MC::isStable(thePart)) continue;
175 if (!HepMC::is_simulation_particle(thePart)) continue;
176 long iParticlePDG = thePart->pdgId();
177 // exclude neutrino
178 if (std::abs(iParticlePDG) == 12 || std::abs(iParticlePDG) == 14 || std::abs(iParticlePDG) == 16) continue;
179 if (thePart->decayVtx() != nullptr) continue;
180 if (std::hypot( detPhi(phiClus, thePart->phi())/m_partExtrConePhi, detEta(etaClus, thePart->eta())/m_partExtrConeEta ) > 1.0) continue;
181
182 double pt = thePart->pt() / Athena::Units::GeV;
183 double q = thePart->charge();
184 // exclude charged particles with pT<1 GeV
185 if (q != 0 && pt < m_pTChargePartCut) continue;
186 if (q == 0 && pt < m_pTNeutralPartCut) continue;
187
188 double dR(-999.);
189 bool isNCone = false;
190 bool isExt = genPartToCalo(ctx, clus, thePart, isFwrdEle, dR, isNCone, *caloDDMgr);
191 if (!isExt) continue;
192
193 theMatchPart = MC::findMatching(truthParticleContainerReadHandle.ptr(),thePart);
194 if (info) {
195 info->egPartPtr.push_back(thePart);
196 info->egPartdR.push_back(dR);
197 info->egPartClas.push_back(particleTruthClassifier(theMatchPart, info));
198 }
199 // the leading photon or electron inside narrow eleptical cone
200 // m_phtClasConePhi X m_phtClasConeEta
201 if ((iParticlePDG == 22 || std::abs(iParticlePDG) == 11) && isNCone && pt > LeadingPhtPT) {
202 theEgamma = thePart;
203 LeadingPhtPT = pt;
204 LeadingPhtdR = dR;
205 }
206 // leading particle (excluding photon or electron) inside narrow eleptic
207 // cone m_phtClasConePhi X m_phtClasConeEta
208 if ((iParticlePDG != 22 && std::abs(iParticlePDG) != 11) && isNCone && pt > LeadingPartPT) {
209 theLeadingPartInCone = thePart;
210 LeadingPartPT = pt;
211 LeadingPartdR = dR;
212 }
213 // the best dR matched particle outside narrow eleptic cone cone
214 // m_phtClasConePhi X m_phtClasConeEta
215 if (!isNCone && dR < BestPartdR) {
216 theBestPartOutCone = thePart;
217 BestPartdR = dR;
218 }
219 }
220
221 if (theEgamma != nullptr) {
222 theMatchPart = MC::findMatching(truthParticleContainerReadHandle.ptr(),theEgamma);
223 if (info) info->deltaRMatch = LeadingPhtdR;
224 } else if (theLeadingPartInCone != nullptr) {
225 theMatchPart = MC::findMatching(truthParticleContainerReadHandle.ptr(),theLeadingPartInCone);
226 if (info) info->deltaRMatch = LeadingPartdR;
227 } else if (theBestPartOutCone != nullptr) {
228 theMatchPart = MC::findMatching(truthParticleContainerReadHandle.ptr(),theBestPartOutCone);
229 if (info) info->deltaRMatch = BestPartdR;
230 } else {
231 theMatchPart = nullptr;
232 }
233 ATH_MSG_DEBUG("succeeded egammaClusMatch ");
234 return theMatchPart;
235}
ToolHandle< xAOD::ITruthParticlesInConeTool > m_truthInConeTool
SG::ReadCondHandleKey< CaloDetDescrManager > m_caloMgrKey
bool genPartToCalo(const EventContext &ctx, const xAOD::CaloCluster *clus, const xAOD::TruthParticle *thePart, bool isFwrdEle, double &dRmatch, bool &isNarrowCone, const CaloDetDescrManager &caloDDMgr) const
double detEta(double x, double y) const
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOrigin > particleTruthClassifier(const xAOD::TruthParticle *, MCTruthPartClassifier::Info *info=nullptr) const override final
double detPhi(double x, double y) const
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_truthParticleContainerKey
float phiBE(const unsigned layer) const
Get the phi in one layer of the EM Calo.
virtual double eta() const
The pseudorapidity ( ) of the particle.
virtual double phi() const
The azimuthal angle ( ) of the particle.
float etaBE(const unsigned layer) const
Get the eta in one layer of the EM Calo.

◆ evtStore()

ServiceHandle< StoreGateSvc > & AthCommonDataStore< AthCommonMsg< AlgTool > >::evtStore ( )
inlineinherited

The standard StoreGateSvc (event store) Returns (kind of) a pointer to the StoreGateSvc.

Definition at line 85 of file AthCommonDataStore.h.

◆ extraDeps_update_handler()

void AthCommonDataStore< AthCommonMsg< AlgTool > >::extraDeps_update_handler ( Gaudi::Details::PropertyBase & ExtraDeps)
protectedinherited

Add StoreName to extra input/output deps as needed.

use the logic of the VarHandleKey to parse the DataObjID keys supplied via the ExtraInputs and ExtraOuputs Properties to add the StoreName if it's not explicitly given

◆ findJetConstituents()

void MCTruthClassifier::findJetConstituents ( const xAOD::Jet * jet,
std::set< const xAOD::TruthParticle * > & constituents,
bool DR ) const
private

Definition at line 278 of file MCRecoToTruth.cxx.

281{
282 if (DR) {
283 // use a DR matching scheme (default)
284 // retrieve collection and get a pointer
285 SG::ReadHandle<xAOD::TruthParticleContainer> truthParticleContainerReadHandle(m_truthParticleContainerKey);
286
287 if (!truthParticleContainerReadHandle.isValid()) {
288 ATH_MSG_WARNING(" Invalid ReadHandle for xAOD::TruthParticleContainer with key: " << truthParticleContainerReadHandle.key());
289 return;
290 }
291 ATH_MSG_DEBUG("xAODTruthParticleContainer with key " << truthParticleContainerReadHandle.key() << " has valid ReadHandle ");
292 // find the matching truth particles
293 for (const auto *const thePart : *truthParticleContainerReadHandle) {
294 // match truth particles to the jet
295 if (MC::isStable(thePart) && thePart->p4().DeltaR(jet->p4()) < m_jetPartDRMatch) {
296 constituents.insert(thePart);
297 }
298 }
299 }
300 else {
301 xAOD::JetConstituentVector vec = jet->getConstituents();
302 for (const auto *particle0 : vec) {
303 const xAOD::TruthParticle* thePart = dynamic_cast<const xAOD::TruthParticle*>(particle0->rawConstituent());
304 if (MC::isStable(thePart)) {
305 constituents.insert(thePart);
306 }
307 }
308 }
309}
std::vector< size_t > vec
virtual FourMom_t p4() const
The full 4-momentum of the particle.
Definition Jet_v1.cxx:71
JetConstituentVector getConstituents() const
Return a vector of consituents. The object behaves like vector<const IParticle*>. See JetConstituentV...
Definition Jet_v1.cxx:147

◆ fracParticleInJet()

double MCTruthClassifier::fracParticleInJet ( const xAOD::TruthParticle * thePart,
const xAOD::Jet * jet,
bool DR,
bool nparts ) const
private

Definition at line 310 of file MCRecoToTruth.cxx.

311{
312 std::set<const xAOD::TruthParticle*> constituents;
313 std::set<const xAOD::TruthParticle*> daughters;
314 std::set<const xAOD::TruthParticle*> intersect;
315
316 findJetConstituents(jet, constituents, DR);
317 MC::findParticleStableDescendants(thePart, daughters);
318 if (daughters.empty()) daughters.insert(thePart);
319 // Get the intersection of constituents and daughters
320 std::set_intersection(constituents.begin(),
321 constituents.end(),
322 daughters.begin(),
323 daughters.end(),
324 std::inserter(intersect, intersect.begin()));
325
326 if (nparts) return 1.0*intersect.size() / daughters.size();
327 double frac = 0;
328 double tot = 0;
329 for (const auto *daughter : daughters) { tot += daughter->pt();}
330 for (const auto *particle : intersect) { frac += particle->pt();}
331 return frac/tot;
332}
void findJetConstituents(const xAOD::Jet *, std::set< const xAOD::TruthParticle * > &constituents, bool DR) const
std::optional< double > intersect(const AmgVector(N)&posA, const AmgVector(N)&dirA, const AmgVector(N)&posB, const AmgVector(N)&dirB)
Calculates the point B' along the line B that's closest to a second line A.
void findParticleStableDescendants(T thePart, std::set< T > &allstabledescendants)
Function to get the particle stable MC daughters.
constexpr ParticleHypothesis particle[PARTICLEHYPOTHESES]
the array of masses

◆ genPartToCalo()

bool MCTruthClassifier::genPartToCalo ( const EventContext & ctx,
const xAOD::CaloCluster * clus,
const xAOD::TruthParticle * thePart,
bool isFwrdEle,
double & dRmatch,
bool & isNarrowCone,
const CaloDetDescrManager & caloDDMgr ) const
private

Definition at line 237 of file MCTruthClassifierAthena.cxx.

244{
245 dRmatch = -999.;
246 isNarrowCone = false;
247 if (thePart == nullptr) return false;
248 double phiClus = clus->phiBE(2);
249 double etaClus = clus->etaBE(2);
250 if (etaClus < -900) {
251 etaClus = clus->eta();
252 }
253 if (phiClus < -900) {
254 phiClus = clus->phi();
255 }
256 //--FixMe
257 if (isFwrdEle || (etaClus == 0. && phiClus == 0.)) {
258 phiClus = clus->phi();
259 etaClus = clus->eta();
260 }
261 // define calo sample
262 CaloSampling::CaloSample sample = CaloSampling::EMB2;
263 if ((clus->inBarrel() && !clus->inEndcap()) ||
264 (clus->inBarrel() && clus->inEndcap() && clus->eSample(CaloSampling::EMB2) >= clus->eSample(CaloSampling::EME2))) {
265 // Barrel
266 sample = CaloSampling::EMB2;
267 } else if ((!clus->inBarrel() && clus->inEndcap() && !isFwrdEle) ||
268 (clus->inBarrel() && clus->inEndcap() && clus->eSample(CaloSampling::EME2) > clus->eSample(CaloSampling::EMB2))) {
269 // End-cap
270 sample = CaloSampling::EME2;
271 } else if (isFwrdEle && clus->inEndcap()) {
272 // FCAL
273 sample = CaloSampling::FCAL2;
274 } else {
275 return false;
276 }
277 std::unique_ptr<Trk::CurvilinearParameters> params = extractParamFromTruth(*thePart);
278 if (!params) return false;
279 // create extension to sample
280 std::vector<CaloSampling::CaloSample> samples = { sample };
281 auto extension = m_caloExtensionTool->layersCaloExtension(ctx, *params, samples, etaClus, caloDDMgr);
282 bool extensionOK = (!extension.empty());
283 if (!extensionOK) {
284 ATH_MSG_WARNING("extrapolation of Truth Particle with eta " << thePart->eta() << " , charge " << thePart->charge() << " , Pt " << thePart->pt() << " to calo failed");
285 return false;
286 }
287 double etaCalo = extension[0].second->position().eta();
288 double phiCalo = extension[0].second->position().phi();
289
290 double dPhi = detPhi(phiCalo, phiClus);
291 double dEta = detEta(etaCalo, etaClus);
292 dRmatch = std::hypot(dPhi, dEta);
293
294 if ((!isFwrdEle && dRmatch > m_phtdRtoTrCut) || (isFwrdEle && dRmatch > m_fwrdEledRtoTrCut)) return false;
295 if (!isFwrdEle && std::hypot( dPhi/m_phtClasConePhi, dEta/m_phtClasConeEta ) <= 1.0) isNarrowCone = true;
296 return true;
297}
ToolHandle< Trk::IParticleCaloExtensionTool > m_caloExtensionTool
bool inBarrel() const
Returns true if at least one clustered cell in the barrel.
float eSample(const CaloSample sampling) const
bool inEndcap() const
Returns true if at least one clustered cell in the endcap.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
double charge() const
Physical charge.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
bool dPhi(const xAOD::TauJet &tau, const xAOD::CaloVertexedTopoCluster &cluster, float &out)
bool dEta(const xAOD::TauJet &tau, const xAOD::CaloVertexedTopoCluster &cluster, float &out)

◆ getGenPart()

const xAOD::TruthParticle * MCTruthClassifier::getGenPart ( const xAOD::TrackParticle * trk,
MCTruthPartClassifier::Info * info = nullptr ) const
finaloverridevirtual

Implements IMCTruthClassifier.

Definition at line 181 of file MCRecoToTruth.cxx.

182{
183 // return GenParticle corresponding to given TrackParticle
184 ATH_MSG_DEBUG("Executing getGenPart ");
185 if (!trk) return nullptr;
186 if (info) {
187 info->deltaRMatch = -999.;
188 info->deltaPhi = -999.;
189 info->probTrkToTruth = 0;
190 info->numOfSiHits = 0;
191 }
192
193 uint8_t NumOfPixHits = 0;
194 uint8_t NumOfSCTHits = 0;
195 typedef ElementLink<xAOD::TruthParticleContainer> TruthLink_t;
196
197 static const SG::AuxElement::Accessor<TruthLink_t> tPL("truthParticleLink");
198 if (!tPL.isAvailable(*trk)) {
199 ATH_MSG_DEBUG("Track particle is not associated to truth particle");
200 return nullptr;
201 }
202
203 const auto& truthLink = tPL(*trk);
204 if (!truthLink.isValid()) {
205 ATH_MSG_DEBUG("Invalid link to truth particle");
206 return nullptr;
207 }
208
209 const xAOD::TruthParticle* theGenParticle = (*truthLink);
210 if (!theGenParticle) {
211 ATH_MSG_DEBUG("Could not find truth matching for track");
212 return nullptr;
213 }
214
215 if (info) {
216 static const SG::AuxElement::Accessor<float> tMP("truthMatchProbability");
217 if (tMP.isAvailable(*trk)) {
218 info->probTrkToTruth = tMP(*trk);
219 } else {
220 ATH_MSG_DEBUG("Truth match probability not available");
221 }
222 }
223
224 if (theGenParticle->status() == 3) {
225 ATH_MSG_WARNING("track matched to the truth with status " << theGenParticle->status());
226 }
227 else if (MC::isDecayed(theGenParticle)) {
228 // Matching to status == 2 particles is to be expected if
229 // quasi-stable particle simulation was used.
230 ATH_MSG_DEBUG("track matched to the truth with status " << theGenParticle->status());
231 }
232
233 if (MC::isDecayed(theGenParticle) && (MC::isElectron(theGenParticle) || MC::isMuon(theGenParticle))) {
234 const xAOD::TruthVertex* EndVrtx = theGenParticle->decayVtx();
235 const xAOD::TruthParticle* theGenPartTmp(nullptr);
236
237 if (EndVrtx != nullptr) {
238 int itr = 0;
239 do {
240 theGenPartTmp = nullptr;
241 for (const auto & theDaugt: EndVrtx->particles_out()) {
242 if (!theDaugt) continue;
243 if (theDaugt->pdgId() == theGenParticle->pdgId()) theGenPartTmp = theDaugt;
244 if (theDaugt->pdgId() != theGenParticle->pdgId() && !MC::isPhoton(theDaugt)) theGenPartTmp = nullptr;
245 }
246 itr++;
247 if (itr > 100) {
248 ATH_MSG_WARNING("getGenPart infinite while");
249 break;
250 }
251 EndVrtx = theGenPartTmp ? theGenPartTmp->decayVtx() : nullptr;
252 } while (theGenPartTmp && theGenPartTmp->pdgId() == theGenParticle->pdgId() && MC::isDecayed(theGenPartTmp) && EndVrtx != nullptr);
253
254 if (theGenPartTmp && theGenPartTmp->pdgId() == theGenParticle->pdgId()) theGenParticle = theGenPartTmp;
255 }
256 }
257
258 if (!trk->summaryValue(NumOfSCTHits, xAOD::numberOfSCTHits)) ATH_MSG_DEBUG("Could not retrieve number of SCT hits");
259 if (!trk->summaryValue(NumOfPixHits, xAOD::numberOfPixelHits)) ATH_MSG_DEBUG("Could not retrieve number of Pixel hits");
260
261 uint8_t NumOfSiHits = NumOfSCTHits + NumOfPixHits;
262
263 float deltaPhi = detPhi(theGenParticle->phi(), trk->phi());
264 float deteta = detEta(theGenParticle->eta(), trk->eta());
265 float deltaRMatch = std::hypot(deltaPhi, deteta);
266 if ((NumOfSiHits > m_NumOfSiHitsCut && deltaRMatch > m_deltaRMatchCut) ||
267 (NumOfSiHits <= m_NumOfSiHitsCut && deltaPhi > m_deltaPhiMatchCut)) theGenParticle = nullptr;
268
269 if (info) {
270 info->deltaRMatch = deltaRMatch;
271 info->deltaPhi = deltaPhi;
272 info->numOfSiHits = NumOfSiHits;
273 }
274 ATH_MSG_DEBUG("getGenPart succeeded ");
275 return (theGenParticle);
276}
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
ElementLink< xAOD::TruthParticleContainer > TruthLink_t
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .)
bool summaryValue(uint8_t &value, const SummaryType &information) const
Accessor for TrackSummary values.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
virtual double phi() const override final
The azimuthal angle ( ) of the particle.
@ numberOfSCTHits
number of hits in SCT [unit8_t].
@ numberOfPixelHits
these are the pixel hits, including the b-layer [unit8_t].

◆ getKey()

SG::sgkey_t asg::AsgTool::getKey ( const void * ptr) const
inherited

Get the (hashed) key of an object that is in the event store.

This is a bit of a special one. StoreGateSvc and xAOD::TEvent both provide ways for getting the SG::sgkey_t key for an object that is in the store, based on a bare pointer. But they provide different interfaces for doing so.

In order to allow tools to efficiently perform this operation, they can use this helper function.

See also
asg::AsgTool::getName
Parameters
ptrThe bare pointer to the object that the event store should know about
Returns
The hashed key of the object in the store. If not found, an invalid (zero) key.

Definition at line 119 of file AsgTool.cxx.

119 {
120
121#ifdef XAOD_STANDALONE
122 // In case we use @c xAOD::TEvent, we have a direct function call
123 // for this.
124 return evtStore()->event()->getKey( ptr );
125#else
126 const SG::DataProxy* proxy = evtStore()->proxy( ptr );
127 return ( proxy == nullptr ? 0 : proxy->sgkey() );
128#endif // XAOD_STANDALONE
129 }
ServiceHandle< StoreGateSvc > & evtStore()

◆ getName()

const std::string & asg::AsgTool::getName ( const void * ptr) const
inherited

Get the name of an object that is / should be in the event store.

This is a bit of a special one. StoreGateSvc and xAOD::TEvent both provide ways for getting the std::string name for an object that is in the store, based on a bare pointer. But they provide different interfaces for doing so.

In order to allow tools to efficiently perform this operation, they can use this helper function.

See also
asg::AsgTool::getKey
Parameters
ptrThe bare pointer to the object that the event store should know about
Returns
The string name of the object in the store. If not found, an empty string.

Definition at line 106 of file AsgTool.cxx.

106 {
107
108#ifdef XAOD_STANDALONE
109 // In case we use @c xAOD::TEvent, we have a direct function call
110 // for this.
111 return evtStore()->event()->getName( ptr );
112#else
113 const SG::DataProxy* proxy = evtStore()->proxy( ptr );
114 static const std::string dummy = "";
115 return ( proxy == nullptr ? dummy : proxy->name() );
116#endif // XAOD_STANDALONE
117 }

◆ getProperty()

template<class T>
const T * asg::AsgTool::getProperty ( const std::string & name) const
inherited

Get one of the tool's properties.

◆ initialize()

virtual StatusCode MCTruthClassifier::initialize ( void )
inlineoverridevirtual

Dummy implementation of the initialisation function.

It's here to allow the dual-use tools to skip defining an initialisation function. Since many are doing so...

Reimplemented from asg::AsgTool.

Reimplemented in D3PD::D3PDMCTruthClassifier.

Definition at line 96 of file MCTruthClassifier.h.

96 {
97 ATH_MSG_INFO(" Initializing MCTruthClassifier");
98#ifndef XAOD_ANALYSIS
99 // Only needed for GenParticle interface
101#endif
103
104#if !defined(XAOD_ANALYSIS) && !defined(GENERATIONBASE)
105 if (!m_caloExtensionTool.empty()) {
106 ATH_CHECK(m_caloExtensionTool.retrieve());
107 } else {
108 m_caloExtensionTool.disable();
109 }
110
112
113 if (!m_truthInConeTool.empty()) {
114 ATH_CHECK(m_truthInConeTool.retrieve());
115 } else {
116 m_truthInConeTool.disable();
117 }
118#endif
119 return StatusCode::SUCCESS;
120 }
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_INFO(x)
SG::ReadHandleKey< xAODTruthParticleLinkVector > m_truthLinkVecReadHandleKey

◆ inputHandles()

virtual std::vector< Gaudi::DataHandle * > AthCommonDataStore< AthCommonMsg< AlgTool > >::inputHandles ( ) const
overridevirtualinherited

Return this algorithm's input handles.

We override this to include handle instances from key arrays if they have not yet been declared. See comments on updateVHKA.

◆ msg()

MsgStream & AthCommonMsg< AlgTool >::msg ( ) const
inlineinherited

Definition at line 24 of file AthCommonMsg.h.

24 {
25 return this->msgStream();
26 }

◆ msg_level_name()

const std::string & asg::AsgTool::msg_level_name ( ) const
inherited

A deprecated function for getting the message level's name.

Instead of using this, weirdly named function, user code should get the string name of the current minimum message level (in case they really need it...), with:

MSG::name( msg().level() )

This function's name doesn't follow the ATLAS coding rules, and as such will be removed in the not too distant future.

Returns
The string name of the current minimum message level that's printed

Definition at line 101 of file AsgTool.cxx.

101 {
102
103 return MSG::name( msg().level() );
104 }
MsgStream & msg() const
const std::string & name(Level lvl)
Convenience function for translating message levels to strings.
Definition MsgLevel.cxx:19

◆ msgLvl()

bool AthCommonMsg< AlgTool >::msgLvl ( const MSG::Level lvl) const
inlineinherited

Definition at line 30 of file AthCommonMsg.h.

30 {
31 return this->msgLevel(lvl);
32 }

◆ outputHandles()

virtual std::vector< Gaudi::DataHandle * > AthCommonDataStore< AthCommonMsg< AlgTool > >::outputHandles ( ) const
overridevirtualinherited

Return this algorithm's output handles.

We override this to include handle instances from key arrays if they have not yet been declared. See comments on updateVHKA.

◆ particleHepMCTruthClassifier()

std::pair< ParticleType, ParticleOrigin > MCTruthClassifier::particleHepMCTruthClassifier ( const HepMcParticleLink & theLink,
MCTruthPartClassifier::Info * info = nullptr ) const
finaloverridevirtual

Implements IMCTruthClassifier.

Definition at line 25 of file MCTruthClassifierGen.cxx.

25 {
26 // Retrieve the links between HepMC and xAOD::TruthParticle
27 const EventContext& ctx = info ? info->eventContext : Gaudi::Hive::currentContext();
28 SG::ReadHandle<xAODTruthParticleLinkVector> truthParticleLinkVecReadHandle(m_truthLinkVecReadHandleKey, ctx);
29 if (!truthParticleLinkVecReadHandle.isValid()) {
30 ATH_MSG_WARNING(" Invalid ReadHandle for xAODTruthParticleLinkVector with key: " << truthParticleLinkVecReadHandle.key());
31 return std::make_pair(Unknown, NonDefined);
32 }
33 ElementLink<xAOD::TruthParticleContainer> tplink = truthParticleLinkVecReadHandle->find (theLink);
34 if (tplink.isValid()) {
35 return particleTruthClassifier (*tplink, info);
36 }
37 return std::make_pair(Unknown, NonDefined);
38}
@ Unknown
Definition TruthClasses.h:9

◆ particleTruthClassifier() [1/7]

virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOrigin > MCTruthClassifier::particleTruthClassifier ( const xAOD::CaloCluster * ,
MCTruthPartClassifier::Info * info = nullptr ) const
finaloverridevirtual

Implements IMCTruthClassifier.

Reimplemented in D3PD::D3PDMCTruthClassifier.

◆ particleTruthClassifier() [2/7]

std::pair< ParticleType, ParticleOrigin > MCTruthClassifier::particleTruthClassifier ( const xAOD::Electron * elec,
MCTruthPartClassifier::Info * info = nullptr ) const
finaloverridevirtual

Implements IMCTruthClassifier.

Reimplemented in D3PD::D3PDMCTruthClassifier.

Definition at line 24 of file MCRecoToTruth.cxx.

25{
26 ATH_MSG_DEBUG("Executing egamma electron Classifier");
27 ParticleType parttype = Unknown;
28 ParticleOrigin partorig = NonDefined;
29 const xAOD::TruthParticle* genPart = nullptr;
30 const xAOD::TrackParticle* trkPtr = elec->trackParticle();
31 if (elec->author() != xAOD::EgammaParameters::AuthorFwdElectron ||trkPtr) {
32 // Central electron or forward electron with track (when reco
33 // implemented in the future)
34 if (!trkPtr){
35 return std::make_pair(parttype, partorig);
36 }
37 genPart = getGenPart(trkPtr);
38 } else {
39#ifndef XAOD_ANALYSIS // cluster matching available only in Athena
40 const xAOD::CaloCluster* clus = elec->caloCluster();
41 genPart = egammaClusMatch(clus, true, info);
42#else
43 ATH_MSG_WARNING("Forward Electron classification using extrapolation to Calo is available only in Athena , check your enviroment. ");
44#endif
45 }
46
47 if (info) info->genPart = genPart;
48 if (!genPart) return std::make_pair(parttype, partorig);
49 ATH_MSG_DEBUG("egamma electron Classifier succeeded ");
50 return particleTruthClassifier(genPart, info);
51}
virtual const xAOD::TruthParticle * egammaClusMatch(const xAOD::CaloCluster *, bool, MCTruthPartClassifier::Info *info) const override final
virtual const xAOD::TruthParticle * getGenPart(const xAOD::TrackParticle *, MCTruthPartClassifier::Info *info=nullptr) const override final
uint16_t author(uint16_t bitmask=EgammaParameters::AuthorALL) const
Get author.
const xAOD::CaloCluster * caloCluster(size_t index=0) const
Pointer to the xAOD::CaloCluster/s that define the electron candidate.
const xAOD::TrackParticle * trackParticle(size_t index=0) const
Pointer to the xAOD::TrackParticle/s that match the electron candidate.
const uint16_t AuthorFwdElectron
Electron reconstructed by the Forward cluster-based algorithm.
Definition EgammaDefs.h:30
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
TrackParticle_v1 TrackParticle
Reference the current persistent version:

◆ particleTruthClassifier() [3/7]

std::pair< ParticleType, ParticleOrigin > MCTruthClassifier::particleTruthClassifier ( const xAOD::Jet * jet,
bool DR,
MCTruthPartClassifier::Info * info = nullptr ) const
finaloverridevirtual

Implements IMCTruthClassifier.

Reimplemented in D3PD::D3PDMCTruthClassifier.

Definition at line 134 of file MCRecoToTruth.cxx.

135{
136 ATH_MSG_DEBUG("Executing Classifier with jet Input");
137 ParticleType parttype = UnknownJet;
138 ParticleOrigin partorig = NonDefined;
139 ParticleType tempparttype = UnknownJet;
140 std::set<const xAOD::TruthParticle*> allJetMothers;
141 std::set<const xAOD::TruthParticle*> constituents;
142 if (!jet) return std::make_pair(parttype, partorig);
143 allJetMothers.clear();
144 constituents.clear();
145 findJetConstituents(jet, constituents, DR);
146 // AV: Jet type is the type of hadron with "heaviest" flavour among the jet constituents.
147 // AV: No hadrons in the jet -- the flavour is unknown.
148 // AV: The algorithm will fail on 4/5 quark hadrons and probably on nonBSM hadrons. To be fixed.
149 for (const auto& thePart: constituents) {
150 MC::findParticleAncestors(thePart, allJetMothers);
151 //AV: probably skip ME particles
152 if (!MC::isPhysical(thePart)) continue;
153 // determine if hadron and its type
154 tempparttype = particleTruthClassifier(thePart, info).first;
155 if (tempparttype != Hadron) continue;
156 tempparttype = defTypeOfHadron(thePart->pdgId());
157 // classify the jet
158 if (tempparttype == BBbarMesonPart || tempparttype == BottomMesonPart || tempparttype == BottomBaryonPart) {
159 parttype = BJet;
160 continue;
161 }
162 if (tempparttype == CCbarMesonPart || tempparttype == CharmedMesonPart || tempparttype == CharmedBaryonPart) {
163 if (parttype != BJet) parttype = CJet;
164 continue;
165 }
166 if (tempparttype == StrangeBaryonPart || tempparttype == LightBaryonPart || tempparttype == StrangeMesonPart || tempparttype == LightMesonPart) {
167 if (parttype != BJet && parttype != CJet) parttype = LJet;
168 continue;
169 }
170 }
171
172 // clasify the jet origin
173 partorig = defJetOrig(allJetMothers);
174 allJetMothers.clear();
175 constituents.clear();
176 ATH_MSG_DEBUG(" jet Classifier succeeded");
177 return std::make_pair(parttype, partorig);
178}
@ Hadron
@ StrangeMesonPart
@ UnknownJet
@ CharmedMesonPart
@ BottomMesonPart
@ CJet
@ BJet
@ LightBaryonPart
@ LJet
@ CharmedBaryonPart
@ LightMesonPart
@ BottomBaryonPart
@ StrangeBaryonPart
ParticleOrigin defJetOrig(const T &allJetMothers)
void findParticleAncestors(T thePart, std::set< T > &allancestors)
Function to find all ancestors of the particle.

◆ particleTruthClassifier() [4/7]

virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOrigin > MCTruthClassifier::particleTruthClassifier ( const xAOD::Muon * ,
MCTruthPartClassifier::Info * info = nullptr ) const
finaloverridevirtual

Implements IMCTruthClassifier.

Reimplemented in D3PD::D3PDMCTruthClassifier.

◆ particleTruthClassifier() [5/7]

std::pair< ParticleType, ParticleOrigin > MCTruthClassifier::particleTruthClassifier ( const xAOD::Photon * phot,
MCTruthPartClassifier::Info * info = nullptr ) const
finaloverridevirtual

Implements IMCTruthClassifier.

Reimplemented in D3PD::D3PDMCTruthClassifier.

Definition at line 54 of file MCRecoToTruth.cxx.

55{
56 ATH_MSG_DEBUG("Executing egamma photon Classifier");
57 ParticleType parttype = Unknown;
58 ParticleOrigin partorig = NonDefined;
59 const xAOD::CaloCluster* clus = phot->caloCluster();
60 if (!clus) return std::make_pair(parttype, partorig);
61 if (std::fabs(clus->eta()) > 10.0 || std::fabs(clus->phi()) > 6.28 || (clus->et()) <= 0.) return std::make_pair(parttype, partorig);
62
63 const xAOD::Vertex* VxCvPtr = phot->vertex();
64 if (VxCvPtr != nullptr) {
65 for (int itrk = 0; itrk < (int)VxCvPtr->nTrackParticles(); itrk++) {
66 if (itrk > 1) continue;
67 const xAOD::TrackParticle* trkPtr = VxCvPtr->trackParticle(itrk);
68 if (!trkPtr) continue;
69 const xAOD::TruthParticle* thePart = getGenPart(trkPtr);
70 std::pair<ParticleType, ParticleOrigin> classif = particleTruthClassifier(thePart, info);
71 if (info) {
72 info->cnvPhotTrkPtr.push_back(trkPtr);
73 info->cnvPhotTrkToTruthPart.push_back(thePart);
74 info->cnvPhotPartType.push_back(classif.first);
75 info->cnvPhotPartOrig.push_back(classif.second);
76 }
77 }
78 }
79
80 const xAOD::TruthParticle* genPart = nullptr;
81#ifndef XAOD_ANALYSIS // Fwd electron available only in Athena
82 genPart = egammaClusMatch(clus, false, info);
83#else
84 ATH_MSG_WARNING("Photon Classification using extrapolation to Calo is available only in Athena , check your enviroment. ");
85#endif
86 if (!genPart) return std::make_pair(parttype, partorig);
87 if (info) info->genPart = genPart;
88 ATH_MSG_DEBUG("egamma photon Classifier succeeded ");
89 return particleTruthClassifier(genPart, info);
90}
const xAOD::Vertex * vertex(size_t index=0) const
Pointer to the xAOD::Vertex/es that match the photon candidate.
Definition Photon_v1.cxx:61
size_t nTrackParticles() const
Get the number of tracks associated with this vertex.
const TrackParticle * trackParticle(size_t i) const
Get the pointer to a given track that was used in vertex reco.
Vertex_v1 Vertex
Define the latest version of the vertex class.

◆ particleTruthClassifier() [6/7]

std::pair< ParticleType, ParticleOrigin > MCTruthClassifier::particleTruthClassifier ( const xAOD::TrackParticle * trkPtr,
MCTruthPartClassifier::Info * info = nullptr ) const
finaloverridevirtual

Implements IMCTruthClassifier.

Reimplemented in D3PD::D3PDMCTruthClassifier.

Definition at line 11 of file MCRecoToTruth.cxx.

12{
13 ATH_MSG_DEBUG("Executing trackClassifier");
14 ParticleType parttype = Unknown;
15 ParticleOrigin partorig = NonDefined;
16 const xAOD::TruthParticle* genPart = getGenPart(trkPtr);
17 if (info) info->genPart = genPart;
18 if (!genPart) return std::make_pair(parttype, partorig);
19 ATH_MSG_DEBUG("trackClassifier succeeded ");
20 return particleTruthClassifier(genPart, info);
21}

◆ particleTruthClassifier() [7/7]

std::pair< ParticleType, ParticleOrigin > MCTruthClassifier::particleTruthClassifier ( const xAOD::TruthParticle * thePart,
MCTruthPartClassifier::Info * info = nullptr ) const
finaloverridevirtual

Implements IMCTruthClassifier.

Reimplemented in D3PD::D3PDMCTruthClassifier.

Definition at line 42 of file MCTruthClassifierGen.cxx.

42 {
43 MCTruthPartClassifier::Info tmpinfo;
44 MCTruthPartClassifier::Info& info = (infoin) ? *infoin : tmpinfo;
45
46 ATH_MSG_DEBUG("Executing particleTruthClassifier");
47
48 ParticleType partType = Unknown;
49 ParticleOrigin partOrig = NonDefined;
50 if (!thePart) {
51 return std::make_pair(partType, partOrig);
52 }
53 info.genPart = thePart;
54
55 // retrieve collection and get a pointer
56 SG::ReadHandle<xAOD::TruthParticleContainer> truthParticleContainerReadHandle(m_truthParticleContainerKey,info.eventContext);
57 if (!truthParticleContainerReadHandle.isValid()) {
58 ATH_MSG_WARNING( " Invalid ReadHandle for xAOD::TruthParticleContainer with key: " << truthParticleContainerReadHandle.key());
59 return std::make_pair(partType, partOrig);
60 }
61
62 ATH_MSG_DEBUG("xAODTruthParticleContainer with key " << truthParticleContainerReadHandle.key() << " has valid ReadHandle ");
63
64 if (!MC::isStable(thePart) && !MC::isDecayed(thePart)) {
65 return std::make_pair(GenParticle, partOrig);
66 }
67 const bool isPartHadr = MC::isHadron(thePart) && !MC::isBeam(thePart);
68 if (MC::isDecayed(thePart) && (!MC::isTau(thePart) && !isPartHadr)) return std::make_pair(GenParticle, partOrig);
69
70 // SUSY datasets: tau(status==2)->tau(status==2)
71 if (MC::isDecayed(thePart) && MC::isTau(thePart)) {
72 const xAOD::TruthVertex* endVert = thePart->decayVtx();
73 if (endVert) {
74 if (endVert->nOutgoingParticles() == 1 && MC::isTau(endVert->outgoingParticle(0))) {
75 return std::make_pair(GenParticle, partOrig);
76 }
77 }
78 }
79
80 if (MC::isStable(thePart) && MC::isSUSY(thePart)) return std::make_pair(SUSYParticle, partOrig);
81
82 if (MC::isStable(thePart) && MC::isBSM(thePart)) return std::make_pair(OtherBSMParticle, partOrig);
83
84 if (MC::isDecayed(thePart) &&
85 (!MC::isElectron(thePart) && !MC::isMuon(thePart) &&
86 !MC::isTau(thePart) && !MC::isPhoton(thePart)) &&
87 !isPartHadr)
88 return std::make_pair(GenParticle, partOrig);
89
90 // FIXME vetoing protons here to preserve previous behaviour
91 if (MC::isNucleus(thePart) && std::abs(thePart->pdgId()) != MC::PROTON) return std::make_pair(NuclFrag, partOrig);
92
93 if ( !MC::isSMLepton(thePart) && !MC::isPhoton(thePart) && !isPartHadr) return std::make_pair(partType, partOrig);
94 // don't consider generator particles
95
96 const xAOD::TruthVertex* partProdVtx = thePart->hasProdVtx() ? thePart->prodVtx() : nullptr;
97
99 if (partProdVtx) {
100 for (const auto& temp: partProdVtx->particles_in()) {if (temp) parent = temp;}
101 }
102 const int parentPDG = parent?parent->pdg_id():0;
103 info.setMotherProperties(parent);
104
105 if (!partProdVtx && HepMC::is_simulation_particle(thePart)) {
106 return std::make_pair(NonPrimary, partOrig);
107 }
108 if (!partProdVtx && MC::isElectron(thePart)) {
109 // to define electron outcome status
110 bool isPrompt = false; // updated by defOrigOfElectron
111 partOrig = defOrigOfElectron(*truthParticleContainerReadHandle, thePart, isPrompt, info);
112 return std::make_pair(UnknownElectron, partOrig);
113 }
114 if (!partProdVtx && MC::isMuon(thePart)) {
115 // to define electron outcome status
116 bool isPrompt = false; // updated by defOrigOfMuon
117 partOrig = defOrigOfMuon(*truthParticleContainerReadHandle, thePart, isPrompt, info);
118 return std::make_pair(UnknownMuon, partOrig);
119 }
120 if (!partProdVtx && MC::isTau(thePart)) {
121 // to define electron outcome status
122 partOrig = defOrigOfTau(*truthParticleContainerReadHandle, thePart, parentPDG, info);
123 return std::make_pair(UnknownTau, partOrig);
124 }
125 if (!partProdVtx && MC::isPhoton(thePart)) {
126 // to define photon outcome
127 bool isPrompt = false; // updated by defOrigOfPhoton
128 partOrig = defOrigOfPhoton(*truthParticleContainerReadHandle, thePart, isPrompt, info);
129 return std::make_pair(UnknownPhoton, partOrig);
130 }
131 if (!partProdVtx && MC::isNeutrino(thePart)) {
132 // to define neutrino outcome
133 info.particleOutCome = NonInteract;
134 return std::make_pair(Neutrino, partOrig);
135 }
136
137 if (thePart && info.Mother() && HepMC::is_same_generator_particle(thePart,info.Mother()))
138 return std::make_pair(NonPrimary, partOrig);
139
140 if (isPartHadr) return std::make_pair(Hadron, partOrig);
141
142 if (partProdVtx && parentPDG == 0 && partProdVtx->nOutgoingParticles() == 1 &&
143 partProdVtx->nIncomingParticles() == 0) {
144 if (MC::isElectron(thePart)) {
145 info.particleOutCome = defOutComeOfElectron(thePart);
146 return std::make_pair(IsoElectron, SingleElec);
147 }
148 if (MC::isMuon(thePart)) {
149 info.particleOutCome = defOutComeOfMuon(thePart);
150 return std::make_pair(IsoMuon, SingleMuon);
151 }
152 if (MC::isTau(thePart)) {
153 info.particleOutCome = defOutComeOfTau(thePart);
154 return std::make_pair(IsoTau, SingleTau);
155 }
156 if (MC::isPhoton(thePart)) {
157 info.particleOutCome = defOutComeOfPhoton(thePart);
158 return std::make_pair(IsoPhoton, SinglePhot);
159 }
160 }
161
162 if (parentPDG == thePart->pdg_id() && parent && parent->status() == 3 && MC::isDecayed(thePart)) return std::make_pair(GenParticle, partOrig);
163
164 if (MC::isElectron(thePart)) {
165 bool isPrompt = false; // updated by defOrigOfElectron
166 partOrig = defOrigOfElectron(*truthParticleContainerReadHandle, thePart, isPrompt, info);
167 partType = defTypeOfElectron(partOrig, isPrompt);
168 } else if (MC::isMuon(thePart)) {
169 bool isPrompt = false; // updated by defOrigOfMuon
170 partOrig = defOrigOfMuon(*truthParticleContainerReadHandle, thePart, isPrompt, info);
171 partType = defTypeOfMuon(partOrig, isPrompt);
172 } else if (MC::isTau(thePart)) {
173 partOrig = defOrigOfTau(*truthParticleContainerReadHandle, thePart, parentPDG, info);
174 partType = defTypeOfTau(partOrig);
175 } else if (MC::isPhoton(thePart)) {
176 bool isPrompt = false; // updated by defOrigOfPhoton
177 partOrig = defOrigOfPhoton(*truthParticleContainerReadHandle, thePart, isPrompt, info);
178 partType = defTypeOfPhoton(partOrig);
179 } else if (MC::isNeutrino(thePart)) {
180 bool isPrompt = false; // updated by defOrigOfNeutrino
181 partOrig = defOrigOfNeutrino(*truthParticleContainerReadHandle, thePart, isPrompt, info);
182 partType = Neutrino;
183 }
184
185 ATH_MSG_DEBUG("particleTruthClassifier succeeded ");
186 return std::make_pair(partType, partOrig);
187}
@ UnknownTau
@ NuclFrag
@ OtherBSMParticle
@ IsoMuon
@ IsoElectron
@ UnknownElectron
@ NonPrimary
@ IsoPhoton
@ Neutrino
@ UnknownPhoton
@ SUSYParticle
@ UnknownMuon
@ GenParticle
@ SingleElec
@ SingleMuon
@ SingleTau
MCTruthPartClassifier::ParticleOrigin defOrigOfElectron(const xAOD::TruthParticleContainer &xTruthParticleContainer, const xAOD::TruthParticle *, bool &isPrompt, MCTruthPartClassifier::Info &info) const
MCTruthPartClassifier::ParticleOrigin defOrigOfNeutrino(const xAOD::TruthParticleContainer &xTruthParticleContainer, const xAOD::TruthParticle *, bool &isPrompt, MCTruthPartClassifier::Info &info) const
MCTruthPartClassifier::ParticleOrigin defOrigOfMuon(const xAOD::TruthParticleContainer &xTruthParticleContainer, const xAOD::TruthParticle *, bool &isPrompt, MCTruthPartClassifier::Info &info) const
MCTruthPartClassifier::ParticleOrigin defOrigOfPhoton(const xAOD::TruthParticleContainer &xTruthParticleContainer, const xAOD::TruthParticle *, bool &isPrompt, MCTruthPartClassifier::Info &info) const
int pdg_id() const
PDG ID code.
ParticleType defTypeOfPhoton(ParticleOrigin PhotOrig)
ParticleType defTypeOfMuon(ParticleOrigin MuOrig, bool isPrompt)
ParticleType defTypeOfElectron(ParticleOrigin EleOrig, bool isPrompt)
bool isNeutrino(const T &p)
APID: the fourth generation neutrinos are neutrinos.
bool isBeam(const T &p)
Identify if the particle is beam particle.
bool isHadron(const T &p)

◆ print()

◆ renounce()

std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > AthCommonDataStore< AthCommonMsg< AlgTool > >::renounce ( T & h)
inlineprotectedinherited

Definition at line 380 of file AthCommonDataStore.h.

381 {
382 h.renounce();
384 }
std::enable_if_t< std::is_void_v< std::result_of_t< decltype(&T::renounce)(T)> > &&!std::is_base_of_v< SG::VarHandleKeyArray, T > &&std::is_base_of_v< Gaudi::DataHandle, T >, void > renounce(T &h)

◆ renounceArray()

void AthCommonDataStore< AthCommonMsg< AlgTool > >::renounceArray ( SG::VarHandleKeyArray & handlesArray)
inlineprotectedinherited

remove all handles from I/O resolution

Definition at line 364 of file AthCommonDataStore.h.

364 {
366 }

◆ sysInitialize()

virtual StatusCode AthCommonDataStore< AthCommonMsg< AlgTool > >::sysInitialize ( )
overridevirtualinherited

Perform system initialization for an algorithm.

We override this to declare all the elements of handle key arrays at the end of initialization. See comments on updateVHKA.

Reimplemented in asg::AsgMetadataTool, AthCheckedComponent< AthAlgTool >, AthCheckedComponent<::AthAlgTool >, and DerivationFramework::CfAthAlgTool.

◆ sysStart()

virtual StatusCode AthCommonDataStore< AthCommonMsg< AlgTool > >::sysStart ( )
overridevirtualinherited

Handle START transition.

We override this in order to make sure that conditions handle keys can cache a pointer to the conditions container.

◆ TruthLoopDetectionMethod1()

bool MCTruthClassifier::TruthLoopDetectionMethod1 ( const xAOD::TruthVertex * childOrigVtx,
const xAOD::TruthParticle * parent ) const
private

Definition at line 190 of file MCTruthClassifierGen.cxx.

191{
192 // Start of method 1 of protecting against loops
193 const int parentPDG = parent->pdgId();
194 for (const auto& aChild: childOrigVtx->particles_out()) {
195 if (!aChild) continue;
196 if (parentPDG == aChild->pdgId() && HepMC::is_same_generator_particle(aChild, parent)) {
197 // One of the children produced in the decay of parent is
198 // actually the same particle. NB In the case of multiple
199 // children this child may not necessarily be
200 // thePriPart. Does this matter?
201 return true;
202 }
203 }
204
205 // to resolve Sherpa loop
206 return TruthLoopDetectionMethod3(childOrigVtx, parent);
207 // End of method 1 of protecting against loops
208}
bool TruthLoopDetectionMethod3(const xAOD::TruthVertex *childOrigVtx, const xAOD::TruthParticle *parent) const

◆ TruthLoopDetectionMethod2()

bool MCTruthClassifier::TruthLoopDetectionMethod2 ( const xAOD::TruthParticle * child,
const xAOD::TruthParticle * parent ) const
private

Definition at line 211 of file MCTruthClassifierGen.cxx.

212{
213 // Start of method 2 of protecting against loops
214 // to prevent Sherpa loop
215 const xAOD::TruthVertex* child_prdVtx{};
216 const xAOD::TruthVertex* child_endVtx{};
217 if (child) {
218 child_prdVtx = child->hasProdVtx() ? child->prodVtx() : nullptr;
219 child_endVtx = child->decayVtx();
220 }
221 const xAOD::TruthVertex* parent_prdVtx{};
222 const xAOD::TruthVertex* parent_endVtx{};
223 if (parent) {
224 parent_prdVtx = parent->hasProdVtx() ? parent->prodVtx() : nullptr;
225 parent_endVtx = parent->decayVtx();
226 }
227 // V0->parent->V1-> ...->V2->child->V3
228 // V3 == V0 && V1 == V2
229 return (child_endVtx == parent_prdVtx && child_prdVtx == parent_endVtx);
230}

◆ TruthLoopDetectionMethod3()

bool MCTruthClassifier::TruthLoopDetectionMethod3 ( const xAOD::TruthVertex * childOrigVtx,
const xAOD::TruthParticle * parent ) const
private

Definition at line 233 of file MCTruthClassifierGen.cxx.

234{
235 // Start of method 3 of protecting against loops
236 // to resolve Sherpa loop
237 const xAOD::TruthVertex* parentOrigVtx = parent->hasProdVtx() ? parent->prodVtx() : nullptr;
238 if (parentOrigVtx && HepMC::is_same_vertex(parentOrigVtx,childOrigVtx)) {
239 // The "parent" and the "child" have the same production vertex.
240 return true;
241 }
242 return false;
243 // End of method 3 of protecting against loops
244}
bool is_same_vertex(const T1 &p1, const T2 &p2)
Method to establish if two particles in the GenEvent actually represent the same vertex.

◆ updateVHKA()

void AthCommonDataStore< AthCommonMsg< AlgTool > >::updateVHKA ( Gaudi::Details::PropertyBase & )
inlineinherited

Definition at line 308 of file AthCommonDataStore.h.

308 {
309 // debug() << "updateVHKA for property " << p.name() << " " << p.toString()
310 // << " size: " << m_vhka.size() << endmsg;
311 for (auto &a : m_vhka) {
313 for (auto k : keys) {
314 k->setOwner(this);
315 }
316 }
317 }
std::vector< SG::VarHandleKeyArray * > m_vhka

Member Data Documentation

◆ m_caloExtensionTool

ToolHandle<Trk::IParticleCaloExtensionTool> MCTruthClassifier::m_caloExtensionTool {this,"ParticleCaloExtensionTool",""}
private

Definition at line 226 of file MCTruthClassifier.h.

226{this,"ParticleCaloExtensionTool",""};

◆ m_caloMgrKey

SG::ReadCondHandleKey<CaloDetDescrManager> MCTruthClassifier::m_caloMgrKey {this,"CaloDetDescrManager",""}
private

Definition at line 227 of file MCTruthClassifier.h.

227{this,"CaloDetDescrManager",""};

◆ m_deltaPhiMatchCut

float MCTruthClassifier::m_deltaPhiMatchCut
private

Definition at line 254 of file MCTruthClassifier.h.

◆ m_deltaRMatchCut

float MCTruthClassifier::m_deltaRMatchCut
private

Definition at line 253 of file MCTruthClassifier.h.

◆ m_detStore

StoreGateSvc_t AthCommonDataStore< AthCommonMsg< AlgTool > >::m_detStore
privateinherited

Pointer to StoreGate (detector store by default)

Definition at line 393 of file AthCommonDataStore.h.

◆ m_evtStore

StoreGateSvc_t AthCommonDataStore< AthCommonMsg< AlgTool > >::m_evtStore
privateinherited

Pointer to StoreGate (event store by default)

Definition at line 390 of file AthCommonDataStore.h.

◆ m_FwdElectronTruthExtrEtaCut

float MCTruthClassifier::m_FwdElectronTruthExtrEtaCut
private

Definition at line 232 of file MCTruthClassifier.h.

◆ m_FwdElectronTruthExtrEtaWindowCut

float MCTruthClassifier::m_FwdElectronTruthExtrEtaWindowCut
private

Definition at line 233 of file MCTruthClassifier.h.

◆ m_FwdElectronUseG4Sel

bool MCTruthClassifier::m_FwdElectronUseG4Sel
private

Definition at line 231 of file MCTruthClassifier.h.

◆ m_fwrdEledRtoTrCut

float MCTruthClassifier::m_fwrdEledRtoTrCut
private

Definition at line 240 of file MCTruthClassifier.h.

◆ m_inclG4part

bool MCTruthClassifier::m_inclG4part
private

Definition at line 245 of file MCTruthClassifier.h.

◆ m_jetPartDRMatch

float MCTruthClassifier::m_jetPartDRMatch
private

Definition at line 256 of file MCTruthClassifier.h.

◆ m_NumOfSiHitsCut

int MCTruthClassifier::m_NumOfSiHitsCut
private

Definition at line 255 of file MCTruthClassifier.h.

◆ m_partExtrConeEta

float MCTruthClassifier::m_partExtrConeEta
private

Definition at line 234 of file MCTruthClassifier.h.

◆ m_partExtrConePhi

float MCTruthClassifier::m_partExtrConePhi
private

Definition at line 235 of file MCTruthClassifier.h.

◆ m_phtClasConeEta

float MCTruthClassifier::m_phtClasConeEta
private

Definition at line 238 of file MCTruthClassifier.h.

◆ m_phtClasConePhi

float MCTruthClassifier::m_phtClasConePhi
private

Definition at line 237 of file MCTruthClassifier.h.

◆ m_phtdRtoTrCut

float MCTruthClassifier::m_phtdRtoTrCut
private

Definition at line 239 of file MCTruthClassifier.h.

◆ m_pTChargePartCut

float MCTruthClassifier::m_pTChargePartCut
private

Definition at line 243 of file MCTruthClassifier.h.

◆ m_pTNeutralPartCut

float MCTruthClassifier::m_pTNeutralPartCut
private

Definition at line 244 of file MCTruthClassifier.h.

◆ m_ROICone

bool MCTruthClassifier::m_ROICone
private

Definition at line 241 of file MCTruthClassifier.h.

◆ m_truthInConeTool

ToolHandle<xAOD::ITruthParticlesInConeTool> MCTruthClassifier::m_truthInConeTool {this,"TruthInConeTool","xAOD::TruthParticlesInConeTool/TruthParticlesInConeTool"}
private

Definition at line 229 of file MCTruthClassifier.h.

229{this,"TruthInConeTool","xAOD::TruthParticlesInConeTool/TruthParticlesInConeTool"};

◆ m_truthLinkVecReadHandleKey

SG::ReadHandleKey<xAODTruthParticleLinkVector> MCTruthClassifier::m_truthLinkVecReadHandleKey {this,"xAODTruthLinkVector","xAODTruthLinks", "ReadHandleKey for xAODTruthParticleLinkVector"}
private

Definition at line 250 of file MCTruthClassifier.h.

250{this,"xAODTruthLinkVector","xAODTruthLinks", "ReadHandleKey for xAODTruthParticleLinkVector"};

◆ m_truthParticleContainerKey

SG::ReadHandleKey<xAOD::TruthParticleContainer> MCTruthClassifier::m_truthParticleContainerKey {this,"xAODTruthParticleContainerName","TruthParticles","ReadHandleKey for xAOD::TruthParticleContainer"}
private

Definition at line 223 of file MCTruthClassifier.h.

223{this,"xAODTruthParticleContainerName","TruthParticles","ReadHandleKey for xAOD::TruthParticleContainer"};

◆ m_useCaching

bool MCTruthClassifier::m_useCaching
private

Definition at line 236 of file MCTruthClassifier.h.

◆ m_varHandleArraysDeclared

bool AthCommonDataStore< AthCommonMsg< AlgTool > >::m_varHandleArraysDeclared
privateinherited

Definition at line 399 of file AthCommonDataStore.h.

◆ m_vhka

std::vector<SG::VarHandleKeyArray*> AthCommonDataStore< AthCommonMsg< AlgTool > >::m_vhka
privateinherited

Definition at line 398 of file AthCommonDataStore.h.


The documentation for this class was generated from the following files: