ATLAS Offline Software
SystObjectLinkerAlg.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
7 #include <unordered_map>
8 #include <iomanip>
9 
13 
15 static const SG::AuxElement::Decorator< iplink_t > dec_nominalObject("nominalObjectLink");
16 
17 namespace CP
18 {
20  ISvcLocator *pSvcLocator)
21  : EL::AnaReentrantAlgorithm(name, pSvcLocator)
22  {
23 
24  }
25 
27  {
28 
29  // Read syst-aware input handles
31 
32  // Intialise syst-aware output decorators
34 
35  // Intialise syst list (must come after all syst-aware inputs and outputs)
37 
38  ATH_MSG_DEBUG("Adding nominal/systematic object links for " << m_inputHandle.getNamePattern());
39 
40  return StatusCode::SUCCESS;
41  }
42 
43  StatusCode SystObjectLinkerAlg ::execute(const EventContext&) const
44  {
45 
46  // Populate a map of systematics hash to container, so we
47  // can iterate safely regardless of the ordering of systs
48  // from the SystematicsSvc
49  // (mainly avoid assumption that nominal comes first)
50  std::unordered_map<std::size_t, const xAOD::IParticleContainer*> systhash_to_container;
51  systhash_to_container.reserve(m_systematicsList.systematicsVector().size());
52  // Record the hash for the nominal for easier access
53  size_t nominal_hash{SIZE_MAX};
54  // Loop is over CP::SystematicsSet, but recommended to use auto
55  // in case this ever changes...
56  for (const auto& sys : m_systematicsList.systematicsVector())
57  {
58  const xAOD::IParticleContainer* sys_container = nullptr;
59  ATH_CHECK( m_inputHandle.retrieve(sys_container, sys) );
60 
61  // Record the hash for the nominal
62  if(sys.name().empty()) {nominal_hash = sys.hash();}
63 
64  // We can't find the original container if the systematics
65  // copies are empty. This is a slight vulnerability.
66  if (sys_container->empty()) {
67  ATH_MSG_DEBUG("Container for systematic variation '" << sys.name() << "' was empty.");
68  systhash_to_container.insert({sys.hash(), nullptr});
69  continue;
70  }
71 
72  // Navigate to the full container, as this may be a view container
73  // holding a subset of the objects
74  // Cast from SG::AuxVectorData
75  const xAOD::IParticleContainer* full_container =
76  static_cast<const xAOD::IParticleContainer*>(sys_container->front()->container());
77  systhash_to_container.insert({sys.hash(), full_container});
78  if(full_container == sys_container) {
79  ATH_MSG_VERBOSE("The unfiltered container and the input container are the same.");
80  } else {
81  ATH_MSG_DEBUG("Read in container with " << sys_container->size() << " elements.");
82  ATH_MSG_DEBUG("Traced back to unfiltered container with " << full_container->size() << " elements.");
83  }
84  }
85 
86  if(nominal_hash==SIZE_MAX) {
87  ATH_MSG_ERROR("The nominal variation was not detected!");
88  return StatusCode::FAILURE;
89  }
90 
91  // Iterate over the nominal container, extract the index-parallel syst
92  // Then apply the bidirectional links as decorations
93  const xAOD::IParticleContainer* nom_cont = systhash_to_container[nominal_hash];
94  if(nom_cont==nullptr) {
95  ATH_MSG_DEBUG("Unable to retrieve the nominal container, will have to assume there are no relevant objects");
96  return StatusCode::SUCCESS;
97  }
98 
99  for (const xAOD::IParticle* nom_obj : *nom_cont) {
100  for (const auto& sys : m_systematicsList.systematicsVector()) {
101  if(sys.hash()==nominal_hash) {continue;}
102  const xAOD::IParticleContainer *var_cont = systhash_to_container[sys.hash()];
103  if(var_cont==nullptr) {
104  ATH_MSG_ERROR("Cannot decorate syst '" << sys.name() << "' for obj " << nom_obj->index());
105  ATH_MSG_ERROR("Likely the systematics input container was empty after filtering.");
106  //must return here, the var_cont pointer is dereferenced in the next line
107  return StatusCode::FAILURE;
108  }
109  const xAOD::IParticle* var_obj = (*var_cont)[nom_obj->index()];
110  dec_nominalObject(*var_obj) = iplink_t(*nom_cont, nom_obj->index());
111  ATH_MSG_VERBOSE("Writing decoration " << m_syst_link_decor.getName(sys) << " from object " << nom_obj->index());
112  m_syst_link_decor.set(*nom_obj, iplink_t(*var_cont, var_obj->index()), sys);
113  ATH_MSG_VERBOSE("Nominal object with pt " << std::setprecision(3) << nom_obj->pt()/1e3 << " GeV linked to");
114  ATH_MSG_VERBOSE(" '" << sys.name() << "' varied object with pt " << std::setprecision(3) << var_obj->pt()/1e3 << " GeV.");
115  }
116  }
117 
118  return StatusCode::SUCCESS;
119  }
120 }
CP::SystObjectLinkerAlg::initialize
StatusCode initialize() override
Initialisation method, for setting up tools and other persistent configs.
Definition: SystObjectLinkerAlg.cxx:26
ConstDataVector.h
DataVector adapter that acts like it holds const pointers.
SystematicSet.h
CP::SysListHandle::systematicsVector
const std::vector< CP::SystematicSet > & systematicsVector() const
the list of systematics to loop over
Definition: SysListHandle.cxx:96
ATH_MSG_VERBOSE
#define ATH_MSG_VERBOSE(x)
Definition: AthMsgStreamMacros.h:28
CP::SystObjectLinkerAlg::execute
StatusCode execute(const EventContext &ctx) const override
Execute method, for actions to be taken in the event loop.
Definition: SystObjectLinkerAlg.cxx:43
xAOD::IParticle
Class providing the definition of the 4-vector interface.
Definition: Event/xAOD/xAODBase/xAODBase/IParticle.h:40
CP
Select isolated Photons, Electrons and Muons.
Definition: Control/xAODRootAccess/xAODRootAccess/TEvent.h:48
mapkey::sys
@ sys
Definition: TElectronEfficiencyCorrectionTool.cxx:42
SystObjectLinkerAlg.h
CP::SystObjectLinkerAlg::SystObjectLinkerAlg
SystObjectLinkerAlg(const std::string &name, ISvcLocator *pSvcLocator)
The standard constructor.
Definition: SystObjectLinkerAlg.cxx:19
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
CheckAppliedSFs.e3
e3
Definition: CheckAppliedSFs.py:264
CP::SysListHandle::initialize
::StatusCode initialize()
intialize this property
Definition: SysListHandle.cxx:69
SG::Decorator
Helper class to provide type-safe access to aux data.
Definition: Decorator.h:58
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
DataVector::front
const T * front() const
Access the first element in the collection as an rvalue.
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
EL
This module defines the arguments passed from the BATCH driver to the BATCH worker.
Definition: AlgorithmWorkerData.h:24
SG::AuxElement::index
size_t index() const
Return the index of this element within its container.
DataVector
Derived DataVector<T>.
Definition: DataVector.h:581
CP::SystObjectLinkerAlg::m_systematicsList
CP::SysListHandle m_systematicsList
We use default finalize() – this is for cleanup, and we don't do any.
Definition: SystObjectLinkerAlg.h:53
xAOD::IParticle::pt
virtual double pt() const =0
The transverse momentum ( ) of the particle.
CP::SystObjectLinkerAlg::m_inputHandle
CP::SysReadHandle< xAOD::IParticleContainer > m_inputHandle
Setup syst-aware input container handles.
Definition: SystObjectLinkerAlg.h:57
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:195
CP::SystObjectLinkerAlg::m_syst_link_decor
CP::SysWriteDecorHandle< ElementLink< xAOD::IParticleContainer > > m_syst_link_decor
Setup sys-aware output decorations.
Definition: SystObjectLinkerAlg.h:61
iplink_t
ElementLink< xAOD::IParticleContainer > iplink_t
Definition: SystObjectLinkerAlg.cxx:14
CP::iplink_t
ElementLink< xAOD::IParticleContainer > iplink_t
Definition: SystObjectUnioniserAlg.h:58
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
DataVector::empty
bool empty() const noexcept
Returns true if the collection is empty.