ATLAS Offline Software
Loading...
Searching...
No Matches
SystObjectLinkerAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <unordered_map>
8#include <iomanip>
9
12
14static const SG::Decorator< iplink_t > dec_nominalObject("nominalObjectLink");
15
16namespace CP
17{
18 StatusCode SystObjectLinkerAlg ::initialize()
19 {
20
21 // Read syst-aware input handles
23
24 // Intialise syst-aware output decorators
26
27 // Intialise syst list (must come after all syst-aware inputs and outputs)
28 ATH_CHECK (m_systematicsList.initialize());
29
30 ATH_MSG_DEBUG("Adding nominal/systematic object links for " << m_inputHandle.getNamePattern());
31
32 return StatusCode::SUCCESS;
33 }
34
35 StatusCode SystObjectLinkerAlg ::execute(const EventContext& ctx) const
36 {
37
38 // Populate a map of systematics hash to container, so we
39 // can iterate safely regardless of the ordering of systs
40 // from the SystematicsSvc
41 // (mainly avoid assumption that nominal comes first)
42 std::unordered_map<std::size_t, const xAOD::IParticleContainer*> systhash_to_container;
43 systhash_to_container.reserve(m_systematicsList.systematicsVector().size());
44 // Record the hash for the nominal for easier access
45 size_t nominal_hash{SIZE_MAX};
46 // Loop is over CP::SystematicsSet, but recommended to use auto
47 // in case this ever changes...
48 for (const auto& sys : m_systematicsList.systematicsVector())
49 {
50 const xAOD::IParticleContainer* sys_container = nullptr;
51 ATH_CHECK( m_inputHandle.retrieve(sys_container, sys, ctx) );
52
53 // Record the hash for the nominal
54 if(sys.name().empty()) {nominal_hash = sys.hash();}
55
56 // We can't find the original container if the systematics
57 // copies are empty. This is a slight vulnerability.
58 if (sys_container->empty()) {
59 ATH_MSG_DEBUG("Container for systematic variation '" << sys.name() << "' was empty.");
60 systhash_to_container.insert({sys.hash(), nullptr});
61 continue;
62 }
63
64 // Navigate to the full container, as this may be a view container
65 // holding a subset of the objects
66 // Cast from SG::AuxVectorData
67 const xAOD::IParticleContainer* full_container =
68 static_cast<const xAOD::IParticleContainer*>(sys_container->front()->container());
69 systhash_to_container.insert({sys.hash(), full_container});
70 if(full_container == sys_container) {
71 ATH_MSG_VERBOSE("The unfiltered container and the input container are the same.");
72 } else {
73 ATH_MSG_DEBUG("Read in container with " << sys_container->size() << " elements.");
74 ATH_MSG_DEBUG("Traced back to unfiltered container with " << full_container->size() << " elements.");
75 }
76 }
77
78 if(nominal_hash==SIZE_MAX) {
79 ATH_MSG_ERROR("The nominal variation was not detected!");
80 return StatusCode::FAILURE;
81 }
82
83 // Iterate over the nominal container, extract the index-parallel syst
84 // Then apply the bidirectional links as decorations
85 const xAOD::IParticleContainer* nom_cont = systhash_to_container[nominal_hash];
86 if(nom_cont==nullptr) {
87 for (const auto& sys : m_systematicsList.systematicsVector()) {
88 if(sys.hash()!=nominal_hash && systhash_to_container[sys.hash()]!=nullptr) {
89 ATH_MSG_WARNING("Nominal container is empty but the container for systematic variation '" << sys.name() << "' is not."
90 << " No nominal/systematic links will be written, so e.g. SystObjectUnioniserAlg will fail on this event.");
91 break;
92 }
93 }
94 ATH_MSG_DEBUG("Unable to retrieve the nominal container, will have to assume there are no relevant objects");
95 return StatusCode::SUCCESS;
96 }
97
98 for (const auto& sys : m_systematicsList.systematicsVector()) {
99 if(sys.hash()==nominal_hash) {continue;}
100 const xAOD::IParticleContainer *var_cont = systhash_to_container[sys.hash()];
101 if(var_cont==nullptr) {
102 ATH_MSG_ERROR("Cannot decorate syst '" << sys.name() << "'");
103 ATH_MSG_ERROR("Likely the systematics input container was empty after filtering.");
104 //must return here, the var_cont pointer is dereferenced below
105 return StatusCode::FAILURE;
106 }
107 ATH_MSG_VERBOSE("Writing decoration " << m_syst_link_decor.getName(sys));
108 for (const xAOD::IParticle* nom_obj : *nom_cont) {
109 const xAOD::IParticle* var_obj = (*var_cont)[nom_obj->index()];
110 dec_nominalObject(*var_obj) = iplink_t(*nom_cont, nom_obj->index(), ctx);
111 m_syst_link_decor.set(*nom_obj, iplink_t(*var_cont, var_obj->index(), ctx), sys);
112 ATH_MSG_VERBOSE("Nominal object with pt " << std::setprecision(3) << nom_obj->pt()/1e3 << " GeV linked to");
113 ATH_MSG_VERBOSE(" '" << sys.name() << "' varied object with pt " << std::setprecision(3) << var_obj->pt()/1e3 << " GeV.");
114 }
115 }
116
117 return StatusCode::SUCCESS;
118 }
119}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_VERBOSE(x,...)
ElementLink< xAOD::IParticleContainer > iplink_t
static const SG::Decorator< iplink_t > dec_nominalObject("nominalObjectLink")
CP::SysReadHandle< xAOD::IParticleContainer > m_inputHandle
Setup syst-aware input container handles.
CP::SysListHandle m_systematicsList
We use default finalize() – this is for cleanup, and we don't do any.
CP::SysWriteDecorHandle< ElementLink< xAOD::IParticleContainer > > m_syst_link_decor
Setup sys-aware output decorations.
const T * front() const
Access the first element in the collection as an rvalue.
size_type size() const noexcept
Returns the number of elements in the collection.
bool empty() const noexcept
Returns true if the collection is empty.
Class providing the definition of the 4-vector interface.
virtual double pt() const =0
The transverse momentum ( ) of the particle.
Select isolated Photons, Electrons and Muons.
ElementLink< xAOD::IParticleContainer > iplink_t
SG::Decorator< T, ALLOC > Decorator
Helper class to provide type-safe access to aux data, specialized for JaggedVecElt.
Definition AuxElement.h:576
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.