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