ATLAS Offline Software
CopyTruthJetParticles.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4 
10 
15 #include "AsgMessaging/Check.h"
18 
19 #include <mutex> // std::call_once, std::once_flag
20 
21 #ifndef XAOD_STANDALONE
22 // Usage of metadata is for now only possible in Athena...
23 //#include "CoralBase/AttributeListException.h"
25 #endif
26 
27 // For std::find in comesFrom()
28 #include <algorithm>
29 
30 using namespace std;
31 using namespace MCTruthPartClassifier;
32 
34  : AsgTool(name) {}
35 
37 
39  ATH_CHECK(m_outTruthPartKey.initialize());
40  ATH_CHECK(m_dressingNames.initialize());
41 
42  // ATLASRECTS-8290: this is for backward compatability, remove eventually
43  if (m_use_barcode) m_uid = SG::ConstAccessor<int>("barcode");
44 
45  return StatusCode::SUCCESS;
46 }
47 
48 
49 
51  std::vector<const xAOD::TruthParticle*>& promptLeptons,
52  std::map<const xAOD::TruthParticle*,unsigned int>& tc_results) const {
53 
54  // Needed for the dressed photon decorations
55  const EventContext& ctx = Gaudi::Hive::currentContext();
56 
57  // Check if this thing is a candidate to be in a truth jet
58  // First block is largely copied from isGenStable, which works on HepMC only
59  if (HepMC::is_simulation_particle(tp)) return false; // Particle is from G4
60  int pdgid = tp->pdgId();
61  if (MC::isZeroEnergyPhoton(tp)) return false; // Work around for an old generator bug
62 
63  // -- changed for dark jet clustering -- //
64  if ( !MC::isStable(tp) && !m_includeDark ) return false; // dark hadrons will not be status 1
65  // ----------------------------------- //
66 
67  // Easy classifiers by PDG ID
68  if(MC::isNeutrino(pdgid)) {
69  if (!m_includeNu) return false;
70  } else {
71  if (!m_includeBSMNonInt && !MC::isInteracting(pdgid)) return false;
72  }
73  if (!m_includeMu && MC::isMuon(pdgid)) return false;
74 
75  // Already built a list of prompt leptons, just use it here
76  if (!m_includePromptLeptons && std::find(promptLeptons.begin(),promptLeptons.end(),tp)!=promptLeptons.end()){
77  ATH_MSG_VERBOSE("Veto prompt lepton (" << pdgid << ") with pt " << tp->pt());
78  return false;
79  }
80 
81  // Extra catch. If we aren't supposed to include prompt leptons, we aren't supposed to include prompt neutrinos
82  unsigned int tc_res = getTCresult(tp, tc_results);
84  return false;
85  }
86 
87  // -- added for dark jet clustering -- //
88  // new classifiers to account for dark particles
89  // for dark jets: ignore SM particles; include only "stable" dark hadrons
90  if (!m_includeSM && !MC::isHiddenValley(tp)) return false;
91  if (m_includeDark) {
92  if (abs(tp->pdgId()) <= 4900101) return false; // ignore Xd, qd, gd
93  if (tp->hasDecayVtx()) {
94  size_t good_hadrons = 0;
95  for (size_t p = 0; p < tp->end_vertex()->nOutgoingParticles(); ++p) {
96  if (!MC::isHiddenValley(tp->child(p))) {
97  good_hadrons++;
98  }
99  }
100  if (good_hadrons == 0) return false; // ignore "non-stable" dark hadrons (decaying to dark sector) -- "stable" if decaying to SM
101  }
102  }
103  // for SM jets: ignore dark particles - probably unnecessary bc of status requirement above
104  if (!m_includeDark && MC::isHiddenValley(tp)) return false;
105  // ----------------------------------- //
106 
107  if (!m_includePromptPhotons && MC::isPhoton(pdgid) && tp->hasProdVtx()){
108  //ParticleOrigin orig = getPartOrigin(tp, originMap);
109  //if (orig==Higgs || orig==HiggsMSSM) return false;
110  if (MCTruthPartClassifier::isPrompt(tc_res)) return false;
111  }
112 
113  // If we want to remove photons via the dressing decoration
114  if (!m_dressingNames.empty()){
115  // Accessor for the dressing decoration above
116  bool foundDressDec{false};
117  for(const auto &decName : m_dressingNames){
119  if (MC::isPhoton(pdgid) && dressAcc(*tp)) foundDressDec = true;
120  }
121  if (foundDressDec) return false;
122  } // End of removal via dressing decoration
123 
124  // Pseudo-rapidity cut
125  if(std::abs(tp->eta())>m_maxAbsEta) return false;
126 
127  // Vetoes of specific origins. Not fast, but if no particles are specified should not execute
128  if (m_vetoPDG_IDs.size()>0){
129  std::vector<int> used_vertices;
130  for (int anID : m_vetoPDG_IDs){
131  used_vertices.clear();
132  if (comesFrom(tp,anID,used_vertices)) return false;
133  }
134  }
135 
136  // Made it!
137  return true;
138 }
139 
140 
142  std::map<const xAOD::TruthParticle*,unsigned int>& tc_results) const
143 {
144  if(tc_results.find(tp) == tc_results.end()) {
145  const unsigned int result = tp ? std::get<0>(MCTruthPartClassifier::defOrigOfParticle(tp)) : 0;
146  tc_results[tp] = result;
147  }
148  return tc_results[tp];
149 }
150 
152 
153  // retrieve barcode Offset for this event from metadata.
154  // We'd need a cleaner solution where this offset is set only at
155  // each new file, but this requires some tool interface which does
156  // not exist in RootCore yet.
157  // So we use the less disruptive solution in Athena for now...
158 
159  // the function used below is
160  // std::call_once(metaDataFlag,basicMetaDataCheck(), this);
161  // std::call_once(metaDataFlag,this->basicMetaDataCheck());
162  // the syntax is explained in http://stackoverflow.com/questions/23197333/why-is-this-pointer-needed-when-calling-stdcall-once
163  // this syntax requires the call_once function to receive the object the function is called upon
164  //": these are all non-static member functions , they act on objects
165  // they need the "this" pointer which always point to the object the function is working on
166  //http://www.learncpp.com/cpp-tutorial/812-static-member-functions/
167 
168  std::vector<const xAOD::TruthParticle*> promptLeptons;
169  promptLeptons.reserve(10);
170 
171  // Retrieve the xAOD truth objects
172  auto truthParticles = SG::makeHandle(m_truthParticleKey);
173  if ( !truthParticles.isValid() ) {
174  ATH_MSG_ERROR("Failed to retrieve truth particle container " << m_truthParticleKey.key());
175  return 1;
176  }
177 
178  // Classify particles for tagging and add to the TruthParticleContainer
179  std::unique_ptr<ConstDataVector<xAOD::TruthParticleContainer> > ptruth(new ConstDataVector<xAOD::TruthParticleContainer>(SG::VIEW_ELEMENTS));
180  std::map<const xAOD::TruthParticle*,unsigned int> tc_results;
181  tc_results.clear();
182  size_t numCopied = 0;
183 
184  for (const xAOD::TruthParticle* tp : *truthParticles) {
185  if(!tp) continue;
186  if (tp->pt() < m_ptmin)
187  continue;
188  // Cannot use the truth helper functions; they're written for HepMC
189  // Last two switches only apply if the thing is a lepton and not a tau
190  if ((MC::isElectron(tp) || MC::isMuon(tp)) && tp->hasProdVtx()) {
191  // If this is a prompt, generator stable lepton, then we can use it
193  promptLeptons.push_back(tp);
194  }
195  }
196  }
197 
198  for (const xAOD::TruthParticle* tp : *truthParticles) {
199  if(!tp) continue;
200  if (tp->pt() < m_ptmin)
201  continue;
202 
203  if (classifyJetInput(tp, promptLeptons, tc_results)) {
204  ptruth->push_back(tp);
205  numCopied += 1;
206  }
207  }
208 
209  ATH_MSG_DEBUG("Copied " << numCopied << " truth particles into " << m_outTruthPartKey.key() << " TruthParticle container");
210 
211  // record
212  auto truthParticles_out = SG::makeHandle(m_outTruthPartKey);
213  ATH_MSG_DEBUG("Recorded truth particle collection " << m_outTruthPartKey.key());
214  // notify
215  if (!truthParticles_out.put(std::move(ptruth))) {
216  ATH_MSG_ERROR("Unable to write new TruthParticleContainer to event store: "
217  << m_outTruthPartKey.key());
218  } else {
219  ATH_MSG_DEBUG("Created new TruthParticleContainer in event store: "
220  << m_outTruthPartKey.key());
221  }
222 
223  return 0;
224 }
225 
226 
227 bool CopyTruthJetParticles::comesFrom( const xAOD::TruthParticle* tp, const int pdgID, std::vector<int>& used_vertices ) const {
228  // If it's not a particle, then it doesn't come from something...
229  if (!tp) return false;
230  // If it doesn't have a production vertex or has no parents, it doesn't come from much of anything
231  if (!tp->prodVtx() || tp->nParents()==0) return false;
232  // If we have seen it before, then skip this production vertex
233  // ATLASRECTS-8290: this should be replaced with ->uid()
234  if (std::find(used_vertices.begin(),used_vertices.end(), m_uid(*tp->prodVtx()))!=used_vertices.end()) return false;
235  // Add the production vertex to our used list
236  // ATLASRECTS-8290: this should be replaced with ->uid()
237  used_vertices.push_back( m_uid(*tp->prodVtx()) );
238  // Loop over the parents
239  for (size_t par=0;par<tp->nParents();++par){
240  // Check for null pointers in case of skimming
241  if (!tp->parent(par)) continue;
242  // Check for a match
243  if (tp->parent(par)->absPdgId()==pdgID) return true;
244  // Recurse on this parent
245  if (comesFrom(tp->parent(par), pdgID, used_vertices)) return true;
246  }
247  // No hits -- all done with the checks!
248  return false;
249 }
250 
WriteHandle.h
Handle class for recording to StoreGate.
Check.h
get_generator_info.result
result
Definition: get_generator_info.py:21
find
std::string find(const std::string &s)
return a remapped string
Definition: hcg.cxx:135
CopyTruthJetParticles::m_includeSM
Gaudi::Property< bool > m_includeSM
Definition: CopyTruthJetParticles.h:82
CopyTruthJetParticles::comesFrom
bool comesFrom(const xAOD::TruthParticle *tp, const int pdgID, std::vector< int > &used_vertices) const
Definition: CopyTruthJetParticles.cxx:227
SG::VIEW_ELEMENTS
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
Definition: OwnershipPolicy.h:18
CurrentContext.h
isHiddenValley
bool isHiddenValley(const T &p)
PDG rule 11k Hidden Valley particles have n = 4 and n_r = 9, and trailing numbers in agreement with t...
Definition: AtlasPID.h:668
ConstDataVector.h
DataVector adapter that acts like it holds const pointers.
TruthParticleContainer.h
isNeutrino
bool isNeutrino(const T &p)
APID: the fourth generation neutrinos are neutrinos.
Definition: AtlasPID.h:212
ParticleTest.tp
tp
Definition: ParticleTest.py:25
CopyTruthJetParticles::m_maxAbsEta
Gaudi::Property< float > m_maxAbsEta
Maximum allowed eta for particles in jets.
Definition: CopyTruthJetParticles.h:63
CopyTruthJetParticles::m_truthParticleKey
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_truthParticleKey
Key for input truth event.
Definition: CopyTruthJetParticles.h:51
SG::ConstAccessor< int >
MCTruthClassifier.h
MCTruthPartClassifier::defOrigOfParticle
std::tuple< unsigned int, T > defOrigOfParticle(T thePart)
Definition: TruthClassifiers.h:151
CopyTruthJetParticles::m_includeDark
Gaudi::Property< bool > m_includeDark
Definition: CopyTruthJetParticles.h:84
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
SG::VarHandleKey::key
const std::string & key() const
Return the StoreGate ID for the referenced object.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:141
CopyTruthJetParticles::m_includeMu
Gaudi::Property< bool > m_includeMu
Definition: CopyTruthJetParticles.h:73
SG::makeHandle
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
Definition: ReadCondHandle.h:274
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:209
CopyTruthJetParticles::m_use_barcode
Gaudi::Property< bool > m_use_barcode
Definition: CopyTruthJetParticles.h:88
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
SG::ReadDecorHandle
Handle class for reading a decoration on an object.
Definition: StoreGate/StoreGate/ReadDecorHandle.h:94
HepMC::is_simulation_particle
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...
Definition: MagicNumbers.h:354
CopyTruthJetParticles::m_uid
SG::ConstAccessor< int > m_uid
Definition: CopyTruthJetParticles.h:91
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
xAOD::EgammaHelpers::isElectron
bool isElectron(const xAOD::Egamma *eg)
is the object an electron (not Fwd)
Definition: EgammaxAODHelpers.cxx:12
xAOD::TruthParticle_v1
Class describing a truth particle in the MC record.
Definition: TruthParticle_v1.h:37
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
CopyTruthJetParticles::m_includePromptLeptons
Gaudi::Property< bool > m_includePromptLeptons
Definition: CopyTruthJetParticles.h:75
TruthVertex.h
CopyTruthJetParticles.h
CopyTruthJetParticles::m_includePromptPhotons
Gaudi::Property< bool > m_includePromptPhotons
Definition: CopyTruthJetParticles.h:77
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:240
createCoolChannelIdFile.par
par
Definition: createCoolChannelIdFile.py:28
MagicNumbers.h
CopyTruthJetParticles::execute
virtual int execute() const override final
redefine execute so we can call our own classify()
Definition: CopyTruthJetParticles.cxx:151
CopyTruthJetParticles::m_includeBSMNonInt
Gaudi::Property< bool > m_includeBSMNonInt
Definition: CopyTruthJetParticles.h:69
ReadHandle.h
Handle class for reading from StoreGate.
CopyTruthJetParticles::m_ptmin
Gaudi::Property< float > m_ptmin
Minimum pT for particle selection (in MeV)
Definition: CopyTruthJetParticles.h:60
AthAnalysisHelper.h
MC::isStable
bool isStable(const T &p)
Identify if the particle is stable, i.e. has not decayed.
Definition: HepMCHelpers.h:45
CopyTruthJetParticles::classifyJetInput
bool classifyJetInput(const xAOD::TruthParticle *tp, std::vector< const xAOD::TruthParticle * > &promptLeptons, std::map< const xAOD::TruthParticle *, unsigned int > &tc_results) const
Redefine our own Classifier function(s)
Definition: CopyTruthJetParticles.cxx:50
MCTruthPartClassifier::isPrompt
int isPrompt(const unsigned int classify, bool allow_prompt_tau_decays=true)
Definition: TruthClassifiers.h:180
CopyTruthJetParticles::initialize
virtual StatusCode initialize() override final
Function initialising the tool.
Definition: CopyTruthJetParticles.cxx:36
MCTruthPartClassifier
Definition: TruthClassifiers.h:12
CopyTruthJetParticles::m_dressingNames
SG::ReadDecorHandleKeyArray< xAOD::TruthParticleContainer > m_dressingNames
Name of the decoration to be used for identifying FSR (dressing) photons.
Definition: CopyTruthJetParticles.h:54
ConstDataVector
DataVector adapter that acts like it holds const pointers.
Definition: ConstDataVector.h:76
xAOD::EgammaHelpers::isPhoton
bool isPhoton(const xAOD::Egamma *eg)
is the object a photon
Definition: EgammaxAODHelpers.cxx:21
CopyTruthJetParticles::m_vetoPDG_IDs
Gaudi::Property< std::vector< int > > m_vetoPDG_IDs
Definition: CopyTruthJetParticles.h:65
MC::isInteracting
bool isInteracting(const T &p)
Identify if the particle with given PDG ID would not interact with the detector, i....
Definition: HepMCHelpers.h:33
CopyTruthJetParticles::getTCresult
unsigned int getTCresult(const xAOD::TruthParticle *tp, std::map< const xAOD::TruthParticle *, unsigned int > &tc_results) const
Definition: CopyTruthJetParticles.cxx:141
MC::isZeroEnergyPhoton
bool isZeroEnergyPhoton(const T &p)
Identify a photon with zero energy. Probably a workaround for a generator bug.
Definition: HepMCHelpers.h:71
CopyTruthJetParticles::m_includeNu
Gaudi::Property< bool > m_includeNu
Definition: CopyTruthJetParticles.h:71
checker_macros.h
Define macros for attributes used to control the static checker.
CopyTruthJetParticles::m_outTruthPartKey
SG::WriteHandleKey< ConstDataVector< xAOD::TruthParticleContainer > > m_outTruthPartKey
Key for output truth particles.
Definition: CopyTruthJetParticles.h:57
HepMCHelpers.h
CopyTruthJetParticles::CopyTruthJetParticles
CopyTruthJetParticles(const std::string &name)
Constructor.
Definition: CopyTruthJetParticles.cxx:33
isMuon
bool isMuon(const T &p)
Definition: AtlasPID.h:205