ATLAS Offline Software
Loading...
Searching...
No Matches
EgammaCalibrationAndSmearingTool.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#ifndef EGAMMA_CALIB_TOOL_H_
6#define EGAMMA_CALIB_TOOL_H_
7
8#include <array>
9#include <functional>
10#include <map>
11#include <memory>
12#include <string>
13
17#include "AsgTools/AsgTool.h"
36#include "xAODEgamma/Egamma.h"
37#include "xAODEgamma/Electron.h"
38#include "xAODEgamma/Photon.h"
40
41// Forward declarations
43namespace egGain {
44class GainTool;
45class GainUncertainty;
46} // namespace egGain
47class LinearityADC;
48class TH2;
49
50namespace xAOD {
51inline float get_phi_calo(const xAOD::CaloCluster& cluster, int author,
52 bool do_throw = false) {
53 static const SG::ConstAccessor<float> phiCaloAcc("phiCalo");
54 double phi_calo;
56 phi_calo = cluster.phi();
58 phi_calo)) {
59 } else if (phiCaloAcc.isAvailable(cluster)) {
60 phi_calo = phiCaloAcc(cluster);
61 } else {
62 asg::AsgMessaging msg("get_phi_calo");
63 msg.msg(MSG::ERROR) << "phiCalo not available as auxilliary variable"
64 << endmsg;
65 if (do_throw) {
66 throw std::runtime_error("phiCalo not available as auxilliary variable");
67 }
68 msg.msg(MSG::WARNING) << "using phi as phiCalo" << endmsg;
69 phi_calo = cluster.phi();
70 }
71 return phi_calo;
72}
73
74inline float get_eta_calo(const xAOD::CaloCluster& cluster, int author,
75 bool do_throw = false) {
76 double eta_calo;
77 static const SG::ConstAccessor<float> etaCaloAcc("etaCalo");
79 eta_calo = cluster.eta();
81 eta_calo)) {
82 } else if (etaCaloAcc.isAvailable(cluster)) {
83 eta_calo = etaCaloAcc(cluster);
84 } else {
85 asg::AsgMessaging msg("get_eta_calo");
86 msg.msg(MSG::ERROR) << "etaCalo not available as auxilliary variable"
87 << endmsg;
88 if (do_throw) {
89 throw std::runtime_error("etaCalo not available as auxilliary variable");
90 }
91 msg.msg(MSG::WARNING) << "using eta as etaCalo" << endmsg;
92 }
93 return eta_calo;
94}
95} // namespace xAOD
96
97
98// the columnar accessor variant of the above functions. I'm not sure
99// if they are used anywhere else, so I'm keeping both.
100namespace columnar {
101 namespace ClusterHelpers {
102
103 template<ContainerIdConcept CI = ClusterDef,ColumnarModeConcept CM=ColumnarMode>
104 class PhiCaloAccessor final
105 {
109
110 public:
111
113 : m_phiCaloAcc (columnarTool, "phiCalo", {.isOptional = true}),
114 m_phiAcc (columnarTool, "calPhi"),
115 m_phicaloframeAcc (columnarTool, "PHICALOFRAME", {.isOptional = true})
116 {}
117
118 float operator () (ClusterId cluster, int author, bool do_throw=false) const
119 {
120 double phi_calo;
122 phi_calo = m_phiAcc (cluster);
123 }
124 else if (m_phicaloframeAcc.isAvailable (cluster)) {
125 phi_calo = m_phicaloframeAcc (cluster);
126 }
127 else if (m_phiCaloAcc.isAvailable(cluster)) {
128 phi_calo = m_phiCaloAcc(cluster);
129 }
130 else {
131 asg::AsgMessaging msg("get_phi_calo");
132 msg.msg(MSG::ERROR) << "phiCalo not available as auxilliary variable" << endmsg;
133 if (do_throw) { throw std::runtime_error("phiCalo not available as auxilliary variable"); }
134 msg.msg(MSG::WARNING) << "using phi as phiCalo" << endmsg;
135 phi_calo = m_phiAcc (cluster);
136 }
137 return phi_calo;
138 }
139 };
140
141 template<ContainerIdConcept CI = ClusterDef,ColumnarModeConcept CM=ColumnarMode>
142 class EtaCaloAccessor final
143 {
147
148 public:
149
151 : m_etaCaloAcc (columnarTool, "etaCalo", {.isOptional = true}),
152 m_etaAcc (columnarTool, "calEta"),
153 m_etacaloframeAcc (columnarTool, "ETACALOFRAME", {.isOptional = true})
154 {}
155
156 float operator () (ClusterId cluster, int author, bool do_throw=false) const
157 {
158 double eta_calo;
160 eta_calo = m_etaAcc (cluster);
161 }
162 else if (m_etacaloframeAcc.isAvailable(cluster)) {
163 eta_calo = m_etacaloframeAcc(cluster);
164 }
165 else if (m_etaCaloAcc.isAvailable(cluster)) {
166 eta_calo = m_etaCaloAcc(cluster);
167 }
168 else {
169 asg::AsgMessaging msg("get_eta_calo");
170 msg.msg(MSG::ERROR) << "etaCalo not available as auxilliary variable" << endmsg;
171 if (do_throw) { throw std::runtime_error("etaCalo not available as auxilliary variable"); }
172 msg.msg(MSG::WARNING) << "using eta as etaCalo" << endmsg;
173 eta_calo = m_etaAcc (cluster);
174 }
175 return eta_calo;
176 }
177 };
178 }
179}
180
181namespace ADD_CMODE(CP) {
182
183class EgammaCalibrationAndSmearingTool
184 : virtual public CP::IEgammaCalibrationAndSmearingTool,
185 public asg::AsgMetadataTool, public columnar::ColumnarTool<> {
186 // Create a proper constructor for Athena
187 ASG_TOOL_CLASS3(EgammaCalibrationAndSmearingTool,
188 IEgammaCalibrationAndSmearingTool, CP::ISystematicsTool,
189 CP::IReentrantSystematicsTool)
190
191 public:
192 enum class ScaleDecorrelation {
193 FULL,
194 ONENP,
195 FULL_ETA_CORRELATED,
196 ONENP_PLUS_UNCONR
197 };
198 enum class ResolutionDecorrelation { FULL, ONENP };
199 static const int AUTO = 2; // this is used as a third state for boolean
200 // properties (true/false/automatic)
201 typedef unsigned int RandomNumber;
202 typedef std::function<int(const EgammaCalibrationAndSmearingTool&,
204 IdFunction;
205 typedef std::function<bool(const EgammaCalibrationAndSmearingTool&, columnar::EgammaId)> EgammaPredicate;
206
207 EgammaCalibrationAndSmearingTool(const std::string& name);
208 ~EgammaCalibrationAndSmearingTool();
209
210 StatusCode initialize() override;
211
212 // Apply the correction on a modifyable egamma object
213 virtual CP::CorrectionCode applyCorrection(xAOD::Egamma&) const override;
214 CP::CorrectionCode applyCorrection(columnar::MutableEgammaId input, columnar::EventInfoId event_info) const;
215 void setPt(columnar::MutableEgammaId input, double energy) const;
216
217 // Create a corrected copy from a constant egamma object
218 // virtual CP::CorrectionCode correctedCopy(const xAOD::Egamma&,
219 // xAOD::Egamma*&);
220 virtual CP::CorrectionCode correctedCopy(const xAOD::Electron&,
221 xAOD::Electron*&) const override;
222 virtual CP::CorrectionCode correctedCopy(const xAOD::Photon&,
223 xAOD::Photon*&) const override;
224 double getEnergy(const xAOD::Photon&) const; // for python usage
225 double getEnergy(const xAOD::Electron&) const; // for python usage
226
227 // systematics
228 // Which systematics have an effect on the tool's behaviour?
229 virtual CP::SystematicSet affectingSystematics() const override;
230 // Is the tool affected by a specific systematic?
231 virtual bool isAffectedBySystematic(
232 const CP::SystematicVariation& systematic) const override;
233 // Systematics to be used for physics analysis
234 virtual CP::SystematicSet recommendedSystematics() const override;
235 // Use specific systematic
236 virtual StatusCode applySystematicVariation(
237 const CP::SystematicSet& systConfig) override;
238 virtual void setRandomSeedFunction(const IdFunction&& function) {
239 m_set_seed_function = std::move(function);
240 }
241 const IdFunction getRandomSeedFunction() const { return m_set_seed_function; }
242
243 virtual double resolution(
244 double energy, double cl_eta, double cl_etaCalo,
246 bool withCT = false) const override;
247
248 private:
249 static const unsigned int m_Run2Run3runNumberTransition = 400000;
250
251 std::string m_ESModel;
252 std::string m_decorrelation_model_name;
253 std::string m_decorrelation_model_scale_name;
254 std::string m_decorrelation_model_resolution_name;
255 ScaleDecorrelation m_decorrelation_model_scale = ScaleDecorrelation::FULL;
256 ResolutionDecorrelation m_decorrelation_model_resolution =
257 ResolutionDecorrelation::FULL;
258 egEnergyCorr::ESModel m_TESModel;
259 int m_doScaleCorrection;
260 int m_doSmearing;
261 double m_varSF;
262 std::string m_ResolutionType;
264 int m_useFastSim;
265 int m_use_AFII;
268 // flags duplicated from the underlying ROOT tool
269 int m_useIntermoduleCorrection;
270 int m_usePhiUniformCorrection;
271 int m_useCaloDistPhiUnifCorrection;
272 int m_useGainCorrection;
273 int m_doADCLinearityCorrection;
274 int m_doLeakageCorrection;
275 bool m_use_ep_combination;
276 int m_use_mva_calibration;
277 bool m_use_full_statistical_error;
278 int m_use_temp_correction201215;
279 int m_use_uA2MeV_2015_first2weeks_correction;
280 bool m_use_mapping_correction;
281 int m_user_random_run_number;
282 int m_useGainInterpolation;
283 int m_useLayerCorrection;
284 int m_usePSCorrection;
285 int m_useS12Correction;
286 int m_useSaccCorrection;
287 bool m_decorateEmva;
288
289 // 2D histrogram (eta,phi) for a correction to cope with calo distortion
290 // (sagging)
291 std::unique_ptr<TH2> m_caloDistPhiUnifCorr;
292
293 Gaudi::Property<bool> m_fixForMissingCells{
294 this, "FixForMissingCells", true,
295 "AOD fix for cell recovery in core egamma cluster"};
296
297 Gaudi::Property<bool> m_doFwdCalib{
298 this, "DoFwdElectronCalibration", false,
299 "MVA calibration of the forward electron"};
300
301 Gaudi::Property<bool> m_doElectronMVA{
302 this, "DoElectronMVACalibration", true,
303 "Load the electron MVA calibration (disable if no electrons are calibrated)"};
304
305 Gaudi::Property<bool> m_doPhotonMVA{
306 this, "DoPhotonMVACalibration", true,
307 "Load the photon MVA calibrations (disable if no photons are calibrated)"};
308
309 Gaudi::Property<std::string> m_pVtxKey{
310 this, "PrimaryVerticesKey", "PrimaryVertices",
311 "Name of the primary vertex container"};
312
313 void setupSystematics();
314
315 // if using eta not abs_eta
316 struct EtaCaloPredicate
317 {
318 EtaCaloPredicate(double eta_min, double eta_max) : m_eta_min(eta_min), m_eta_max(eta_max) {}
319 bool operator()(const EgammaCalibrationAndSmearingTool& tool, columnar::EgammaId p) {
320 const Accessors& acc = *tool.m_accessors;
321 const double eta = acc.etaCaloAcc(acc.caloClusterAcc(p)[0].value(),acc.authorAcc (p));
322 return (eta >= m_eta_min and eta < m_eta_max);
323 }
324 private:
325 float m_eta_min, m_eta_max;
326 };
327
328 const EgammaPredicate EtaCaloPredicateFactory(double eta_min, double eta_max) const
329 {
330 return EtaCaloPredicate(eta_min, eta_max);
331 }
332
333 // this is needed (instead of a simpler lambda since a clang bug, see
334 // https://its.cern.ch/jira/browse/ATLASG-688)
335 struct AbsEtaCaloPredicate {
336 AbsEtaCaloPredicate(double eta_min, double eta_max)
337 : m_eta_min(eta_min), m_eta_max(eta_max) {}
338 bool operator()(const EgammaCalibrationAndSmearingTool& tool, columnar::EgammaId p) {
339 const Accessors& acc = *tool.m_accessors;
340 const double aeta =
341 std::abs(acc.etaCaloAcc(acc.caloClusterAcc(p)[0].value(),acc.authorAcc (p)));
342 return (aeta >= m_eta_min and aeta < m_eta_max);
343 }
344
345 private:
346 float m_eta_min, m_eta_max;
347 };
348
349 const EgammaPredicate AbsEtaCaloPredicateFactory(double eta_min,
350 double eta_max) const {
351 /*return [eta_min, eta_max](const xAOD::Egamma& p) {
352 const double aeta = std::abs(xAOD::get_eta_calo(*p.caloCluster()));
353 return (aeta >= eta_min and aeta < eta_max); };*/
354 return AbsEtaCaloPredicate(eta_min, eta_max);
355 }
356
357 const EgammaPredicate AbsEtaCaloPredicateFactory(
358 std::pair<double, double> edges) const {
359 return AbsEtaCaloPredicateFactory(edges.first, edges.second);
360 }
361
362 const std::vector<EgammaPredicate> AbsEtaCaloPredicatesFactory(
363 const std::vector<std::pair<double, double>>& edges) const {
364 std::vector<EgammaPredicate> result;
365 result.reserve(edges.size());
366 for (const auto& it : edges) {
367 result.push_back(AbsEtaCaloPredicateFactory(it.first, it.second));
368 }
369 return result;
370 }
371
372 const std::vector<EgammaPredicate> AbsEtaCaloPredicatesFactory(
373 const std::vector<double>& edges) const {
374 std::vector<EgammaPredicate> result;
375 result.reserve(edges.size() - 1);
376 auto it2 = edges.begin();
377 auto it = it2++;
378 for (; it2 != edges.end(); ++it, ++it2) {
379 result.push_back(AbsEtaCaloPredicateFactory(*it, *it2));
380 }
381 return result;
382 }
383
384 struct DoubleOrAbsEtaCaloPredicate {
385 DoubleOrAbsEtaCaloPredicate(double eta1_min, double eta1_max,
386 double eta2_min, double eta2_max)
387 : m_eta1_min(eta1_min),
388 m_eta1_max(eta1_max),
389 m_eta2_min(eta2_min),
390 m_eta2_max(eta2_max) {}
391
392 bool operator()(const EgammaCalibrationAndSmearingTool& tool, columnar::EgammaId p) {
393 const Accessors& acc = *tool.m_accessors;
394 const double aeta =
395 std::abs(acc.etaCaloAcc(acc.caloClusterAcc(p)[0].value(),acc.authorAcc (p)));
396 return ((aeta >= m_eta1_min and aeta < m_eta1_max) or
397 (aeta >= m_eta2_min and aeta < m_eta2_max));
398 }
399
400 private:
401 float m_eta1_min, m_eta1_max, m_eta2_min, m_eta2_max;
402 };
403
404 const EgammaPredicate DoubleOrAbsEtaCaloPredicateFactory(
405 double eta1_min, double eta1_max, double eta2_min,
406 double eta2_max) const {
407 return DoubleOrAbsEtaCaloPredicate(eta1_min, eta1_max, eta2_min, eta2_max);
408 }
409
410 PATCore::ParticleType::Type xAOD2ptype(columnar::EgammaId particle) const;
411
412 public:
413 virtual double getEnergy(xAOD::Egamma*, const xAOD::EventInfo*);
414 virtual double getElectronMomentum(const xAOD::Electron*,
415 const xAOD::EventInfo*);
416 double getResolution(const xAOD::Egamma& particle,
417 bool withCT = true) const override;
418 double intermodule_correction(double Ecl, double phi, double eta) const;
419 double correction_phi_unif(double eta, double phi) const;
420
421 private:
422 ServiceHandle<IegammaMVASvc> m_MVACalibSvc{this, "MVACalibSvc", "",
423 "calibration service"};
424 std::unique_ptr<egGain::GainUncertainty> m_gain_tool_run2;
425 std::shared_ptr<LinearityADC> m_ADCLinearity_tool;
426 egGain::GainTool* m_gain_tool = nullptr;
427 egammaLayerRecalibTool* m_layer_recalibration_tool = nullptr;
428 std::string m_layer_recalibration_tune;
429
430 // A pointer to the underlying ROOT tool
431 std::unique_ptr<AtlasRoot::egammaEnergyCorrectionTool> m_rootTool;
432 std::string m_MVAfolder;
433
434 struct SysInfo {
435 EgammaPredicate predicate;
437 };
438
439 std::map<CP::SystematicVariation, SysInfo> m_syst_description;
440 std::map<CP::SystematicVariation, egEnergyCorr::Resolution::Variation>
441 m_syst_description_resolution;
442
443 // These are modified by the ISystematicsTool methods
444 egEnergyCorr::Scale::Variation m_currentScaleVariation_MC;
445 egEnergyCorr::Scale::Variation m_currentScaleVariation_data;
446 egEnergyCorr::Resolution::Variation m_currentResolutionVariation_MC;
447 egEnergyCorr::Resolution::Variation m_currentResolutionVariation_data;
448
449 EgammaPredicate m_currentScalePredicate;
450
451 IdFunction m_set_seed_function;
452
453 inline egEnergyCorr::Scale::Variation oldtool_scale_flag_this_event(
454 columnar::EgammaId p, columnar::EventInfoId event_info) const;
455 inline egEnergyCorr::Resolution::Variation oldtool_resolution_flag_this_event(
456 columnar::EgammaId p, columnar::EventInfoId event_info) const;
457
458 // columnar data handles
459public:
460 Gaudi::Property<bool> m_onlyElectrons {this, "onlyElectrons", false, "the tool will only be applied to electrons"};
461 Gaudi::Property<bool> m_onlyPhotons {this, "onlyPhotons", false, "the tool will only be applied to photons"};
462 struct Accessors : public columnar::ColumnarTool<>
463 {
464 Accessors(columnar::ColumnarTool<>& tool) : columnar::ColumnarTool<>(&tool) {}
465
466 columnar::MutableEgammaAccessor<columnar::ObjectColumn> m_egammaHandle {*this, "EGamma"};
467 columnar::MomentumAccessors<columnar::EgammaDef> momAcc;
469 columnar::EgammaDecorator<float> ptOutDec {*this, "ptOut", {.replacesColumn = "pt"}};
473 // test GNN
475 columnar::EgammaAccessor<uint16_t> authorAcc {*this, "author"};
478 columnar::ClusterAccessor<columnar::ObjectColumn> m_clusterHandle {*this, "egammaClusters"};
479 columnar::EgammaAccessor<std::vector<columnar::OptClusterId>> caloClusterAcc {*this, "caloClusterLinks"};
480 columnar::ClusterAccessor<double> Es0Acc {*this, "correctedcl_Es0", {.isOptional = true}};
481 columnar::ClusterAccessor<double> Es1Acc {*this, "correctedcl_Es1", {.isOptional = true}};
482 columnar::ClusterAccessor<double> Es2Acc {*this, "correctedcl_Es2", {.isOptional = true}};
483 columnar::ClusterAccessor<double> Es3Acc {*this, "correctedcl_Es3", {.isOptional = true}};
486 columnar::ClusterHelpers::EnergyBEAccessor<> energyBEAcc {*this};
487 columnar::ClusterHelpers::EtaBEAccessor<> clusterEtaBEAcc {*this};
488 columnar::ClusterHelpers::EtaCaloAccessor<> etaCaloAcc {*this};
489 columnar::ClusterHelpers::PhiCaloAccessor<> phiCaloAcc {*this};
490 columnar::EventInfoAccessor<columnar::ObjectColumn> m_eventHandle {*this, "EventInfo", {.addMTDependency=true}};
491 columnar::EventInfoHelpers::EventTypeAccessor<> eventTypeAcc {*this};
492 columnar::EventInfoAccessor<uint32_t> runNumberAcc {*this, "runNumber"};
493 columnar::EventInfoAccessor<uint64_t> eventNumberAcc {*this, "eventNumber"};
494 columnar::EventInfoAccessor<unsigned int> randomrunnumber_getter {*this, "RandomRunNumber"};
495 columnar::EventInfoAccessor<float> actIntPerXingAcc {*this, "actualInteractionsPerCrossing"};
496 };
497 std::unique_ptr<Accessors> m_accessors;
498
499 void callSingleEvent (columnar::MutableEgammaRange egammas, columnar::EventInfoId event) const;
500 void callEvents (columnar::EventContextRange events) const override;
501};
502
503} // namespace ADD_CMODE(CP)
504#endif
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define endmsg
#define ASG_TOOL_CLASS3(CLASSNAME, INT1, INT2, INT3)
Helper class to provide constant type-safe access to aux data.
void operator()(T1)
parameterization of correction for ADC non linearity
Helper class to provide constant type-safe access to aux data.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
Class mimicking the AthMessaging class from the offline software.
float operator()(ClusterId cluster, int author, bool do_throw=false) const
float operator()(ClusterId cluster, int author, bool do_throw=false) const
the base class for all columnar components
bool retrieveMoment(MomentType type, double &value) const
Retrieve individual moment.
virtual double eta() const
The pseudorapidity ( ) of the particle.
virtual double phi() const
The azimuthal angle ( ) of the particle.
@ ETACALOFRAME
Eta in the calo frame (for egamma).
@ PHICALOFRAME
Phi in the calo frame (for egamma).
double resolution[nGasTypes][nParametersResolution]
::StatusCode StatusCode
StatusCode definition for legacy code.
AccessorTemplate< CI, CT, ColumnAccessMode::input, CM > ColumnAccessor
AccessorTemplate< ClusterDef, CT, ColumnAccessMode::input, CM > ClusterAccessor
Definition ClusterDef.h:25
ObjectRange< MutableEgammaDef > MutableEgammaRange
Definition EgammaDef.h:52
ObjectId< MutableEgammaDef > MutableEgammaId
Definition EgammaDef.h:53
AccessorTemplate< EgammaDef, CT, ColumnAccessMode::input, CM > EgammaAccessor
Definition EgammaDef.h:49
ObjectRange< EventContextDef > EventContextRange
AccessorTemplate< EgammaDef, CT, ColumnAccessMode::output, CM > EgammaDecorator
Definition EgammaDef.h:50
ObjectId< ClusterDef > ClusterId
Definition ClusterDef.h:23
ObjectId< EgammaDef > EgammaId
Definition EgammaDef.h:47
AccessorTemplate< MutableEgammaDef, CT, ColumnAccessMode::input, CM > MutableEgammaAccessor
Definition EgammaDef.h:55
ObjectId< EventInfoDef > EventInfoId
AccessorTemplate< EventInfoDef, CT, ColumnAccessMode::input, CM > EventInfoAccessor
const uint16_t AuthorFwdElectron
Electron reconstructed by the Forward cluster-based algorithm.
Definition EgammaDefs.h:30
ICaloAffectedTool is abstract interface for tools checking if 4 mom is in calo affected region.
float get_phi_calo(const xAOD::CaloCluster &cluster, int author, bool do_throw=false)
EventInfo_v1 EventInfo
Definition of the latest event info version.
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
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)
Photon_v1 Photon
Definition of the current "egamma version".
Definition Photon.h:17
setBGCode setTAP setLVL2ErrorBits bool
Electron_v1 Electron
Definition of the current "egamma version".
Definition Electron.h:17
void initialize()
MsgStream & msg
Definition testRead.cxx:32