ATLAS Offline Software
Loading...
Searching...
No Matches
dumpAllSystematics.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include <format>
6
7#include <set>
8// EDM include(s):
9
12#include "xAODEgamma/Egamma.h"
16
17#include <xAODTruth/TruthParticle.h> // TODO: this introduces an additional dependecy which is not needed by the tool...
22
27
28#include "GaudiKernel/ITHistSvc.h"
29
30
31// local include
32#include "dumpAllSystematics.h"
33
34DumpAllSystematics::DumpAllSystematics(const std::string& name, ISvcLocator* svcLoc)
35 : AthAlgorithm(name, svcLoc)
36{
37 declareProperty("EgammaCalibrationAndSmearingTools", m_EgammaCalibrationAndSmearingTools);
38 declareProperty("particle", m_particle_name="", "electron/photon");
39 declareProperty("recoContainer", m_reco_container_name="", "reco container name");
40 declareProperty("keepOnlyOne", m_keep_one=false, "keep only the most energetic particle");
41}
42
43
45{
46 // Greet the user:
47 ATH_MSG_INFO ("Initializing " << name() << "...");
48
49 if (m_particle_name.empty()) {
50 ATH_MSG_WARNING("particle property is empty, choose between \"photon\" or \"electron\". Assuming electron.");
51 m_particle_name = "electron";
52 }
53 if (m_particle_name != "electron" and m_particle_name != "photon")
54 {
55 ATH_MSG_FATAL("cannot understand particle property: must be \"electron\" or \"photon\"");
56 }
57
59
60 // Retrieve the tools:
61 ATH_MSG_INFO("retrieving tools");
62 if (!m_EgammaCalibrationAndSmearingTools.retrieve().isSuccess())
63 { ATH_MSG_ERROR("Cannot retrieve calibration tools"); }
64 ATH_MSG_INFO("retrieving tools, done");
65
67 ATH_MSG_FATAL("no tool specified in the job options");
68 return StatusCode::FAILURE;
69 }
70 ATH_MSG_INFO("number of tools: " << m_EgammaCalibrationAndSmearingTools.size());
71 if (m_reco_container_name.empty()) {
73 else m_reco_container_name = "Photons";
74 }
75
76 ATH_MSG_INFO("================================================================================");
77 ATH_MSG_INFO("particle: " << m_particle_name);
78 ATH_MSG_INFO("keep only one: " << m_keep_one);
79 ATH_MSG_INFO("reco container: " << m_reco_container_name);
80 ATH_MSG_INFO("================================================================================");
81
82
83
84 ATH_MSG_DEBUG("creating tree");
85
86 const std::string prefix = m_particle_type == ParticleType::ELECTRON ? "el_" : "ph_";
87 m_tree = new TTree("all_sys", "all_sys");
88 m_tree->Branch("index", &m_instance_index, "index/I")->SetTitle("index of the particle as in the original dataset");
89 m_tree->Branch("actualIntPerXing", &m_actualIntPerXing, "actualIntPerXing/F");
90 m_tree->Branch("eventNumber", &m_EventNumber, "eventNumber/I");
91 m_tree->Branch("runNumber", &m_RunNumber, "runNumber/I");
92 m_tree->Branch((prefix + "truth_E").c_str(), &m_truth_E, (prefix + "truth_E/F").c_str());
93 m_tree->Branch((prefix + "truth_eta").c_str(), &m_truth_eta, (prefix + "truth_eta/F").c_str());
94 m_tree->Branch((prefix + "truth_pt").c_str(), &m_truth_pt, (prefix + "truth_pt/F").c_str());
95 m_tree->Branch((prefix + "truth_phi").c_str(), &m_truth_phi, (prefix + "truth_phi/F").c_str());
96 m_tree->Branch((prefix + "truth_pdgId").c_str(), &m_truth_pdgId, (prefix + "truth_pdgId/I").c_str());
97 m_tree->Branch((prefix + "truth_parent_pdgId").c_str(), &m_truth_parent_pdgId, (prefix + "truth_parent_pdgId/I").c_str());
98 m_tree->Branch((prefix + "truth_matched").c_str(), &m_truth_matched, (prefix + "truth_matched/O").c_str());
99 m_tree->Branch((prefix + "cl_eta").c_str(), &m_cl_eta, (prefix + "cl_eta/F").c_str());
100 m_tree->Branch((prefix + "cl_etaCalo").c_str(), &m_cl_etaCalo, (prefix + "cl_etaCalo/F").c_str());
101 m_tree->Branch((prefix + "cl_phi").c_str(), &m_cl_phi, (prefix + "cl_phi/F").c_str());
102 m_tree->Branch((prefix + "cl_rawcl_Es0").c_str(), &m_cl_rawcl_Es0, (prefix + "cl_rawcl_Es0/F").c_str());
103 m_tree->Branch((prefix + "cl_rawcl_Es1").c_str(), &m_cl_rawcl_Es1, (prefix + "cl_rawcl_Es1/F").c_str());
104 m_tree->Branch((prefix + "cl_rawcl_Es2").c_str(), &m_cl_rawcl_Es2, (prefix + "cl_rawcl_Es2/F").c_str());
105 m_tree->Branch((prefix + "cl_rawcl_Es3").c_str(), &m_cl_rawcl_Es3, (prefix + "cl_rawcl_Es3/F").c_str());
106 m_tree->Branch((prefix + "cl_E").c_str(), &m_cl_E, (prefix + "cl_E/F").c_str())->SetTitle("original xAOD caloCluster energy");
107 m_tree->Branch((prefix + "wstot").c_str(), &m_wstot, (prefix + "wstot/F").c_str());
109 m_tree->Branch("ph_truth_isConv", &m_truth_isConv, "ph_truth_isConv/O");
110 m_tree->Branch("ph_truth_Rconv", &m_truth_Rconv, "ph_truth_Rconv/F");
111 m_tree->Branch("ph_Rconv", &m_ph_Rconv, "ph_Rconv/F");
112 m_tree->Branch("ph_convFlag", &m_ph_convFlag, "ph_convFlag/I");
113 }
114 m_tree->Branch("npv", &m_npv, "npv/I");
115
120
121 std::vector<std::vector<std::string> > all_sys_names_per_tool;
122 std::set<std::string> all_sys_names;
123
124 for (unsigned int itool = 0; itool != m_EgammaCalibrationAndSmearingTools.size(); ++itool) {
125 const std::string tool_name = m_EgammaCalibrationAndSmearingTools[itool].name();
126 {
127 const std::string branch_name = prefix + tool_name + "_nominal_E";
128 m_tree->Branch(branch_name.c_str(), &m_nominal_E[itool], (branch_name + "/F").c_str());
129 }
130
131 const CP::SystematicSet& sys_set = m_EgammaCalibrationAndSmearingTools[itool]->recommendedSystematics();
132 ATH_MSG_INFO("size of the systematics set for tool [" << itool << "] " + m_EgammaCalibrationAndSmearingTools[itool].name() << ": " << sys_set.size());
133 std::vector<std::string> sys_names; sys_names.reserve(sys_set.size());
134 for (const auto& sys : sys_set) { if (sys.parameter() == 1) { sys_names.push_back(sys.name()); all_sys_names.insert(sys.name()); } }
135 std::sort(sys_names.begin(), sys_names.end());
136 all_sys_names_per_tool.push_back(sys_names);
137
138
139 m_energy_variations[itool].resize(sys_set.size());
140
141 int isys = 0;
142 for (const auto& sys : sys_set) {
143 const std::string branch_name = prefix + tool_name + "_ratio_" + sys.name();
144 m_tree->Branch(branch_name.c_str(), &m_energy_variations[itool][isys],
145 (branch_name + "/F").c_str());
146 ++isys;
147 }
148
149 m_tree->Branch((prefix + tool_name + "_ratio_SCALE_sum__1up").c_str(), &m_energy_variations_sum_up[itool], (prefix + tool_name + "_ratio_SCALE_sum__1up/F").c_str());
150 m_tree->Branch((prefix + tool_name + "_ratio_SCALE_sum__1down").c_str(), &m_energy_variations_sum_down[itool], (prefix + tool_name + "_ratio_SCALE_sum__1down/F").c_str());
151 }
152
153 {
154 std::string header = std::string(45, ' ');
155 for (unsigned int i = 0; i != m_EgammaCalibrationAndSmearingTools.size(); ++i) {
156 header += std::format(" [{}] ", i);
157 }
159 }
160 for (auto sysname : all_sys_names) {
161 std::string line = std::format("{:>45}", sysname);
162 for (const auto& sys_per_tool : all_sys_names_per_tool) {
163 if (std::find(sys_per_tool.begin(), sys_per_tool.end(), sysname) != sys_per_tool.end()) line += " X ";
164 else line += " ";
165 }
166 ATH_MSG_INFO(line);
167 }
168
169 if (m_particle_type == ParticleType::ELECTRON) ATH_MSG_INFO("dumping electrons");
170 else if (m_particle_type == ParticleType::PHOTON) ATH_MSG_INFO("dumping photons");
171
172 // output configuration
173 ServiceHandle<ITHistSvc> histSvc("THistSvc", name());
174 CHECK(histSvc.retrieve());
175 const std::string tree_stream = "/DATASTREAM";
176 CHECK(histSvc->regTree(tree_stream + "/myTree", m_tree));
177
178 return StatusCode::SUCCESS;
179}
180
181
183 ATH_MSG_INFO("Particle saved: " << m_tree->GetEntries());
184 if (m_tree->GetEntries() == 0) ATH_MSG_WARNING("no particle saved");
185 ATH_MSG_INFO("Finalizing " << name() << "...");
186
187 return StatusCode::SUCCESS;
188}
189
191{
192 const xAOD::EventInfo* eventInfo = nullptr;
193 ATH_CHECK(evtStore()->retrieve(eventInfo));
194
197 m_EventNumber = eventInfo->eventNumber();
198 m_RunNumber = eventInfo->runNumber();
199
200 // vertex information
201 const xAOD::VertexContainer* vtx_container = nullptr;
202 if (!evtStore()->retrieve(vtx_container, "PrimaryVertices")) { m_npv = -999; }
203 else {
204 m_npv = 0;
205 for (const auto* vtx : *vtx_container) { if (vtx->vertexType() == xAOD::VxType::PriVtx or vtx->vertexType() == xAOD::VxType::PileUp) ++m_npv; }
206 }
207
208
209 if (m_particle_type == ParticleType::ELECTRON) { // TODO: find a better way to generalize to electron / photons
210
211 const xAOD::ElectronContainer* electrons = nullptr;
212 CHECK(evtStore()->retrieve(electrons, m_reco_container_name));
213
214 std::pair<xAOD::ElectronContainer*, xAOD::ShallowAuxContainer*> electrons_shallowCopy = xAOD::shallowCopyContainer(*electrons);
215 for (xAOD::Electron* el : *electrons_shallowCopy.first) {
216 ATH_MSG_DEBUG("new electron eta: " << el->eta());
217
218
219 CHECK(do_truth(*el));
220 CHECK(do_egamma(*el));
221 for (unsigned int itool = 0; itool != m_EgammaCalibrationAndSmearingTools.size(); ++itool) {
222 CHECK(do_energy(*el, itool));
223 }
224
225 m_tree->Fill();
226
227 if (m_keep_one) break;
228 }
229 }
231
232 const xAOD::PhotonContainer* photons = nullptr;
233 CHECK(evtStore()->retrieve(photons, m_reco_container_name));
234
235 std::pair<xAOD::PhotonContainer*, xAOD::ShallowAuxContainer*> photons_shallowCopy = xAOD::shallowCopyContainer(*photons);
236 for (xAOD::Photon* ph : *photons_shallowCopy.first) {
237 ATH_MSG_DEBUG("new photon eta: " << ph->eta());
238
239 CHECK(do_truth(*ph));
240 CHECK(do_egamma(*ph));
241
242 if (const auto* vertex = ph->vertex()) {
243 m_ph_Rconv = hypot(vertex->position().x(), vertex->position().y());
244 }
245 else { m_ph_Rconv = 0; }
246
247 const auto original = xAOD::EgammaHelpers::conversionType(ph);
248 if (original == 3) m_ph_convFlag = 2;
249 else if (original != 0) m_ph_convFlag = 1;
250 else m_ph_convFlag = original;
251
252 for (unsigned int itool = 0; itool != m_EgammaCalibrationAndSmearingTools.size(); ++itool) {
253 CHECK(do_energy(*ph, itool));
254 }
255
256 m_tree->Fill();
257
258 if (m_keep_one) break;
259 }
260 }
261
262 return StatusCode::SUCCESS;
263}
264
266{
267 // truth
268 const xAOD::TruthParticle* true_particle = nullptr;
269 true_particle = xAOD::TruthHelpers::getTruthParticle(particle);
270
271 if (true_particle) {
272 m_truth_matched = true;
273 m_truth_pt = true_particle->pt();
274 m_truth_phi = true_particle->phi();
275 m_truth_eta = true_particle->eta();
276 m_truth_E = true_particle->e();
277 m_truth_pdgId = true_particle->pdgId();
278
280 for (size_t p = 0; p < true_particle->nParents(); ++p) {
281 if (true_particle->parent(p)) { m_truth_parent_pdgId = true_particle->parent(p)->pdgId(); break; }
282 }
283
286 m_truth_Rconv = (true_particle->pdgId() == 22) ? (true_particle->hasDecayVtx() ? true_particle->decayVtx()->perp() : 0) : -999;
287 }
288
289 }
290 else {
292 m_truth_matched = false;
293 m_truth_isConv = false; // careful here (always check truth_matched before)
294 }
295 return StatusCode::SUCCESS;
296}
297
299{
300 m_cl_phi = particle.phi();
301 m_cl_eta = particle.caloCluster()->eta();
302 m_cl_etaCalo = xAOD::get_eta_calo(*particle.caloCluster(),particle.author());
303 m_cl_rawcl_Es0 = particle.caloCluster()->energyBE(0);
304 m_cl_rawcl_Es1 = particle.caloCluster()->energyBE(1);
305 m_cl_rawcl_Es2 = particle.caloCluster()->energyBE(2);
306 m_cl_rawcl_Es3 = particle.caloCluster()->energyBE(3);
307 static const SG::AuxElement::Accessor<float> wstot_accessor("wtots1");
308 m_wstot = wstot_accessor.isAvailable(particle) ? wstot_accessor(particle) : -999;
309 m_cl_E = particle.caloCluster()->e();
310
311 return StatusCode::SUCCESS;
312}
313
314StatusCode DumpAllSystematics::do_energy(xAOD::Egamma& particle, int itool)
315{
317 std::fill(m_energy_variations[itool].begin(), m_energy_variations[itool].end(), -999.);
318
319 if (m_EgammaCalibrationAndSmearingTools[itool]->applySystematicVariation(CP::SystematicSet()) != StatusCode::SUCCESS) {
320 ATH_MSG_ERROR("cannot apply nominal energy");
321 return StatusCode::FAILURE;
322 }
323 if (m_EgammaCalibrationAndSmearingTools[itool]->applyCorrection(particle) == CP::CorrectionCode::Ok) {
324 m_nominal_E[itool] = particle.e();
325 ATH_MSG_DEBUG("nominal energy: " << particle.e());
326 }
327 else {
328 ATH_MSG_WARNING("Cannot calibrate electron, eta: " << particle.eta() << " phi: " << particle.phi());
329 return StatusCode::FAILURE;
330 }
331
332 // systematics
333 m_energy_variations_sum_up[itool] = 0.;
335
336 const CP::SystematicSet& sys_set = m_EgammaCalibrationAndSmearingTools[itool]->recommendedSystematics();
337 int isys = -1; // ugly
338 for (const auto& sys : sys_set) {
339 ++isys;
341 ss.insert(sys);
342
343 if (m_EgammaCalibrationAndSmearingTools[itool]->applySystematicVariation(ss) != StatusCode::SUCCESS) {
344 ATH_MSG_ERROR("Cannot configure calibration tool for systematic");
345 continue;
346 }
347
348 if (m_EgammaCalibrationAndSmearingTools[itool]->applyCorrection(particle) == CP::CorrectionCode::Ok) {
349 m_energy_variations[itool][isys] = particle.e() / m_nominal_E[itool] - 1;
350
351 if (sys.basename().find("SCALE") != std::string::npos) { // sum only the scale variations
352 if (sys.parameter() == 1) m_energy_variations_sum_up[itool] += m_energy_variations[itool][isys] * m_energy_variations[itool][isys];
353 else if (sys.parameter() == -1) m_energy_variations_sum_down[itool] += m_energy_variations[itool][isys] * m_energy_variations[itool][isys];
354 }
355 ATH_MSG_DEBUG("calibrated with systematic " << sys.name() << ": " << particle.e());
356 }
357 else {
358 ATH_MSG_WARNING("Cannot calibrate electron with systematic");
359 }
360 }
361
364
365 return StatusCode::SUCCESS;
366}
367
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define CHECK(...)
Evaluate an expression and check for errors.
static Double_t ss
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
@ Ok
The correction was done successfully.
Class to wrap a set of SystematicVariations.
size_t size() const
returns: size of the set
StatusCode do_egamma(const xAOD::Egamma &particle)
StatusCode do_truth(const xAOD::Egamma &particle)
virtual StatusCode finalize()
DumpAllSystematics(const std::string &name, ISvcLocator *svcLoc)
Regular Algorithm constructor.
StatusCode do_energy(xAOD::Egamma &particle, int itool)
std::vector< float > m_energy_variations_sum_down
ParticleType m_particle_type
std::vector< std::vector< float > > m_energy_variations
virtual StatusCode execute()
unsigned long long m_EventNumber
std::vector< float > m_nominal_E
std::string m_reco_container_name
virtual StatusCode initialize()
ToolHandleArray< CP::IEgammaCalibrationAndSmearingTool > m_EgammaCalibrationAndSmearingTools
std::vector< float > m_energy_variations_sum_up
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
Definition Egamma_v1.cxx:71
float averageInteractionsPerCrossing() const
Average interactions per crossing for all BCIDs - for out-of-time pile-up.
float actualInteractionsPerCrossing() const
Average interactions per crossing for the current BCID - for in-time pile-up.
uint32_t runNumber() const
The current event's run number.
uint64_t eventNumber() const
The current event's event number.
const xAOD::Vertex * vertex(size_t index=0) const
Pointer to the xAOD::Vertex/es that match the photon candidate.
Definition Photon_v1.cxx:61
int pdgId() const
PDG ID code.
const TruthVertex_v1 * decayVtx() const
The decay vertex of this particle.
const TruthParticle_v1 * parent(size_t i) const
Retrieve the i-th mother (TruthParticle) of this TruthParticle.
bool hasDecayVtx() const
Check for a decay vertex on this particle.
virtual double e() const override final
The total energy of the particle.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
size_t nParents() const
Number of parents of this particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
virtual double phi() const override final
The azimuthal angle ( ) of the particle.
float perp() const
Vertex transverse distance from the beam line.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
xAOD::EgammaParameters::ConversionType conversionType(const xAOD::Photon *ph)
return the photon conversion type (see EgammaEnums)
bool isTrueConvertedPhoton(const xAOD::Photon *ph, float maxRadius=800.)
is the object matched to a true converted photon with R < maxRadius
const xAOD::TruthParticle * getTruthParticle(const xAOD::IParticle &p)
Return the truthParticle associated to the given IParticle (if any)
@ PileUp
Pile-up vertex.
@ PriVtx
Primary vertex.
PhotonContainer_v1 PhotonContainer
Definition of the current "photon container version".
ElectronContainer_v1 ElectronContainer
Definition of the current "electron container version".
EventInfo_v1 EventInfo
Definition of the latest event info version.
std::pair< std::unique_ptr< T >, std::unique_ptr< ShallowAuxContainer > > shallowCopyContainer(const T &cont, const EventContext &ctx)
Function making a shallow copy of a constant container.
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
Egamma_v1 Egamma
Definition of the current "egamma version".
Definition Egamma.h:17
float get_eta_calo(const xAOD::CaloCluster &cluster, int author, bool do_throw=false)
TruthParticle_v1 TruthParticle
Typedef to implementation.
Photon_v1 Photon
Definition of the current "egamma version".
Electron_v1 Electron
Definition of the current "egamma version".