ATLAS Offline Software
Loading...
Searching...
No Matches
SystObjectLinkerAlg.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 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 SystObjectLinkerAlg ::SystObjectLinkerAlg(const std::string &name,
19 ISvcLocator *pSvcLocator)
20 : EL::AnaReentrantAlgorithm(name, pSvcLocator)
21 {
22
23 }
24
25 StatusCode SystObjectLinkerAlg ::initialize()
26 {
27
28 // Read syst-aware input handles
30
31 // Intialise syst-aware output decorators
33
34 // Intialise syst list (must come after all syst-aware inputs and outputs)
35 ATH_CHECK (m_systematicsList.initialize());
36
37 ATH_MSG_DEBUG("Adding nominal/systematic object links for " << m_inputHandle.getNamePattern());
38
39 return StatusCode::SUCCESS;
40 }
41
42 StatusCode SystObjectLinkerAlg ::execute(const EventContext&) const
43 {
44
45 // Populate a map of systematics hash to container, so we
46 // can iterate safely regardless of the ordering of systs
47 // from the SystematicsSvc
48 // (mainly avoid assumption that nominal comes first)
49 std::unordered_map<std::size_t, const xAOD::IParticleContainer*> systhash_to_container;
50 systhash_to_container.reserve(m_systematicsList.systematicsVector().size());
51 // Record the hash for the nominal for easier access
52 size_t nominal_hash{SIZE_MAX};
53 // Loop is over CP::SystematicsSet, but recommended to use auto
54 // in case this ever changes...
55 for (const auto& sys : m_systematicsList.systematicsVector())
56 {
57 const xAOD::IParticleContainer* sys_container = nullptr;
58 ATH_CHECK( m_inputHandle.retrieve(sys_container, sys) );
59
60 // Record the hash for the nominal
61 if(sys.name().empty()) {nominal_hash = sys.hash();}
62
63 // We can't find the original container if the systematics
64 // copies are empty. This is a slight vulnerability.
65 if (sys_container->empty()) {
66 ATH_MSG_DEBUG("Container for systematic variation '" << sys.name() << "' was empty.");
67 systhash_to_container.insert({sys.hash(), nullptr});
68 continue;
69 }
70
71 // Navigate to the full container, as this may be a view container
72 // holding a subset of the objects
73 // Cast from SG::AuxVectorData
74 const xAOD::IParticleContainer* full_container =
75 static_cast<const xAOD::IParticleContainer*>(sys_container->front()->container());
76 systhash_to_container.insert({sys.hash(), full_container});
77 if(full_container == sys_container) {
78 ATH_MSG_VERBOSE("The unfiltered container and the input container are the same.");
79 } else {
80 ATH_MSG_DEBUG("Read in container with " << sys_container->size() << " elements.");
81 ATH_MSG_DEBUG("Traced back to unfiltered container with " << full_container->size() << " elements.");
82 }
83 }
84
85 if(nominal_hash==SIZE_MAX) {
86 ATH_MSG_ERROR("The nominal variation was not detected!");
87 return StatusCode::FAILURE;
88 }
89
90 // Iterate over the nominal container, extract the index-parallel syst
91 // Then apply the bidirectional links as decorations
92 const xAOD::IParticleContainer* nom_cont = systhash_to_container[nominal_hash];
93 if(nom_cont==nullptr) {
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 xAOD::IParticle* nom_obj : *nom_cont) {
99 for (const auto& sys : m_systematicsList.systematicsVector()) {
100 if(sys.hash()==nominal_hash) {continue;}
101 const xAOD::IParticleContainer *var_cont = systhash_to_container[sys.hash()];
102 if(var_cont==nullptr) {
103 ATH_MSG_ERROR("Cannot decorate syst '" << sys.name() << "' for obj " << nom_obj->index());
104 ATH_MSG_ERROR("Likely the systematics input container was empty after filtering.");
105 //must return here, the var_cont pointer is dereferenced in the next line
106 return StatusCode::FAILURE;
107 }
108 const xAOD::IParticle* var_obj = (*var_cont)[nom_obj->index()];
109 dec_nominalObject(*var_obj) = iplink_t(*nom_cont, nom_obj->index());
110 ATH_MSG_VERBOSE("Writing decoration " << m_syst_link_decor.getName(sys) << " from object " << nom_obj->index());
111 m_syst_link_decor.set(*nom_obj, iplink_t(*var_cont, var_obj->index()), 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_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(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.
AnaReentrantAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
constructor with parameters
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
This module defines the arguments passed from the BATCH driver to the BATCH worker.
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.