ATLAS Offline Software
Loading...
Searching...
No Matches
egammaTruthAssociationAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
14
16
17#include <memory>
18
19namespace {
23xAOD::TruthParticle* getEgammaTruthParticle(
24 const xAOD::TruthParticle* truth,
25 xAOD::TruthParticleContainer& egammaTruthContainer) {
26 if (!truth) {
27 return nullptr;
28 }
29 // Find the original truth particle for electrons from conversions
30 for (unsigned int i = 0;
31 i < 100 && truth && HepMC::is_simulation_particle(truth); ++i) {
32 if (truth->prodVtx() && truth->prodVtx()->nIncomingParticles()) {
33 truth = truth->prodVtx()->incomingParticle(0);
34 } else {
35 break;
36 }
37 }
38
39 // In case truth became null in the above loop
40 if (!truth) {
41 return nullptr;
42 }
43 for (auto egammaTruth : egammaTruthContainer) {
44 if (HepMC::is_same_particle(truth,*egammaTruth)) {
45 return egammaTruth;
46 }
47 }
48 return nullptr;
49}
50} // namespace
51
56
58 ISvcLocator* pSvcLocator)
59 : AthReentrantAlgorithm(name, pSvcLocator)
60{}
61
62StatusCode
64{
65
66 ATH_MSG_DEBUG("Initializing " << name() << "...");
67
68 // initialize the data handles
73
74 // Now the standard decoration handles
75 if (m_matchElectrons) {
77 } else {
78 m_electronDecKeys.clear();
79 }
80
81 if (m_matchPhotons) {
83 } else {
84 m_photonDecKeys.clear();
85 }
86
87 if (m_matchClusters) {
89 } else {
90 m_clusterDecKeys.clear();
91 }
92
95 } else {
97 }
98
99 CHECK(m_mcTruthClassifier.retrieve());
100 ATH_MSG_DEBUG("Retrieved tool " << m_mcTruthClassifier);
101 ATH_MSG_DEBUG("Initialization successful");
102 return StatusCode::SUCCESS;
103}
104
105StatusCode
107{
108 return StatusCode::SUCCESS;
109}
110
111StatusCode
112egammaTruthAssociationAlg::execute(const EventContext& ctx) const
113{
114
116
118
121 ATH_CHECK(egammaTruthContainer.record(
122 std::make_unique<xAOD::TruthParticleContainer>(),
123 std::make_unique<xAOD::TruthParticleAuxContainer>()));
124
125 // Add a copy of electrons and photons to the truth egamma container
128
129 // only for serial running. Can remove check later
130 if (!truthEvtContainer.isValid() || truthEvtContainer->empty()) {
131 ATH_MSG_WARNING("Could not retrieve "
133 << " or container empty, returning");
134 return StatusCode::SUCCESS;
135 }
136
137 for (const auto& truthParticleLink :
138 truthEvtContainer->front()->truthParticleLinks()) {
139 if (!truthParticleLink.isValid())
140 continue;
141 const xAOD::TruthParticle* truthParticle = *truthParticleLink;
142 if (!isPromptEgammaParticle(ctx, truthParticle))
143 continue;
145 *egammaTruthContainer,
146 truthParticle,
147 truthParticleLink.getDataPtr());
148 }
149 }
150 // Decorate containers with truth info, including links to truth particles
151 // Decorate the truth particles with links to the reco ones
152
153 // note that in multithreading this must be valid; can't just fail with
154 // success.
157
158 // accessors
159 static const SG::AuxElement::Accessor<ClusterLink_t> accClusLink(
160 "recoClusterLink");
161 static const SG::AuxElement::Accessor<ElectronLink_t> accElLink(
162 "recoElectronLink");
163 static const SG::AuxElement::Accessor<PhotonLink_t> accPhLink(
164 "recoPhotonLink");
165
166 if (m_matchElectrons) {
167 ATH_MSG_DEBUG("About to match electrons");
168 ATH_CHECK(match(ctx,
169 *truthParticles,
171 accElLink,
172 egammaTruthContainer.ptr()));
173 }
174
175 if (m_matchPhotons) {
176 ATH_MSG_DEBUG("About to match photons");
177 ATH_CHECK(match(ctx,
178 *truthParticles,
180 accPhLink,
181 egammaTruthContainer.ptr()));
182 }
183
184 if (m_matchClusters) {
185 ATH_MSG_DEBUG("About to match clusters");
186 ATH_CHECK(match(ctx,
187 *truthParticles,
189 accClusLink,
190 egammaTruthContainer.ptr()));
191 }
192
194 ATH_MSG_DEBUG("About to match fwd electrons");
195 ATH_CHECK(match(ctx,
196 *truthParticles,
198 accElLink,
199 egammaTruthContainer.ptr()));
200 }
201
202 return StatusCode::SUCCESS;
203}
204
205bool
207 const EventContext& ctx,
208 const xAOD::TruthParticle* truth) const
209{
210
211 if ((truth->pdgId() != 22 && abs(truth->pdgId()) != 11) ||
212 MC::isDecayed(truth) || !MC::isPhysical(truth) ||
213 HepMC::is_simulation_particle(truth) || truth->pt() < m_minPt) {
214 return false;
215 }
216 MCTruthPartClassifier::Info mcinfo(ctx);
217 auto type = m_mcTruthClassifier->particleTruthClassifier(truth, &mcinfo);
218
219 // Isolated electron or photons are kept
222 return true;
223 }
224
225 //In UPC mode (e.g \gamma \gamma -> e e )
226 // keep (non-Geant see above) electrons from photons (Bkg)
227 if (m_UPCmode &&
229 return true;
230 }
231
232 // FSR photon
235 truth->pt() > m_minPtFSR) {
236 return true;
237 }
238
239 return false;
240}
241
242void
244 const EventContext& ctx,
245 xAOD::TruthParticleContainer& egammaTruthContainer,
246 const xAOD::TruthParticle* truth,
247 const xAOD::TruthParticleContainer* oldContainer) const
248{
249 auto *truthParticle = egammaTruthContainer.push_back(std::make_unique<xAOD::TruthParticle>());
250 truthParticle->setPdgId(truth->pdgId());
251 truthParticle->setUid(HepMC::uniqueID(truth));
252 truthParticle->setStatus(truth->status());
253 truthParticle->setPx(truth->px());
254 truthParticle->setPy(truth->py());
255 truthParticle->setPz(truth->pz());
256 truthParticle->setE(truth->e());
257 truthParticle->setM(truth->m());
258 truthParticle->setProdVtxLink(truth->prodVtxLink());
259 truthParticle->setDecayVtxLink(truth->decayVtxLink());
260
261 static const SG::AuxElement::Accessor<ClusterLink_t> accClusLink(
262 "recoClusterLink");
263 static const SG::AuxElement::Accessor<ElectronLink_t> accElLink(
264 "recoElectronLink");
265 static const SG::AuxElement::Accessor<PhotonLink_t> accPhLink(
266 "recoPhotonLink");
267 static const SG::AuxElement::Accessor<TruthLink_t> accTruthLink(
268 "truthParticleLink");
269 static const SG::AuxElement::Accessor<int> accType("truthType");
270 static const SG::AuxElement::Accessor<int> accOrigin("truthOrigin");
271 static const SG::AuxElement::Accessor<unsigned int> accClassification("truthClassification");
272
273 if (m_matchClusters) {
274 accClusLink(*truthParticle) = ClusterLink_t();
275 }
276 accElLink(*truthParticle) = ElectronLink_t();
277 accPhLink(*truthParticle) = PhotonLink_t();
278 accTruthLink(*truthParticle) = TruthLink_t(truth, *oldContainer, ctx);
279 accTruthLink(*truthParticle).toPersistent();
280 // MCTruthClassifier info
281 MCTruthPartClassifier::Info mcinfo(ctx);
282 auto info = m_mcTruthClassifier->particleTruthClassifier(truth, &mcinfo);
283 accType(*truthParticle) = static_cast<int>(info.first);
284 accOrigin(*truthParticle) = static_cast<int>(info.second);
285 accClassification(*truthParticle) = std::get<0>(MCTruthPartClassifier::defOrigOfParticle(truth)); // See AGENE-2351
286}
287
289template<class T>
290StatusCode
293 const std::string& name)
294{
295 if (!keys.empty()) {
296 ATH_MSG_FATAL("The WriteDecorHandle should not be configured directly.");
297 return StatusCode::FAILURE;
298 }
299
300 keys.emplace_back(name + ".truthParticleLink");
301 keys.emplace_back(name + ".truthType");
302 keys.emplace_back(name + ".truthOrigin");
303 keys.emplace_back(name + ".truthClassification");
304 ATH_CHECK(keys.initialize());
305 return StatusCode::SUCCESS;
306}
307
308// constructor
309template<class T>
312 const EventContext& ctx)
313 : el(hkeys.at(0), ctx)
314 , type(hkeys.at(1), ctx)
315 , origin(hkeys.at(2), ctx)
316 , classification(hkeys.at(3), ctx)
317{}
318
319template<class T>
322 const EventContext& ctx,
323 const T* particle) const
324{
325 MCTruthInfo_t info{};
326 MCTruthPartClassifier::Info mcinfo(ctx);
327 auto ret = m_mcTruthClassifier->particleTruthClassifier(particle, &mcinfo);
328 info.genPart = mcinfo.genPart;
329 info.first = ret.first;
330 info.second = ret.second;
331 return info;
332}
333
336template<>
339 const EventContext& ctx,
340 const xAOD::Electron* electron) const
341{
342 MCTruthInfo_t info{};
343 MCTruthPartClassifier::Info mcinfo(ctx);
344 auto ret = m_mcTruthClassifier->particleTruthClassifier(electron, &mcinfo);
345 if (ret.first == MCTruthPartClassifier::Unknown &&
347 electron->caloCluster()) {
348 ATH_MSG_DEBUG("Trying cluster-based truth classification for electron");
349 ret = m_mcTruthClassifier->particleTruthClassifier(electron->caloCluster(),&mcinfo);
350 }
351 info.genPart = mcinfo.genPart;
352 info.first = ret.first;
353 info.second = ret.second;
354 return info;
355}
356
357template<class T, class L>
360 const EventContext& ctx,
361 const xAOD::TruthParticleContainer& truthParticles,
363 const SG::AuxElement::Accessor<L>& linkAccess,
364 xAOD::TruthParticleContainer* egammaTruthContainer) const
365{
366
367 writeDecorHandles<T> decoHandles(hkeys, ctx);
368
369
370 for (auto particle : *decoHandles.readHandle()) {
371
372 MCTruthInfo_t info =
373 particleTruthClassifier(ctx, particle);
374
375 const xAOD::TruthParticle* truthParticle = info.genPart;
376 if (truthParticle) {
378 truthParticle, truthParticles, ctx);
380 "Decorating object with link to truth, index = " << link.index());
381 decoHandles.el(*particle) = link;
382 } else {
383 decoHandles.el(*particle) = ElementLink<xAOD::TruthParticleContainer>();
384 }
385 decoHandles.el(*particle).toPersistent();
386 ATH_MSG_DEBUG("truthType = " << info.first
387 << " truthOrigin = " << info.second);
388 decoHandles.type(*particle) = static_cast<int>(info.first);
389 decoHandles.origin(*particle) = static_cast<int>(info.second);
390 decoHandles.classification(*particle) = (truthParticle) ? std::get<0>(MCTruthPartClassifier::defOrigOfParticle(truthParticle)) : 0; // See AGENE-2351
391
392 // Decorate the corresponding truth particle with the link to the reco
394 if (!egammaTruthContainer) {
395 ATH_MSG_ERROR("The egammaTruthContainer needs to be valid");
396 return StatusCode::FAILURE;
397 }
398 const xAOD::TruthParticle* truth =
400 if (truth) {
401 xAOD::TruthParticle* truthEgamma =
402 getEgammaTruthParticle(truth, *egammaTruthContainer);
403 if (truthEgamma) {
404 // we found a truthEgamma object we should annotate if this is the
405 // best link
406 bool annotateLink = true; // by default we annotate
407 const auto& link = linkAccess(*truthEgamma); // what already exists
408 if (link.isValid()) {
409 auto oldPart = *link;
410 if (oldPart && truthEgamma->e() > 0 &&
411 std::abs(oldPart->e() / truthEgamma->e() - 1) <
412 std::abs(particle->e() / truthEgamma->e() - 1)) {
413 ATH_MSG_DEBUG(truthEgamma
414 << ": "
415 << " already set to a better matched particle: "
416 << particle);
417 annotateLink = false;
418 }
419 }
420
421 if (annotateLink) {
422 L link(particle, *decoHandles.readHandle(), ctx);
423 linkAccess(*truthEgamma) = link;
424 linkAccess(*truthEgamma).toPersistent();
425 }
426 }
427 }
428 }
429 }
430 return StatusCode::SUCCESS;
431}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define CHECK(...)
Evaluate an expression and check for errors.
ATLAS-specific HepMC functions.
ElementLink< xAOD::PhotonContainer > PhotonLink_t
ElementLink< xAOD::ElectronContainer > ElectronLink_t
Handle class for reading from StoreGate.
Handle class for adding a decoration to an object.
Handle class for recording to StoreGate.
ElementLink< xAOD::TruthParticleContainer > TruthLink_t
An algorithm that can be simultaneously executed in multiple threads.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
const xAOD::TruthParticle * genPart
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:573
virtual bool isValid() override final
Can the handle be successfully dereferenced?
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
Gaudi::Property< bool > m_doEgammaTruthContainer
Create egamma truth container?
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_truthParticleContainerKey
Name of the truth particle container.
Gaudi::Property< std::string > m_electronDecName
The electron container name property used to initialize the WriteDecorHandleKeyArray.
Gaudi::Property< bool > m_matchElectrons
Match electrons?
SG::WriteDecorHandleKeyArray< xAOD::ElectronContainer > m_fwdElectronDecKeys
The fwd electron container decor handle key array.
SG::WriteDecorHandleKeyArray< xAOD::PhotonContainer > m_photonDecKeys
The photon container decor handle key array.
StatusCode initializeDecorKeys(SG::WriteDecorHandleKeyArray< T > &keys, const std::string &name)
A function that initializes the decor handles, but also checks the naming convention.
Gaudi::Property< bool > m_matchClusters
Match clusters?
StatusCode match(const EventContext &ctx, const xAOD::TruthParticleContainer &truthParticles, const SG::WriteDecorHandleKeyArray< T > &hkeys, const SG::AuxElement::Accessor< L > &linkAccess, xAOD::TruthParticleContainer *egammaTruthContainer) const
Loop over elements in the reco container, decorate them with truth info and decorate the truth partic...
Gaudi::Property< bool > m_matchPhotons
Match photons?
SG::WriteHandleKey< xAOD::TruthParticleContainer > m_egammaTruthParticleContainerKey
Name of the output egamma truth container.
virtual StatusCode execute(const EventContext &ctx) const override final
execute on container
SG::WriteDecorHandleKeyArray< xAOD::ElectronContainer > m_electronDecKeys
The electron container decor handle key array.
Gaudi::Property< std::string > m_photonDecName
The photon container name property used to initialize the WriteDecorHandleKeyArray.
void getNewTruthParticle(const EventContext &ctx, xAOD::TruthParticleContainer &egammaTruthContainer, const xAOD::TruthParticle *truth, const xAOD::TruthParticleContainer *oldContainer) const
Create a copy a truth particle, add it to the new getNewTruthParticle container and decorate it with ...
Gaudi::Property< float > m_minPt
Minimum Pt to enter egamma truth particle container.
Gaudi::Property< std::string > m_fwdElectronDecName
The fwd electron name property used to initialize the WriteDecorHandleKeyArray.
bool isPromptEgammaParticle(const EventContext &ctx, const xAOD::TruthParticle *truth) const
Return true if the truth particle is a prompt electron or photon.
Gaudi::Property< bool > m_matchForwardElectrons
Match fwd electrons?
Gaudi::Property< float > m_minPtFSR
Minimum Pt for FSR to enter egamma truth particle container.
Gaudi::Property< std::string > m_clusterDecName
The egamma cluster name property used to initialize the WriteDecorHandleKeyArray.
MCTruthInfo_t particleTruthClassifier(const EventContext &ctx, const T *) const
return the result of MCTruthClassifier::particleTruthClassifier or do a second pass for electrons bas...
SG::WriteDecorHandleKeyArray< xAOD::CaloClusterContainer > m_clusterDecKeys
The egamma cluster decor handle key array.
egammaTruthAssociationAlg(const std::string &name, ISvcLocator *pSvcLocator)
constructor
Gaudi::Property< bool > m_UPCmode
Allow electron from photon in egamma truth particle container.
ToolHandle< IMCTruthClassifier > m_mcTruthClassifier
MCTruthClassifier.
virtual StatusCode finalize() override final
finalize method
virtual StatusCode initialize() override final
initialize method
SG::ReadHandleKey< xAOD::TruthEventContainer > m_truthEventContainerKey
Name of the truth event container.
int status() const
Status code.
virtual double m() const override final
The mass of the particle.
int pdgId() const
PDG ID code.
const ElementLink< TruthVertexContainer > & decayVtxLink() const
The decay vertex link of this particle.
float px() const
The x component of the particle's momentum.
virtual double e() const override final
The total energy of the particle.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
const TruthVertex_v1 * prodVtx() const
The production vertex of this particle.
float py() const
The y component of the particle's momentum.
float pz() const
The z component of the particle's momentum.
const ElementLink< TruthVertexContainer > & prodVtxLink() const
The production vertex link of this particle.
const TruthParticle_v1 * incomingParticle(size_t index) const
Get one of the incoming particles.
size_t nIncomingParticles() const
Get the number of incoming particles.
ElementLink< xAOD::CaloClusterContainer > ClusterLink_t
::StatusCode StatusCode
StatusCode definition for legacy code.
int uniqueID(const T &p)
bool is_same_particle(const T1 &p1, const T2 &p2)
Method to establish if two particles in the GenEvent actually represent the same 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...
std::tuple< unsigned int, T > defOrigOfParticle(T thePart)
bool isDecayed(const T &p)
Identify if the particle decayed.
bool isPhysical(const T &p)
Identify if the particle is physical, i.e. is stable or decayed.
DecorHandleKeyArray< WriteDecorHandle< T, S >, WriteDecorHandleKey< T >, Gaudi::DataHandle::Writer > WriteDecorHandleKeyArray
bool isFwdElectron(const xAOD::Egamma *eg)
is the object a Fwd electron
const xAOD::TruthParticle * getTruthParticle(const xAOD::IParticle &p)
Return the truthParticle associated to the given IParticle (if any)
TruthParticle_v1 TruthParticle
Typedef to implementation.
TruthParticleContainer_v1 TruthParticleContainer
Declare the latest version of the truth particle container.
Electron_v1 Electron
Definition of the current "egamma version".
helper class to contain write decoration handles
writeDecorHandles(const SG::WriteDecorHandleKeyArray< T > &keys, const EventContext &ctx)
SG::WriteDecorHandle< T, unsigned int > classification
SG::WriteDecorHandle< T, ElementLink< xAOD::TruthParticleContainer > > el