ATLAS Offline Software
Loading...
Searching...
No Matches
D3PD::D3PDMCTruthClassifier Class Reference

Work around MCTruthClassifier brain-damage. More...

#include <D3PDMCTruthClassifier.h>

Inheritance diagram for D3PD::D3PDMCTruthClassifier:
Collaboration diagram for D3PD::D3PDMCTruthClassifier:

Public Member Functions

 D3PDMCTruthClassifier (const std::string &type, const std::string &name, const IInterface *parent)
 Standard Gaudi tool constructor.
virtual StatusCode initialize ()
 Standard Gaudi initialize method.
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleTruthClassifier (const xAOD::Electron *el)
 Run the classifier for an electron.
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleTruthClassifier (const xAOD::Photon *el)
 Run the classifier for a photon.
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleTruthClassifier (const xAOD::Muon *mu)
 Run the classifier for a muon.
virtual std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOriginparticleTruthClassifier (const xAOD::TruthParticle *, MCTruthPartClassifier::Info *info=nullptr) 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::Jet *, bool DR, 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 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

bool get_tptruth_name (const std::string &tp_name, std::string &tptruth_name)
 Try to find a TrackParticleTruthCollection pointing at TP_NAME.
void getProperty1 (const std::string &pname, std::string &value)
 Helper to retrieve the value of a Gaudi property.
void setProperty1 (const std::string &pname, const std::string &value)
 Helper to set the value of a Gaudi property.
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

ServiceHandle< StoreGateSvcm_sg
 The StoreGate service.
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

Work around MCTruthClassifier brain-damage.

This avoids having to specify the container names during configuration.

MCTruthClassifier requires specifying, at configuration time, the names of the TrackParticleContainer and TrackParticleTruthCollection objects to use for the mapping. This is painful in for electrons in the case where one may have several different track containers.

What we do to make this easier is to search through SG to find a truth collection that points at the TrackParticleContainer that contains the tracks for the electron we're looking at.

Definition at line 41 of file D3PDMCTruthClassifier.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

◆ D3PDMCTruthClassifier()

D3PD::D3PDMCTruthClassifier::D3PDMCTruthClassifier ( const std::string & type,
const std::string & name,
const IInterface * parent )

Standard Gaudi tool constructor.

Parameters
typeThe name of the tool type.
nameThe tool name.
parentThe tool's Gaudi parent.

Definition at line 39 of file D3PDMCTruthClassifier.cxx.

42 : MCTruthClassifier (type, name, parent),
43 m_sg ("StoreGateSvc", name)
44{
45}
ServiceHandle< StoreGateSvc > m_sg
The StoreGate service.
MCTruthClassifier(const std::string &type)

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 }
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)

◆ 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
privateinherited

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 //--Sherpa tttt with all t->Wb; W->lnu
471 if ((numberOfChildren - NumOfquark - NumOfgluon) == 8 &&
472 (NumOfEl + NumOfPos + NumOfMuPl + NumOfMuMin + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 8) &&
473 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) {
474 ATH_MSG_VERBOSE("MultiBoson for 4topLep");
475 return MultiBoson;
476 }
477
478 //--Sherpa Vgamma ( Z->ee+gamma or W->enu+gamma )
479 if ((numberOfChildren - NumOfquark - NumOfgluon) >= 3 && NumOfPhot >= 1 && NumOfEl == 1 && NumOfPos == 1) {
480 ATH_MSG_VERBOSE("Sherpa ee + gamma");
481 return ZBoson;
482 }
483 if ((numberOfChildren - NumOfquark - NumOfgluon) >= 3 && NumOfPhot >= 1 && (NumOfEl == 1 || NumOfPos == 1) && NumOfElNeut == 1) {
484 ATH_MSG_VERBOSE("Sherpa enu + gamma");
485 return WBoson;
486 }
487 }
488
489 // New Sherpa Z->ee
490 if (partProdVtx == ancestorProdVtx) {
491 int NumOfEleLoop = 0;
492 int NumOfLepLoop = 0;
493 int NumOfEleNeuLoop = 0;
494 for (const auto *const pout: partProdVtx->particles_out()) {
495 if (!pout) continue;
496 for (const auto *const pin: partProdVtx->particles_in()) {
497 if (!pin) continue;
498 if (!HepMC::is_same_particle(pout,pin)) continue;
499 if (MC::isElectron(pout)) NumOfEleLoop++;
500 if (std::abs(pout->pdgId()) == MC::NU_E) NumOfEleNeuLoop++;
501 if (MC::isSMLepton(pout)) NumOfLepLoop++;
502 break; // break out of inner loop after having found two matching particles
503 }
504 }
505 if (NumOfEleLoop == 2 && NumOfEleNeuLoop == 0) return ZBoson;
506 if (NumOfEleLoop == 1 && NumOfEleNeuLoop == 1) return WBoson;
507 if ((NumOfEleLoop == 4 && NumOfEleNeuLoop == 0) || (NumOfEleLoop == 3 && NumOfEleNeuLoop == 1) ||
508 (NumOfEleLoop == 2 && NumOfEleNeuLoop == 2)) return DiBoson;
509 if (NumOfLepLoop == 4) return DiBoson;
510 }
511
512 //-- McAtNLo
513
514 if (MC::isHiggs(ancestorPDG)) return Higgs;
515
516 if (MC::isMSSMHiggs(ancestorPDG)) return HiggsMSSM; // MSSM Higgs bosons
517
518 if (MC::isHeavyBoson(ancestorPDG)) return HeavyBoson; // Heavy bosons( Z', Z'', W'+)
519
520 if (MC::isMuon(ancestorPDG)) return Mu;
521 if (MC::isTau(ancestorPDG)) {
522 const ParticleOrigin tauOrig = defOrigOfTau(xTruthParticleContainer, ancestor, ancestorPDG, info);
523 const ParticleType tautype = defTypeOfTau(tauOrig);
524 return (tautype == IsoTau)?tauOrig:TauLep;
525 }
526
527 if (std::abs(ancestorPDG) == MC::WBOSON_LRSM) return WBosonLRSM; // Left-right symmetric model WBoson (Pythia-specific)
528 if (std::abs(ancestorPDG) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
529 if (std::abs(ancestorPDG) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
530 if (std::abs(ancestorPDG) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
531 if (MC::isLeptoQuark(ancestorPDG) || NumOfLQ != 0) return LQ;
532 if (MC::isSUSY(ancestorPDG)) return SUSY;
533 if (MC::isBSM(ancestorPDG)) return OtherBSM;
534
535 const ParticleType pType = defTypeOfHadron(ancestorPDG);
536 if ((pType == BBbarMesonPart || pType == CCbarMesonPart) && ancestorProdVtx && MC::isHardScatteringVertex(ancestorProdVtx)) isPrompt = true;
537 return convHadronTypeToOrig(pType, ancestorPDG);
538}
#define ATH_MSG_VERBOSE(x)
#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.
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
privateinherited

Definition at line 541 of file MCTruthClassifierGen.cxx.

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

Definition at line 1232 of file MCTruthClassifierGen.cxx.

1236{
1237 ATH_MSG_DEBUG("Executing DefOrigOfNeutrino ");
1238
1239 const int nuFlav = std::abs(thePart->pdgId());
1240 // Find the first copy of this particle stored in the xAOD::TruthParticleContainer (i.e. the particle prior to any interactions)
1241 const xAOD::TruthParticle* thePriPart = MC::findMatching(xTruthParticleContainer, thePart);
1242 if (!thePriPart) return NonDefined;
1243 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)
1244
1245 //-- to define neutrino outcome status
1246 info.particleOutCome = NonInteract;
1247
1248 const xAOD::TruthVertex* partProdVtx = thePriPart->hasProdVtx() ? thePriPart->prodVtx() : nullptr;
1249 if (!partProdVtx) return NonDefined;
1250
1251 if (partProdVtx->nIncomingParticles() > 1) ATH_MSG_DEBUG("DefOrigOfNeutrino:: neutrino has more than one parent.");
1252
1253 const xAOD::TruthParticle* ancestor = MC::findMother(thePriPart);
1254 info.setMotherProperties(ancestor);
1255 if (!ancestor) { return NonDefined; } // ancestor is not a nullptr beyond this point
1256
1257 // Start of method 3 of protecting against loops
1258 // to resolve Sherpa loop
1259 bool samePart = TruthLoopDetectionMethod1(partProdVtx, ancestor);
1260 // End of method 3 of protecting against loops
1261
1262 if ((std::abs(ancestor->pdgId()) == nuFlav || MC::isTau(ancestor) || MC::isW(ancestor)) && ancestor->hasProdVtx() && !samePart) {
1263 int pPDG(0);
1264 const xAOD::TruthParticle* ancestorParent{};
1265 do {
1266 pPDG = 0;
1267 ancestorParent = MC::findMother(ancestor);
1268 // Start of method 2 of protecting against loops
1269 // to prevent Sherpa loop
1270 if (TruthLoopDetectionMethod2(ancestor,ancestorParent)) {
1271 ancestorParent = ancestor;
1272 break;
1273 }
1274 //
1275 if (ancestorParent) {
1276 pPDG = ancestorParent->pdgId(); // FIXME difference in behaviour compared to defOrigOfElectron/Muon pPDG set even if we are in a loop
1277 }
1278 // to prevent Sherpa loop
1279 if (ancestor == ancestorParent) { break; }
1280 // End of method 2 of protecting against Sherpa loops
1281 if (std::abs(pPDG) == nuFlav || MC::isTau(pPDG) || MC::isW(pPDG) ) {
1282 // There will be another iteration so set ancestor to ancestorParent
1283 ancestor = ancestorParent; // ancestorParent is not a nullptr
1284 info.setMotherProperties(ancestor); // FIXME difference in behaviour compared to MCTruthClassifier::defOrigOfElectron/Muon
1285 }
1286
1287 } while ((std::abs(pPDG) == nuFlav || MC::isTau(pPDG) || MC::isW(pPDG)));
1288
1289 if (std::abs(pPDG) == nuFlav || MC::isTau(pPDG) || MC::isW(pPDG) || MC::isZ(pPDG) || MC::isHiggs(pPDG) ||
1290 MC::isMSSMHiggs(pPDG) || MC::isHeavyBoson(pPDG) || MC::isTop(pPDG) || // MSSM Higgs bosons, Heavy bosons( Z', Z'', W'+)
1291 std::abs(pPDG) == MC::WBOSON_LRSM || MC::isNeutrinoRH(pPDG) || // Left-right symmetric model WBoson || Right-handed neutrino (Pythia-specific)
1292 MC::isSUSY(pPDG)) {
1293 ancestor = ancestorParent; // ancestorParent is not nullptr here
1294 info.setMotherProperties(ancestor);
1295 }
1296 }
1297 //if ancestor is still nullptr, we have a problem
1298 if (!ancestor) return NonDefined; // FIXME it should not be possible for ancestor to be nullptr at this point???
1299
1300 info.setMotherProperties(ancestor);
1301 const int ancestorPDG = ancestor->pdgId();
1302 partProdVtx = ancestor->decayVtx();
1303 const xAOD::TruthVertex* ancestorProdVtx = ancestor->hasProdVtx() ? ancestor->prodVtx() : nullptr;
1304 const int numOfParents = partProdVtx->nIncomingParticles();
1305 const int numberOfChildren = partProdVtx->nOutgoingParticles();
1306
1307 // Determine decay products
1308 auto DP = DecayProducts(partProdVtx);
1309 const int NumOfPhot = DP.pd(MC::PHOTON);
1310 const int NumOfquark = DP.apd({MC::DQUARK,MC::UQUARK,MC::SQUARK,MC::CQUARK,MC::BQUARK,MC::TQUARK});
1311 const int NumOfgluon = DP.apd(MC::GLUON);
1312 const int NumOfLQ = DP.apd(MC::LEPTOQUARK);
1313 const int NumOfElNeut = DP.apd(MC::NU_E);
1314 const int NumOfMuNeut = DP.apd(MC::NU_MU);
1315 const int NumOfTauNeut = DP.apd(MC::NU_TAU);
1316 const int NumOfEl = DP.apd(MC::ELECTRON);
1317 const int NumOfMu = DP.apd(MC::MUON);
1318 const int NumOfTau = DP.apd(MC::TAU);
1319
1320 samePart = false;
1321 for (const auto& aChild: partProdVtx->particles_out()) {
1322 if (!aChild) continue;
1323 if (aChild->pdgId() == ancestorPDG && HepMC::is_same_generator_particle(aChild,ancestor)) {
1324 samePart = true;
1325 break;
1326 }
1327 }
1328 // End of section determining decay products
1329
1330 // Quark weak decay
1331 if (MC::isQuark(ancestorPDG) && numOfParents == 1 && numberOfChildren == 3 && NumOfquark == 1 && (NumOfEl == 1 || NumOfMu == 1 || NumOfTau == 1)) return QuarkWeakDec;
1332 if (MC::isTop(ancestorPDG)) return top;
1333
1334 if (MC::isW(ancestorPDG) && ancestorProdVtx && ancestorProdVtx->nIncomingParticles() != 0) {
1335 const xAOD::TruthVertex* prodVert = ancestorProdVtx;
1336 const xAOD::TruthParticle* ptrPart;
1337 do {
1338 ptrPart = prodVert->incomingParticle(0); // FIXME just taking the first one
1339 prodVert = ptrPart->hasProdVtx() ? ptrPart->prodVtx() : nullptr;
1340 } while (MC::isW(ptrPart) && prodVert);
1341
1342 if (prodVert && prodVert->nIncomingParticles() == 1) {
1343 if (std::abs(ptrPart->pdgId()) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
1344 if (std::abs(ptrPart->pdgId()) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
1345 if (std::abs(ptrPart->pdgId()) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
1346 }
1347 return WBoson;
1348 }
1349 if (MC::isW(ancestorPDG)) return WBoson;
1350 if (MC::isZ(ancestorPDG)) return ZBoson;
1351
1352 //-- Exotics
1353
1354 // MadGraphPythia ZWW*->lllnulnu or ZWW*->nunulnulnu (don't even know if the latter is generated)
1355 if (numOfParents == 1 && numberOfChildren > 4 && (MC::isSMQuark(ancestorPDG) || MC::isGluon(ancestorPDG))) {
1356
1357 const xAOD::TruthParticle* thePartToCheck = thePriPart;
1358 const xAOD::TruthParticle* theParent = thePriPart->hasProdVtx() ? thePriPart->prodVtx()->incomingParticle(0) : nullptr; // FIXME just taking the first one
1359
1360 if (MC::isElectron(theParent) && MC::isDecayed(theParent)) { thePartToCheck = theParent; }
1361 bool isZboson = false;
1362 bool isWboson = false;
1363 bool skipnext = false;
1364
1365 for (unsigned int ipOut = 0; ipOut + 1 < partProdVtx->nOutgoingParticles(); ++ipOut) {
1366 const xAOD::TruthParticle* aChild = partProdVtx->outgoingParticle(ipOut);
1367 if (!aChild) continue;
1368 const xAOD::TruthParticle* theNextChild{};
1369 for (unsigned int ipOut1 = ipOut + 1; ipOut1 < partProdVtx->nOutgoingParticles(); ipOut1++) {
1370 theNextChild = partProdVtx->outgoingParticle(ipOut1);
1371 if (theNextChild) break;
1372 }
1373 if (!theNextChild) continue;
1374
1375 if (skipnext) {
1376 skipnext = false;
1377 continue;
1378 }
1379
1380 const int apdgID1 = std::abs(aChild->pdgId());
1381 const int apdgID2 = std::abs(theNextChild->pdgId());
1382 if (apdgID1 == apdgID2 && MC::isSMNeutrino(apdgID1)) {
1383 // Zboson
1384 if (thePartToCheck == aChild || thePartToCheck == theNextChild) {
1385 isZboson = true;
1386 break;
1387 }
1388 skipnext = true;
1389 } else if ((apdgID1 == MC::ELECTRON && apdgID2 == MC::NU_E) ||
1390 (apdgID1 == MC::NU_E && apdgID2 == MC::ELECTRON) ||
1391 (apdgID1 == MC::MUON && apdgID2 == MC::NU_MU) ||
1392 (apdgID1 == MC::NU_MU && apdgID2 == MC::MUON) ||
1393 (apdgID1 == MC::TAU && apdgID2 == MC::NU_TAU) ||
1394 (apdgID1 == MC::NU_TAU && apdgID2 == MC::TAU)
1395 ) {
1396 // WBoson
1397 if (thePartToCheck == aChild || thePartToCheck == theNextChild) {
1398 isWboson = true;
1399 break;
1400 }
1401 skipnext = true;
1402 }
1403 }
1404 if (isWboson) return WBoson;
1405 if (isZboson) return ZBoson;
1406 }
1407
1408 if (numOfParents == 2) {
1409 //--Sherpa Z->nunu
1410 if ( (numberOfChildren - NumOfquark - NumOfgluon) == 2 && (NumOfElNeut == 2 || NumOfMuNeut == 2 || NumOfTauNeut == 2)) return ZBoson;
1411
1412 //--Sherpa W->enu ??
1413 if ((numberOfChildren - NumOfquark - NumOfgluon) == 2 && ((NumOfEl == 1 && NumOfElNeut == 1) || (NumOfMu == 1 && NumOfMuNeut == 1) || (NumOfTau == 1 && NumOfTauNeut == 1))) return WBoson;
1414
1415 const int pdg1 = partProdVtx->incomingParticle(0)->pdgId();
1416 const int pdg2 = partProdVtx->incomingParticle(1)->pdgId();
1417 //--Sherpa ZZ,ZW
1418 if ( (numberOfChildren - NumOfquark - NumOfgluon) == 4 && (NumOfEl + NumOfMu + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 4) &&
1419 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return DiBoson;
1420
1421 //--Sherpa VVV -- Note, have to allow for prompt photon radiation or these get lost
1422 if ((numberOfChildren - NumOfquark - NumOfgluon - NumOfPhot) == 6 && (NumOfEl + NumOfMu + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 6) &&
1423 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return MultiBoson;
1424
1425 //--Sherpa Vgamma ( Z->nunu+gamma )
1426 if ((numberOfChildren - NumOfquark - NumOfgluon) >= 3 && NumOfPhot >= 1 && (NumOfElNeut == 2 || NumOfMuNeut == 2 || NumOfTauNeut == 2)) {
1427 ATH_MSG_VERBOSE("Sherpa nunu + gamma");
1428 return ZBoson;
1429 }
1430 }
1431
1432 // New Sherpa Z->nunu
1433 if (partProdVtx == ancestorProdVtx) {
1434 int NumOfLepLoop = 0;
1435 int NumOfNeuLoop = 0;
1436 for (const auto *const pout: partProdVtx->particles_out()) {
1437 if (!pout) continue;
1438 for (const auto *const pin: partProdVtx->particles_in()) {
1439 if (!pin) continue;
1440 if (HepMC::is_same_particle(pin,pout)) continue;
1441 const int apdgid = std::abs(pout->pdgId());
1442 if (MC::isSMLepton(apdgid)) {
1443 if (MC::isSMNeutrino(apdgid)) { NumOfNeuLoop++; }
1444 else { NumOfLepLoop++; }
1445 }
1446 break; // break out of inner loop after having found two matching particles
1447 }
1448 }
1449 if (NumOfNeuLoop == 2 && NumOfLepLoop == 0) return ZBoson;
1450 if (NumOfNeuLoop == 1 && NumOfLepLoop == 1) return WBoson;
1451 if (NumOfNeuLoop + NumOfLepLoop == 4) return DiBoson;
1452 }
1453
1454 //-- McAtNLo
1455
1456 if (MC::isHiggs(ancestorPDG)) return Higgs;
1457 if (MC::isMSSMHiggs(ancestorPDG)) return HiggsMSSM; // MSSM Higgs bosons
1458 if (MC::isHeavyBoson(ancestorPDG)) return HeavyBoson; // Heavy bosons( Z', Z'', W'+)
1459
1460 if (MC::isTau(ancestorPDG)) {
1461 const ParticleOrigin tauOrig = defOrigOfTau(xTruthParticleContainer, ancestor, ancestorPDG, info);
1462 const ParticleType tautype = defTypeOfTau(tauOrig);
1463 return (tautype == IsoTau)?tauOrig:TauLep;
1464 }
1465
1466 if (std::abs(ancestorPDG) == MC::WBOSON_LRSM) return WBosonLRSM; // Left-right symmetric model WBoson (Pythia-specific)
1467 if (std::abs(ancestorPDG) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
1468 if (std::abs(ancestorPDG) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
1469 if (std::abs(ancestorPDG) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
1470 if (MC::isLeptoQuark(ancestorPDG) || NumOfLQ != 0) return LQ;
1471 if (MC::isSUSY(ancestorPDG)) return SUSY;
1472 if (MC::isBSM(ancestorPDG)) return OtherBSM;
1473
1474 const ParticleType pType = defTypeOfHadron(ancestorPDG);
1475 if ((pType == BBbarMesonPart || pType == CCbarMesonPart) && ancestorProdVtx && MC::isHardScatteringVertex(ancestorProdVtx)) isPrompt = true;
1476
1477 return convHadronTypeToOrig(pType, ancestorPDG);
1478}
@ NonInteract
bool isSMNeutrino(const T &p)

◆ defOrigOfPhoton()

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

Definition at line 969 of file MCTruthClassifierGen.cxx.

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

Definition at line 778 of file MCTruthClassifierGen.cxx.

782{
783 ATH_MSG_DEBUG("Executing DefOrigOfTau ");
784
785 // Find the first copy of this particle stored in the xAOD::TruthParticleContainer (i.e. the particle prior to any interactions)
786 const xAOD::TruthParticle* thePriPart = MC::findMatching(xTruthParticleContainer, thePart);
787 if (!thePriPart) return NonDefined;
788 if (!MC::isTau(thePriPart)) return NonDefined;
789
790 //-- to define tau outcome status
791 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?
792
793 const xAOD::TruthVertex* partProdVtx = thePriPart->hasProdVtx() ? thePriPart->prodVtx() : nullptr;
794 if (!partProdVtx) return NonDefined;
795
796 if (partProdVtx->nIncomingParticles() > 1) ATH_MSG_DEBUG("DefOrigOfTau:: tau has more than one parent.");
797
798 const xAOD::TruthParticle* ancestor = MC::findMother(thePriPart);
799 info.setMotherProperties(ancestor);
800 if (!ancestor) { return NonDefined; } // ancestor is not a nullptr beyond this point
801
802 // "method 1" for finding Sherpa loops from defOrigOfElectron not used here. Why?
803
804 // Difference from defOrigOfElectron and defOrigOfMuon - no loop through ancestor particles
805
806 if (MC::isW(ancestorPDGin) && ancestor->hasProdVtx()) { // FIXME ancestorPDGin here could in principle be inconsistent with ancestorProdVtx
807 const xAOD::TruthParticle* ancestorParent = MC::findMother(ancestor);
808 if (ancestorParent && MC::isTop(ancestorParent->pdgId())) {
809 ancestor = ancestorParent; //...so ancestor cannot be nullptr
810 }
811 }
812
813 const int ancestorPDG = ancestor->pdgId();
814 info.setMotherProperties(ancestor);
815 const xAOD::TruthVertex* ancestorProdVtx = ancestor->hasProdVtx() ? ancestor->prodVtx() : nullptr;
816 partProdVtx = ancestor->decayVtx();
817 if (!partProdVtx) return NonDefined; // FIXME not sure this could ever be true?
818 const int numOfParents = partProdVtx->nIncomingParticles();
819
820 // Determine decay products
821 auto DP = DecayProducts(partProdVtx);
822 const int numberOfChildren = DP.size();
823 const int NumOfPhot = DP.pd(MC::PHOTON);
824 const int NumOfEl = DP.pd(MC::ELECTRON);
825 const int NumOfPos = DP.pd(MC::POSITRON);
826 const int NumOfElNeut = DP.apd(MC::NU_E);
827 const int NumOfMuNeut = DP.apd(MC::NU_MU);
828 /* const int NumOfLQ = DP.apd(MC::LEPTOQUARK); */ // FIXME Leptoquarks not an option?
829 const int NumOfquark = DP.apd({MC::DQUARK,MC::UQUARK,MC::SQUARK,MC::CQUARK,MC::BQUARK,MC::TQUARK});
830 const int NumOfgluon = DP.apd(MC::GLUON);
831 const int NumOfMuPl = DP.pd(-MC::MUON);
832 const int NumOfMuMin = DP.pd(MC::MUON);
833 const int NumOfTau = DP.apd(MC::TAU);
834 const int NumOfTauNeut = DP.apd(MC::NU_TAU);
835 // End of section determining decay products
836
837 if (MC::isTop(ancestorPDG)) return top;
838 if (MC::isW(ancestorPDG) && ancestorProdVtx && ancestorProdVtx->nIncomingParticles() != 0) {
839 const xAOD::TruthVertex* prodVert = ancestorProdVtx;
840 const xAOD::TruthParticle* itrP;
841 do {
842 itrP = prodVert->incomingParticle(0); // FIXME just taking the first one
843 prodVert = itrP->hasProdVtx() ? itrP->prodVtx() : nullptr;
844 } while (MC::isW(itrP) && prodVert);
845
846 if (prodVert && prodVert->nIncomingParticles() == 1 ) {
847 if (std::abs(itrP->pdgId()) == MC::RH_NU_E) return NuREle; // Right-handed NU_E (Pythia-specific)
848 if (std::abs(itrP->pdgId()) == MC::RH_NU_MU) return NuRMu; // Right-handed NU_MU (Pythia-specific)
849 if (std::abs(itrP->pdgId()) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
850 }
851 return WBoson;
852 }
853 if (MC::isW(ancestorPDG)) { return WBoson;}
854 if (MC::isZ(ancestorPDG)) { return ZBoson;}
855 if (numOfParents == 1 && numberOfChildren > 4 && (MC::isSMQuark(ancestorPDG) || MC::isGluon(ancestorPDG))) {
856 bool isZboson = false;
857 bool isWboson = false;
858 bool skipnext = false;
859 for (unsigned int ipOut = 0; ipOut + 1 < partProdVtx->nOutgoingParticles(); ipOut++) {
860 if (skipnext) {
861 skipnext = false;
862 continue;
863 }
864 const xAOD::TruthParticle* aChild = partProdVtx->outgoingParticle(ipOut);
865 if (!aChild) continue;
866 const xAOD::TruthParticle* theNextChild{};
867 for (unsigned int ipOut1 = ipOut + 1; ipOut1 < partProdVtx->nOutgoingParticles(); ipOut1++) {
868 theNextChild = partProdVtx->outgoingParticle(ipOut1);
869 if (theNextChild) break;
870 }
871 if (!theNextChild) {
872 continue;
873 }
874 if (MC::isTau(aChild) && MC::isTau(theNextChild)) {
875 // Zboson
876 if (thePriPart == aChild || thePriPart == theNextChild) {
877 isZboson = true;
878 break;
879 }
880 skipnext = true;
881 } else if (MC::isTau(aChild) && std::abs(theNextChild->pdgId()) == MC::NU_TAU) {
882 // WBoson
883 if (thePriPart == aChild || thePriPart == theNextChild) {
884 isWboson = true;
885 break;
886 }
887 skipnext = true;
888 }
889 }
890 if (isWboson) return WBoson;
891 if (isZboson) return ZBoson;
892 }
893 if (numOfParents == 2 ) {
894 const int pdg1 = partProdVtx->incomingParticle(0)->pdgId();
895 const int pdg2 = partProdVtx->incomingParticle(1)->pdgId();
896 //--Sherpa Z->tautau
897 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?
898
899 //--Sherpa W->taunu new
900 if ((numberOfChildren - NumOfquark - NumOfgluon) == 2 && NumOfTau == 1 && NumOfTauNeut == 1) return WBoson;
901
902 //--Sherpa ZZ,ZW
903 if ((numberOfChildren - NumOfquark - NumOfgluon) == 4 &&
904 (NumOfEl + NumOfPos + NumOfMuPl + NumOfMuMin + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 4) &&
905 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return DiBoson;
906
907 //--Sherpa VVV -- Note, have to allow for prompt photon radiation or these get lost
908 if ((numberOfChildren - NumOfquark - NumOfgluon - NumOfPhot) == 6 &&
909 (NumOfEl + NumOfPos + NumOfMuPl + NumOfMuMin + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 6) &&
910 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) return MultiBoson;
911
912 //--Sherpa tttt with all t->Wb; W->lnu
913 if ((numberOfChildren - NumOfquark - NumOfgluon) == 8 &&
914 (NumOfEl + NumOfPos + NumOfMuPl + NumOfMuMin + NumOfTau + NumOfElNeut + NumOfMuNeut + NumOfTauNeut == 8) &&
915 (MC::isQuark(pdg1)||MC::isGluon(pdg1)) && (MC::isQuark(pdg2)||MC::isGluon(pdg2))) {
916 ATH_MSG_VERBOSE("MultiBoson for 4topLep");
917 return MultiBoson;
918 }
919
920 //--Sherpa Vgamma ( Z->tautau+gamma or W->taunu+gamma )
921 if ((numberOfChildren - NumOfquark - NumOfgluon) >= 3 && NumOfPhot >= 1 && NumOfTau == 2) {
922 ATH_MSG_VERBOSE("Sherpa tautau + gamma");
923 return ZBoson;
924 }
925 if ((numberOfChildren - NumOfquark - NumOfgluon) >= 3 && NumOfPhot >= 1 && NumOfTau == 1 && NumOfTauNeut == 1) {
926 ATH_MSG_VERBOSE("Sherpa taunu + gamma");
927 return WBoson;
928 }
929 }
930
931 // New Sherpa Z->tautau
932 if (partProdVtx == ancestorProdVtx) {
933 int NumOfTauLoop = 0;
934 int NumOfTauNeuLoop = 0;
935 int NumOfLepLoop = 0;
936 for ( const auto *const pout: partProdVtx->particles_out()) {
937 if (!pout) continue;
938 for (const auto *const pin: partProdVtx->particles_in()) {
939 if (!pin) continue;
940 if (!HepMC::is_same_particle(pout,pin)) continue;
941 if (MC::isTau(pout)) NumOfTauLoop++;
942 if (std::abs(pout->pdgId()) == MC::NU_TAU) NumOfTauNeuLoop++;
943 if (MC::isSMLepton(pout)) NumOfLepLoop++;
944 break; // break out of inner loop after having found two matching particles
945 }
946 }
947 if (NumOfTauLoop == 2 && NumOfTauNeuLoop == 0) return ZBoson;
948 if (NumOfTauLoop == 1 && NumOfTauNeuLoop == 1) return WBoson;
949 if ((NumOfTauLoop == 4 && NumOfTauNeuLoop == 0) || (NumOfTauLoop == 3 && NumOfTauNeuLoop == 1) || (NumOfTauLoop == 2 && NumOfTauNeuLoop == 2)) return DiBoson;
950 if (NumOfLepLoop == 4) return DiBoson;
951 }
952
953 //-- McAtNLo
954
955 if (MC::isHiggs(ancestorPDG)) return Higgs;
956 if (MC::isMSSMHiggs(ancestorPDG)) return HiggsMSSM; // MSSM Higgs bosons
957 if (MC::isHeavyBoson(ancestorPDG)) return HeavyBoson; // Heavy bosons( Z', Z'', W'+)
958 if (std::abs(ancestorPDG) == MC::WBOSON_LRSM) return WBosonLRSM; // Left-right symmetric model WBoson (Pythia-specific)
959 if (std::abs(ancestorPDG) == MC::RH_NU_TAU) return NuRTau; // Right-handed NU_TAU (Pythia-specific)
960 if (MC::isSUSY(ancestorPDG)) return SUSY;
961 if (MC::isBSM(ancestorPDG)) return OtherBSM;
962 if (std::abs(ancestorPDG) == MC::JPSI) return JPsi;
963
964 const ParticleType pType = defTypeOfHadron(ancestorPDG);
965 return convHadronTypeToOrig(pType, ancestorPDG);
966}
@ 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
inlineprivateinherited

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
inlineprivateinherited

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
finaloverridevirtualinherited

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
float m_FwdElectronTruthExtrEtaWindowCut
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
privateinherited

Definition at line 274 of file MCRecoToTruth.cxx.

277{
278 if (DR) {
279 // use a DR matching scheme (default)
280 // retrieve collection and get a pointer
281 SG::ReadHandle<xAOD::TruthParticleContainer> truthParticleContainerReadHandle(m_truthParticleContainerKey);
282
283 if (!truthParticleContainerReadHandle.isValid()) {
284 ATH_MSG_WARNING(" Invalid ReadHandle for xAOD::TruthParticleContainer with key: " << truthParticleContainerReadHandle.key());
285 return;
286 }
287 ATH_MSG_DEBUG("xAODTruthParticleContainer with key " << truthParticleContainerReadHandle.key() << " has valid ReadHandle ");
288 // find the matching truth particles
289 for (const auto *const thePart : *truthParticleContainerReadHandle) {
290 // match truth particles to the jet
291 if (MC::isStable(thePart) && thePart->p4().DeltaR(jet->p4()) < m_jetPartDRMatch) {
292 constituents.insert(thePart);
293 }
294 }
295 }
296 else {
297 xAOD::JetConstituentVector vec = jet->getConstituents();
298 for (const auto *particle0 : vec) {
299 const xAOD::TruthParticle* thePart = dynamic_cast<const xAOD::TruthParticle*>(particle0->rawConstituent());
300 if (MC::isStable(thePart)) {
301 constituents.insert(thePart);
302 }
303 }
304 }
305}
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:149

◆ fracParticleInJet()

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

Definition at line 306 of file MCRecoToTruth.cxx.

307{
308 std::set<const xAOD::TruthParticle*> constituents;
309 std::set<const xAOD::TruthParticle*> daughters;
310 std::set<const xAOD::TruthParticle*> intersect;
311
312 findJetConstituents(jet, constituents, DR);
313 MC::findParticleStableDescendants(thePart, daughters);
314 if (daughters.empty()) daughters.insert(thePart);
315 // Get the intersection of constituents and daughters
316 std::set_intersection(constituents.begin(),
317 constituents.end(),
318 daughters.begin(),
319 daughters.end(),
320 std::inserter(intersect, intersect.begin()));
321
322 if (nparts) return 1.0*intersect.size() / daughters.size();
323 double frac = 0;
324 double tot = 0;
325 for (const auto *daughter : daughters) { tot += daughter->pt();}
326 for (const auto *particle : intersect) { frac += particle->pt();}
327 return frac/tot;
328}
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
privateinherited

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)

◆ get_tptruth_name()

bool D3PD::D3PDMCTruthClassifier::get_tptruth_name ( const std::string & tp_name,
std::string & tptruth_name )
private

Try to find a TrackParticleTruthCollection pointing at TP_NAME.

Parameters
tp_nameThe name of a TrackParticleContainer.
tptruth_name[out]The name of a TrackParticleTruthCollection pointing at it.
Returns
True if we found a good truth collection.

Definition at line 174 of file D3PDMCTruthClassifier.cxx.

176{
177 // Check all TrackParticleTruthCollections to try to find one
178 // pointing at the desired TrackParticle container.
179 std::vector<std::string> keys;
181
182 for (size_t i = 0; i < keys.size(); i++) {
183 const TrackParticleTruthCollection* tptc = 0;
184 if (m_sg->retrieve (tptc, keys[i]).isFailure() || !tptc)
185 {
186 ATH_MSG_WARNING( "Can't retrieve TrackParticleTruthCollection/"
187 << keys[i] );
188 continue;
189 }
190 tptruth_name = keys[i];
191
192 std::string target_tp_name;
194 // Older files didn't have this link. Hardcode this case.
195 target_tp_name = "TrackParticleCandidate";
196 }
197 else if (!tptc->trackParticleContainerLink().isValid())
198 continue;
199 else
200 target_tp_name = tptc->trackParticleContainerLink().dataID();
201
202 if (tp_name == target_tp_name)
203 return true;
204 }
205 return false;
206}
Athena::TPCnvVers::Old TrackParticleTruthCollection
bool isDefault() const
Test to see if we're in the default state.
DataLink< Rec::TrackParticleContainer > trackParticleContainerLink() const

◆ getGenPart()

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

Implements IMCTruthClassifier.

Definition at line 177 of file MCRecoToTruth.cxx.

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

◆ getProperty1()

void D3PD::D3PDMCTruthClassifier::getProperty1 ( const std::string & pname,
std::string & value )
private

Helper to retrieve the value of a Gaudi property.

Parameters
pnameThe name of the property. param value[out] The value of the property.

Definition at line 214 of file D3PDMCTruthClassifier.cxx.

216{
217 StatusCode sc = getProperty (pname, value);
218 if (sc.isFailure())
219 REPORT_ERROR (sc) << "Can't get property " << pname << "\n";
220}
#define REPORT_ERROR(SC)
Report an error.
static Double_t sc
const T * getProperty(const std::string &name) const
Get one of the tool's properties.
::StatusCode StatusCode
StatusCode definition for legacy code.

◆ initialize()

StatusCode D3PD::D3PDMCTruthClassifier::initialize ( void )
virtual

Standard Gaudi initialize method.

Reimplemented from MCTruthClassifier.

Definition at line 51 of file D3PDMCTruthClassifier.cxx.

52{
54 CHECK( m_sg.retrieve() );
55 return StatusCode::SUCCESS;
56}
#define CHECK(...)
Evaluate an expression and check for errors.
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.

◆ 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
finaloverridevirtualinherited

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
SG::ReadHandleKey< xAODTruthParticleLinkVector > m_truthLinkVecReadHandleKey

◆ particleTruthClassifier() [1/8]

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

Reimplemented from MCTruthClassifier.

Definition at line 143 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 std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOrigin > particleTruthClassifier(const xAOD::Electron *el)
Run the classifier for an electron.
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() [2/8]

std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOrigin > D3PD::D3PDMCTruthClassifier::particleTruthClassifier ( const xAOD::Electron * el)
virtual

Run the classifier for an electron.

Parameters
elThe input electron.

Definition at line 65 of file D3PDMCTruthClassifier.cxx.

66{
67 // Try to find the name of the truth map container,
68 // given the name of the TrackParticleContainer.
69 bool got_names = false;
70 std::string tp_truth_name, tp_name;
71 if (el->trackParticleLink().isValid()) {
72 tp_name = el->trackParticleLink().dataID();
73 got_names = get_tptruth_name (tp_name, tp_truth_name);
74 }
75
76 // If we found the truth map container, diddle the properties
77 // for the base tool (remembering the original values).
78 std::string old_tp_truth_name, old_tp_name;
79 if (got_names) {
80 getProperty1 ("TrackParticleTruthCollection", old_tp_truth_name);
81 getProperty1 ("TrackParticleContainerName", old_tp_name);
82 setProperty1 ("TrackParticleTruthCollection", tp_truth_name);
83 setProperty1 ("TrackParticleContainerName", tp_name);
84 }
85
86 // Call the base tool.
90
91 // Restore original properties, if we changed them.
92 if (got_names) {
93 setProperty1 ("TrackParticleTruthCollection", old_tp_truth_name);
94 setProperty1 ("TrackParticleContainerName", old_tp_name);
95 }
96
97 return ret;
98}
bool get_tptruth_name(const std::string &tp_name, std::string &tptruth_name)
Try to find a TrackParticleTruthCollection pointing at TP_NAME.
void setProperty1(const std::string &pname, const std::string &value)
Helper to set the value of a Gaudi property.
void getProperty1(const std::string &pname, std::string &value)
Helper to retrieve the value of a Gaudi property.

◆ particleTruthClassifier() [3/8]

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

Reimplemented from MCTruthClassifier.

Definition at line 155 of file MCRecoToTruth.cxx.

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

std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOrigin > D3PD::D3PDMCTruthClassifier::particleTruthClassifier ( const xAOD::Muon * mu)
virtual

Run the classifier for a muon.

This function is here to avoid a problem on the mc12 validation samples.

Parameters
elThe input photon.

Definition at line 155 of file D3PDMCTruthClassifier.cxx.

156{
157 // Avoid using forward muons that have a tracklet associated to them:
158 if( mu->muonType() == xAOD::Muon::SiliconAssociatedForwardMuon ) {
160 }
161
162 // For all other muons just use the base class's function:
164}

◆ particleTruthClassifier() [5/8]

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

Reimplemented from MCTruthClassifier.

Definition at line 146 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/8]

std::pair< MCTruthPartClassifier::ParticleType, MCTruthPartClassifier::ParticleOrigin > D3PD::D3PDMCTruthClassifier::particleTruthClassifier ( const xAOD::Photon * ph)
virtual

Run the classifier for a photon.

Parameters
elThe input photon.

Definition at line 107 of file D3PDMCTruthClassifier.cxx.

108{
109 // Try to find the name of the truth map container,
110 // given the name of the TrackParticleContainer.
111 bool got_names = false;
112 std::string tp_truth_name, tp_name;
113 const xAOD::Vertex* vx = ph->vertex();
114 if (vx) {
116 for (auto trklink : links) {
117 if (trklink.isValid()) {
118 tp_name = trklink.dataID();
119 got_names = get_tptruth_name (tp_name, tp_truth_name);
120 if (got_names) break;
121 }
122 }
123 }
124
125 // If we found the truth map container, diddle the properties
126 // for the base tool (remembering the original values).
127 std::string old_tp_truth_name, old_tp_name;
128 if (got_names) {
129 getProperty1 ("TrackParticleTruthCollection", old_tp_truth_name);
130 getProperty1 ("TrackParticleContainerName", old_tp_name);
131 setProperty1 ("TrackParticleTruthCollection", tp_truth_name);
132 setProperty1 ("TrackParticleContainerName", tp_name);
133 }
134
135 // Call the base tool.
139
140 // Restore original properties, if we changed them.
141 if (got_names) {
142 setProperty1 ("TrackParticleTruthCollection", old_tp_truth_name);
143 setProperty1 ("TrackParticleContainerName", old_tp_name);
144 }
145
146 return ret;
147}
const TrackParticleLinks_t & trackParticleLinks() const
Get all the particles associated with the vertex.
std::vector< ElementLink< xAOD::TrackParticleContainer > > TrackParticleLinks_t
Type for the associated track particles.
Definition Vertex_v1.h:128

◆ particleTruthClassifier() [7/8]

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

Reimplemented from MCTruthClassifier.

Definition at line 140 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() [8/8]

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

Reimplemented from MCTruthClassifier.

Definition at line 122 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()

void asg::AsgTool::print ( ) const
virtualinherited

◆ 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 }

◆ setProperty1()

void D3PD::D3PDMCTruthClassifier::setProperty1 ( const std::string & pname,
const std::string & value )
private

Helper to set the value of a Gaudi property.

Parameters
pnameThe name of the property. param value The new value of the property.

Definition at line 228 of file D3PDMCTruthClassifier.cxx.

230{
231 StatusCode sc = setProperty (pname, value);
232 if (sc.isFailure())
233 REPORT_ERROR (sc) << "Can't set property " << pname << "\n";
234}
void setProperty(columnar::PythonToolHandle &self, const std::string &key, nb::object value)

◆ 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
privateinherited

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
privateinherited

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
privateinherited

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",""}
privateinherited

Definition at line 226 of file MCTruthClassifier.h.

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

◆ m_caloMgrKey

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

Definition at line 227 of file MCTruthClassifier.h.

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

◆ m_deltaPhiMatchCut

float MCTruthClassifier::m_deltaPhiMatchCut
privateinherited

Definition at line 254 of file MCTruthClassifier.h.

◆ m_deltaRMatchCut

float MCTruthClassifier::m_deltaRMatchCut
privateinherited

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
privateinherited

Definition at line 232 of file MCTruthClassifier.h.

◆ m_FwdElectronTruthExtrEtaWindowCut

float MCTruthClassifier::m_FwdElectronTruthExtrEtaWindowCut
privateinherited

Definition at line 233 of file MCTruthClassifier.h.

◆ m_FwdElectronUseG4Sel

bool MCTruthClassifier::m_FwdElectronUseG4Sel
privateinherited

Definition at line 231 of file MCTruthClassifier.h.

◆ m_fwrdEledRtoTrCut

float MCTruthClassifier::m_fwrdEledRtoTrCut
privateinherited

Definition at line 240 of file MCTruthClassifier.h.

◆ m_inclG4part

bool MCTruthClassifier::m_inclG4part
privateinherited

Definition at line 245 of file MCTruthClassifier.h.

◆ m_jetPartDRMatch

float MCTruthClassifier::m_jetPartDRMatch
privateinherited

Definition at line 256 of file MCTruthClassifier.h.

◆ m_NumOfSiHitsCut

int MCTruthClassifier::m_NumOfSiHitsCut
privateinherited

Definition at line 255 of file MCTruthClassifier.h.

◆ m_partExtrConeEta

float MCTruthClassifier::m_partExtrConeEta
privateinherited

Definition at line 234 of file MCTruthClassifier.h.

◆ m_partExtrConePhi

float MCTruthClassifier::m_partExtrConePhi
privateinherited

Definition at line 235 of file MCTruthClassifier.h.

◆ m_phtClasConeEta

float MCTruthClassifier::m_phtClasConeEta
privateinherited

Definition at line 238 of file MCTruthClassifier.h.

◆ m_phtClasConePhi

float MCTruthClassifier::m_phtClasConePhi
privateinherited

Definition at line 237 of file MCTruthClassifier.h.

◆ m_phtdRtoTrCut

float MCTruthClassifier::m_phtdRtoTrCut
privateinherited

Definition at line 239 of file MCTruthClassifier.h.

◆ m_pTChargePartCut

float MCTruthClassifier::m_pTChargePartCut
privateinherited

Definition at line 243 of file MCTruthClassifier.h.

◆ m_pTNeutralPartCut

float MCTruthClassifier::m_pTNeutralPartCut
privateinherited

Definition at line 244 of file MCTruthClassifier.h.

◆ m_ROICone

bool MCTruthClassifier::m_ROICone
privateinherited

Definition at line 241 of file MCTruthClassifier.h.

◆ m_sg

ServiceHandle<StoreGateSvc> D3PD::D3PDMCTruthClassifier::m_sg
private

The StoreGate service.

Definition at line 119 of file D3PDMCTruthClassifier.h.

◆ m_truthInConeTool

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

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"}
privateinherited

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"}
privateinherited

Definition at line 223 of file MCTruthClassifier.h.

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

◆ m_useCaching

bool MCTruthClassifier::m_useCaching
privateinherited

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: