ATLAS Offline Software
Loading...
Searching...
No Matches
EgammaCalibrationAndSmearingTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
7
8#include <algorithm>
9#include <format>
10#include <memory>
11#include <string>
12#include <utility>
13
18#include "xAODEgamma/Egamma.h"
24#include "xAODTracking/Vertex.h"
26
27#ifndef ROOTCORE
29#endif
30
31// internal (old) tool
32#include <cmath>
33
40
41namespace CP {
42
43const double GeV = 1000.;
44
45std::unique_ptr<egGain::GainTool> gainToolFactory(egEnergyCorr::ESModel model) {
46 switch (model) {
59 const std::string gain_filename1 = PathResolverFindCalibFile(
60 "ElectronPhotonFourMomentumCorrection/v8/FunctionsTO.root");
61 const std::string gain_filename2 = PathResolverFindCalibFile(
62 "ElectronPhotonFourMomentumCorrection/v8/FunctionsG_all.root");
63 return std::make_unique<egGain::GainTool>(gain_filename1, gain_filename2);
64 }
80 return nullptr;
81 default:
82 return nullptr;
83 }
84}
85
87 std::string folder;
88 switch (model) {
92 folder = "egammaMVACalib/v1";
93 break;
95 folder = "egammaMVACalib/v1";
96 break;
101 folder = "egammaMVACalib/offline/v3";
102 break;
105 folder = "egammaMVACalib/offline/v3_E4crack_bis";
106 break;
114 folder = "egammaMVACalib/offline/v4.0";
115 break;
124 folder = "egammaMVACalib/offline/v7";
125 break;
128 folder = "egammaMVACalib/offline/v9";
129 break;
131 folder = "egammaMVACalib/offline/v10";
132 break;
133 default:
134 folder = "";
135 }
136
137 return folder;
138}
139
140std::unique_ptr<egammaLayerRecalibTool> egammaLayerRecalibToolFactory(
141 egEnergyCorr::ESModel model, int enableSacc) {
142 std::string tune = "";
143 switch (model) {
147 tune = "2011_alt_with_layer2";
148 break;
161 tune = "2012_alt_with_layer2";
162 break;
165 tune = "es2017_20.7_improved";
166 break;
168 tune = "es2017_20.7_final";
169 break;
176 tune = "es2017_21.0_v0";
177 break;
179 tune = "es2018_21.0_v0";
180 break;
182 tune = "es2022_22.0_Precision";
183 break;
185 tune = "es2022_22.0_Precision_v1";
186 break;
188 tune = "es2024_run3_extrapolate_v0";
189 break;
190 default:
191 return nullptr;
192 }
193 return std::make_unique<egammaLayerRecalibTool>(tune, enableSacc);
194}
195
197 switch (model) {
204 return false;
233 return true;
234 case egEnergyCorr::UNDEFINED: // TODO: find better logic
235 return false;
236 }
237 assert(false);
238 return false;
239}
240
242 return use_intermodule_correction(model); // they are equal
243}
244
246 switch (model) {
256 return false;
282 return true;
283 case egEnergyCorr::UNDEFINED: // TODO: find better logic
284 return false;
285 }
286 assert(false);
287 return false;
288}
289
291 const std::string& name)
293 m_TESModel(egEnergyCorr::UNDEFINED),
294 m_TResolutionType(egEnergyCorr::Resolution::SigmaEff90),
298 m_currentResolutionVariation_MC(egEnergyCorr::Resolution::Nominal),
301 columnar::EgammaId egamma,
302 columnar::EventInfoId ei) {
303 const Accessors& acc = *tool.m_accessors;
304 // avoid 0 as result, see
305 // https://root.cern.ch/root/html/TRandom3.html#TRandom3:SetSeed
306 auto cluster = acc.caloClusterAcc(egamma)[0].value();
307 return 1 + static_cast<RandomNumber>(
308 std::abs(acc.clusterPhiAcc(cluster)) * 1E6 +
309 std::abs(acc.clusterEtaAcc(cluster)) * 1E3 +
310 acc.eventNumberAcc(ei));
311 }),
312 m_accessors(std::make_unique<Accessors>(*this)) {
313
314 declareProperty("ESModel", m_ESModel = "");
315 declareProperty("decorrelationModel", m_decorrelation_model_name = "");
316 declareProperty("decorrelationModelScale",
317 m_decorrelation_model_scale_name = "");
318 declareProperty("decorrelationModelResolution",
319 m_decorrelation_model_resolution_name = "");
320 declareProperty("ResolutionType", m_ResolutionType = "SigmaEff90");
321 declareProperty("varSF", m_varSF = 1.0);
322 declareProperty("doScaleCorrection", m_doScaleCorrection = AUTO);
323 declareProperty("doSmearing", m_doSmearing = AUTO);
324 declareProperty("useLayerCorrection", m_useLayerCorrection = AUTO);
325 declareProperty("usePSCorrection", m_usePSCorrection = AUTO);
326 declareProperty("useS12Correction", m_useS12Correction = AUTO);
327 declareProperty("useSaccCorrection", m_useSaccCorrection = AUTO);
328 declareProperty("useIntermoduleCorrection",
329 m_useIntermoduleCorrection = AUTO);
330 declareProperty("usePhiUniformCorrection", m_usePhiUniformCorrection = AUTO);
331 declareProperty("useCaloDistPhiUnifCorrection",
332 m_useCaloDistPhiUnifCorrection = AUTO);
333 declareProperty("useGainCorrection", m_useGainCorrection = AUTO);
334 declareProperty("useGainInterpolation", m_useGainInterpolation = AUTO);
335 declareProperty("doADCLinearityCorrection",
336 m_doADCLinearityCorrection = AUTO);
337 declareProperty("doLeakageCorrection", m_doLeakageCorrection = AUTO);
338 declareProperty("MVAfolder", m_MVAfolder = "");
339 declareProperty("layerRecalibrationTune", m_layer_recalibration_tune = "");
340 declareProperty("useEPCombination", m_use_ep_combination = false);
341 declareProperty("useMVACalibration", m_use_mva_calibration = AUTO);
342 declareProperty("use_full_statistical_error",
343 m_use_full_statistical_error = false);
344 declareProperty("use_temp_correction201215",
345 m_use_temp_correction201215 = AUTO);
346 declareProperty("use_uA2MeV_2015_first2weeks_correction",
347 m_use_uA2MeV_2015_first2weeks_correction = AUTO);
348 declareProperty("randomRunNumber", m_user_random_run_number = 0);
349 // this is the user input, it is never changed by the tool. The tool uses
350 // m_simulation.
351 declareProperty("useFastSim", m_useFastSim = -1,
352 "This should be explicitly set by the user depending on the "
353 "data type (int)0=full sim, (int)1=fast sim");
354 declareProperty(
355 "useAFII", m_use_AFII = -1,
356 "This is now deprecated. Kept for explicit error message for now");
357 declareProperty("decorateEmva", m_decorateEmva = false, "whether to decorate the eMVA value");
358}
359
365
367 ATH_MSG_INFO("Initialization");
368
369 if (m_ESModel == "es2015XX") {
370 ATH_MSG_ERROR("es2015XX is deprecated. Use es2015PRE");
371 }
372
373 if (m_ESModel == "es2010") {
375 } // legacy
376 else if (m_ESModel == "es2011c") {
378 } // mc11c : faulty G4; old geometry
379 else if (m_ESModel == "es2011d") {
381 } // mc11d : corrected G4; new geometry == final Run1 scheme
382 else if (m_ESModel == "es2012a") {
384 } // mc12a : "crude" G4 fix; old geometry
385 else if (m_ESModel == "es2012c") {
387 } // mc12c : corrected G4; new geometry == final Run1 scheme
388 else if (m_ESModel == "es2012XX") {
390 } else if (m_ESModel == "es2015PRE") {
392 } else if (m_ESModel == "es2015PRE_res_improved") {
394 } else if (m_ESModel == "es2015cPRE") {
396 } else if (m_ESModel == "es2015cPRE_res_improved") {
398 } else if (m_ESModel == "es2015c_summer") {
400 } else if (m_ESModel == "es2016PRE") {
402 } else if (m_ESModel == "es2016data_mc15c") {
404 } else if (m_ESModel == "es2016data_mc15c_summer") {
406 } else if (m_ESModel == "es2016data_mc15c_summer_improved") {
408 } else if (m_ESModel == "es2016data_mc15c_final") {
410 } else if (m_ESModel == "es2015_5TeV") {
412 } else if (m_ESModel == "es2017_R21_PRE") {
414 } else if (m_ESModel == "es2017_R21_v0") {
416 } else if (m_ESModel == "es2017_R21_v1") {
418 } else if (m_ESModel == "es2017_R21_ofc0_v1") {
420 } else if (m_ESModel == "es2018_R21_v0") {
422 } else if (m_ESModel == "es2018_R21_v1") {
424 } else if (m_ESModel == "es2022_R22_PRE") {
426 } else if (m_ESModel == "es2023_R22_Run2_v0") {
428 } else if (m_ESModel == "es2023_R22_Run2_v1") {
430 } else if (m_ESModel == "es2024_Run3_ofc0_v0") {
432 } else if (m_ESModel == "es2024_Run3_v0") {
434 } else if (m_ESModel == "es2025_Run3_GNN_v0") {
436 } else if (m_ESModel.empty()) {
437 ATH_MSG_ERROR("you must set ESModel property");
438 return StatusCode::FAILURE;
439 } else {
440 ATH_MSG_ERROR("Cannot understand model " << m_ESModel);
441 return StatusCode::FAILURE;
442 }
443
444 if (m_ResolutionType == "Gaussian") {
446 } else if (m_ResolutionType == "SigmaEff80") {
448 } else if (m_ResolutionType == "SigmaEff90") {
450 } else {
451 ATH_MSG_ERROR("Cannot understand resolution " << m_ResolutionType);
452 return StatusCode::FAILURE;
453 }
454
455 if (m_use_AFII != -1) {
457 "Property useAFII is deprecated. It is now replaced with useFastSim, "
458 "which should be explicitly configured");
459 return StatusCode::FAILURE;
460 }
461
462 if (m_useFastSim == 1) {
464 } else if (m_useFastSim == 0) {
466 } else {
467 ATH_MSG_ERROR("Property useFastSim should be explicitly configured");
468 return StatusCode::FAILURE;
469 }
470
474 "Sample is FastSim but no AF3 calibration is supported with "
475 "MC23 pre-recommendations (es2022_R22_PRE and es2024_Run3_ofc0_v0). "
476 "Please swtich to Run3 consolidated recommendations (es2024_Run3_v0), "
477 "or get in touch with the EGamma CP group in case you are using this");
478 return StatusCode::FAILURE;
479 }
480
481 // configure decorrelation model, translate string property to internal class
482 // enum
483 /* S R SR
484 0. 0 0 0 WARNING Full, Full (this is the default without configuration)
485 1. 0 0 1 SR
486 2. 0 1 0 FATAL
487 3. 0 1 1 WARNING SR then R
488 4. 1 0 0 FATAL
489 5. 1 0 1 WARNING SR then S
490 6. 1 1 0 S, R
491 7. 1 1 1 FATAL
492 */
493 if (m_decorrelation_model_name.empty() and
496 // case 0
497 ATH_MSG_WARNING("no decorrelation model specified, assuming full model");
498 m_decorrelation_model_scale = ScaleDecorrelation::FULL;
500 m_decorrelation_model_name = "FULL_v1";
501 } else if (not m_decorrelation_model_name.empty() and
504 // case 7
505 ATH_MSG_FATAL("too many flags for the decorrelation model");
506 return StatusCode::FAILURE;
507 } else {
508 // set scale decorrelation model
509 if (not m_decorrelation_model_scale_name.empty()) { // case 4, 5, 6, (7)
510 if (not m_decorrelation_model_name.empty()) {
512 "flag decorrelation model ignored for scale decorrelation model");
513 } // case 5
514 if (m_decorrelation_model_scale_name == "1NP_v1")
515 m_decorrelation_model_scale = ScaleDecorrelation::ONENP;
516 else if (m_decorrelation_model_scale_name == "FULL_ETACORRELATED_v1")
517 m_decorrelation_model_scale = ScaleDecorrelation::FULL_ETA_CORRELATED;
518 else if (m_decorrelation_model_scale_name == "1NPCOR_PLUS_UNCOR")
519 m_decorrelation_model_scale = ScaleDecorrelation::ONENP_PLUS_UNCONR;
520 else if (m_decorrelation_model_scale_name == "FULL_v1")
521 m_decorrelation_model_scale = ScaleDecorrelation::FULL;
522 else {
523 ATH_MSG_FATAL("cannot understand the scale decorrelation model '"
524 << m_decorrelation_model_scale_name << "'(typo?)");
525 return StatusCode::FAILURE;
526 }
527 } else if (not m_decorrelation_model_name.empty()) { // case 1, 3
528 if (m_decorrelation_model_name == "1NP_v1")
529 m_decorrelation_model_scale = ScaleDecorrelation::ONENP;
530 else if (m_decorrelation_model_name == "FULL_ETACORRELATED_v1")
531 m_decorrelation_model_scale = ScaleDecorrelation::FULL_ETA_CORRELATED;
532 else if (m_decorrelation_model_name == "1NPCOR_PLUS_UNCOR")
533 m_decorrelation_model_scale = ScaleDecorrelation::ONENP_PLUS_UNCONR;
534 else if (m_decorrelation_model_name == "FULL_v1")
535 m_decorrelation_model_scale = ScaleDecorrelation::FULL;
536 else {
537 ATH_MSG_FATAL("cannot understand the decorrelation model '"
538 << m_decorrelation_model_name << "'(typo?)");
539 return StatusCode::FAILURE;
540 }
541 } else { // case 2, (7)
543 "not information how to initialize the scale decorrelation model");
544 return StatusCode::FAILURE;
545 }
546
547 // set resolution decorralation model
549 .empty()) { // case 2, 3, 6, (7)
550 if (not m_decorrelation_model_name.empty()) {
552 "flag decorrelation model ignored for resolution decorrelation "
553 "model");
554 } // case 3
557 else if (m_decorrelation_model_resolution_name == "FULL_v1")
559 else {
560 ATH_MSG_FATAL("cannot understand the resolution decorrelation model '"
562 return StatusCode::FAILURE;
563 }
564 } else if (not m_decorrelation_model_name.empty()) { // case 1, 5
565 if (m_decorrelation_model_name == "1NP_v1")
567 else if (m_decorrelation_model_name == "FULL_ETACORRELATED_v1")
569 else if (m_decorrelation_model_name == "1NPCOR_PLUS_UNCOR")
571 else if (m_decorrelation_model_name == "FULL_v1")
573 else {
574 ATH_MSG_FATAL("cannot understand the decorrelation model '"
575 << m_decorrelation_model_name << "'(typo?)");
576 return StatusCode::FAILURE;
577 }
578 }
579 }
580
581 // create correction tool
582 ATH_MSG_DEBUG("creating internal correction tool");
583 m_rootTool = std::make_unique<AtlasRoot::egammaEnergyCorrectionTool>();
584 if (!m_rootTool) {
585 ATH_MSG_ERROR("Cannot initialize underlying tool");
586 return StatusCode::FAILURE;
587 }
588 m_rootTool->setESModel(m_TESModel);
589
595 "Using linear interpolation in the gain tool (uncertainties only)");
597 m_rootTool->setApplyL2GainInterpolation();
598 }
599 m_rootTool->msg().setLevel(this->msg().level());
600 m_rootTool->initialize();
601
602 // configure MVA calibration
603 if (m_use_mva_calibration != 0) {
604 ATH_MSG_DEBUG("creating MVA calibration tool (if needed)");
605 if (m_MVAfolder.empty()) { // automatically configure MVA tool
607 }
608
609 if (not m_MVAfolder.empty()) {
610
611 // electron MVA tool
612 asg::AsgToolConfig config_mva_electron(
613 "egammaMVACalibTool/tool_mva_electron");
614 config_mva_electron.setPropertyFromString("folder", m_MVAfolder);
615 ATH_CHECK(config_mva_electron.setProperty("use_layer_corrected", true));
616 ATH_CHECK(config_mva_electron.setProperty(
617 "ParticleType", xAOD::EgammaParameters::electron));
618
619 // unconverted photon MVA tool
620 asg::AsgToolConfig config_mva_unconverted(
621 "egammaMVACalibTool/tool_mva_unconverted");
622 config_mva_unconverted.setPropertyFromString("folder", m_MVAfolder);
623 ATH_CHECK(
624 config_mva_unconverted.setProperty("use_layer_corrected", true));
625 ATH_CHECK(config_mva_unconverted.setProperty(
627 ATH_CHECK(config_mva_unconverted.setProperty("OutputLevel",
628 this->msg().level()));
629
630 // converted photon MVA tool
631 asg::AsgToolConfig config_mva_converted(
632 "egammaMVACalibTool/tool_mva_converted");
633 config_mva_converted.setPropertyFromString("folder", m_MVAfolder);
634 ATH_CHECK(config_mva_converted.setProperty("use_layer_corrected", true));
635 ATH_CHECK(config_mva_converted.setProperty(
637 ATH_CHECK(config_mva_converted.setProperty("OutputLevel",
638 this->msg().level()));
639
640 // initialize the ServiceHandler egammaMVASvc
641 // make the name unique
642 std::ostringstream mva_service_name;
643 mva_service_name << "egammaMVASvc/service_mva_egamma_id"
644 << (void const*)this;
645 asg::AsgServiceConfig config_mva_service(mva_service_name.str());
646 ATH_CHECK(config_mva_service.addPrivateTool("ElectronTool",
647 config_mva_electron));
648 ATH_CHECK(config_mva_service.addPrivateTool("UnconvertedPhotonTool",
649 config_mva_unconverted));
650 ATH_CHECK(config_mva_service.addPrivateTool("ConvertedPhotonTool",
651 config_mva_converted));
652 // fwd electron MVA tool
653 if (m_doFwdCalib) {
654 asg::AsgToolConfig config_mva_fwdelectron(
655 "egammaMVACalibTool/tool_mva_fwdelectron");
656 config_mva_fwdelectron.setPropertyFromString("folder", m_MVAfolder);
657 ATH_CHECK(config_mva_fwdelectron.setProperty(
659 ATH_CHECK(config_mva_fwdelectron.setProperty("ShiftType", 0));
660 ATH_CHECK(config_mva_fwdelectron.setProperty("OutputLevel", this->msg().level()));
661 ATH_CHECK(config_mva_service.addPrivateTool("FwdElectronTool",
662 config_mva_fwdelectron));
663 }
664 config_mva_service.setPropertyFromString("folder", m_MVAfolder);
665 ATH_CHECK(
666 config_mva_service.setProperty("OutputLevel", this->msg().level()));
667 ATH_CHECK(config_mva_service.makeService(m_MVACalibSvc));
670 "WIP: testing GNN based calibration for Run3,"
671 "requring decorated GNN energy (gnn_energy) from input,"
672 "which should already have the layer calibration applied");
673 } else {
674 m_use_mva_calibration = false;
675 }
676 }
677
678 // configure layer recalibration tool
679 // For now: layer recalibration not applied to PRE release 21 (using run 1
680 // based calibration applied at reco level)
681 // for following R21 recommendations, need to apply the run2/run1 layer
682 // calibration ratio
683 if (m_ESModel == "es2017_R21_PRE") {
684 ATH_MSG_INFO("Layer recalibration already applied at cell level");
685 m_useLayerCorrection = false;
686 } else if (!m_useLayerCorrection) {
687 ATH_MSG_INFO("Layer corrections disabled!");
688 } else {
689 ATH_MSG_DEBUG("initializing layer recalibration tool (if needed)");
691 .empty()) { // automatically configure layer recalibration tool
694 .release();
696 ATH_MSG_INFO("not using layer recalibration");
697 }
698 } else {
701 }
703 m_layer_recalibration_tool->msg().setLevel(this->msg().level());
705 if (!m_usePSCorrection) {
706 ATH_MSG_INFO("PS corrections disabled!");
707 m_layer_recalibration_tool->disable_PSCorrections();
708 }
709 if (!m_useS12Correction) {
710 ATH_MSG_INFO("S12 corrections disabled!");
711 m_layer_recalibration_tool->disable_S12Corrections();
712 }
713 if (!m_useSaccCorrection) {
714 ATH_MSG_INFO("Sacc corrections disabled!");
715 m_layer_recalibration_tool->disable_SaccCorrections();
716 }
717 }
718 }
719
721 m_rootTool->use_temp_correction201215(m_use_temp_correction201215);
723 m_rootTool->use_uA2MeV_2015_first2weeks_correction(
726 m_decorrelation_model_scale == ScaleDecorrelation::FULL) {
727 m_rootTool->useStatErrorScaling(true);
728 }
729
731 ATH_MSG_ERROR("ep combination not supported yet");
732 throw std::runtime_error("ep combination not supported yet");
733 }
734
737 }
740 }
742
743 if (m_useGainCorrection == AUTO) {
748 }
749 else {
750 ATH_MSG_DEBUG("initializing gain tool");
753 }
754 }
755 else if (m_useGainCorrection == 1) {
761 "cannot instantiate gain tool for this model (you can only disable "
762 "the gain tool, but not enable it)");
763 }
764 else {
766 "initializing gain tool for run2 final precision recommendations");
768 "Gain corrections required but Zee scales are derived without Gain, "
769 "will cause inconsistency!");
770 std::string gain_tool_run_2_filename = PathResolverFindCalibFile(
771 "ElectronPhotonFourMomentumCorrection/v29/"
772 "gain_uncertainty_specialRun.root");
773 m_gain_tool_run2 = std::make_unique<egGain::GainUncertainty>(
774 gain_tool_run_2_filename, false, "GainCorrection",
776 m_gain_tool_run2->msg().setLevel(this->msg().level());
777 }
778 }
779
784 // ADC non linearity correction
787 std::string adcLinearityCorr_filename = PathResolverFindCalibFile(
788 "ElectronPhotonFourMomentumCorrection/v25/linearity_ADC.root");
789 m_ADCLinearity_tool = std::make_shared<LinearityADC>(adcLinearityCorr_filename);
790 m_ADCLinearity_tool->msg().setLevel(this->msg().level());
791 m_rootTool->setADCTool(m_ADCLinearity_tool);
792 } else {
794 m_ESModel + " recommendations use ADC corrections for scale "
795 "derivation. Disabling the ADCLinearity flag will create "
796 "inconsistency!");
797 }
798
801 m_rootTool->setApplyLeakageCorrection(true);
802 }
803
804 // Calo distortion phi unif correction
808 std::string phiUnifCorrfileName = PathResolverFindCalibFile(
809 "ElectronPhotonFourMomentumCorrection/v33/"
810 "egammaEnergyCorrectionData.root");
811 std::unique_ptr<TFile> fCorr(
812 TFile::Open(phiUnifCorrfileName.c_str(), "READ"));
814 dynamic_cast<TH2*>(fCorr->Get("CaloDistortionPhiUniformityCorrection/"
815 "es2023_R22_Run2_v0/h2DcorrPhiUnif")));
816 m_caloDistPhiUnifCorr->SetDirectory(nullptr);
817 } else {
819 m_ESModel + " recommendations use CaloDistPhiUnif for scale "
820 "derivation. Disabling the CaloDistPhiUnif flag will create "
821 "inconsistency!");
822 }
823 }
824
825 // No scale correction for release 21 ==> obsolete
826 /*if (m_ESModel == "es2017_R21_PRE"){
827 m_doScaleCorrection = 0;
828 }
829 */
830
831 ATH_MSG_INFO("ESModel: " << m_ESModel);
832 ATH_MSG_INFO("ResolutionType: " << m_ResolutionType);
833 ATH_MSG_INFO("decorrelation Model: " << m_decorrelation_model_name);
834 ATH_MSG_DEBUG("layer correction = " << m_useLayerCorrection);
835 ATH_MSG_DEBUG("PS correction = " << m_usePSCorrection);
836 ATH_MSG_DEBUG("S12 correction = " << m_useS12Correction);
837 ATH_MSG_DEBUG("Sacc correction = " << m_useSaccCorrection);
838 ATH_MSG_DEBUG("intermodule correction = " << m_useIntermoduleCorrection);
839 ATH_MSG_DEBUG("phi uniformity correction = " << m_usePhiUniformCorrection);
840 ATH_MSG_DEBUG("distorted calo phi uniformity correction = "
842 ATH_MSG_DEBUG("gain correction = " << m_useGainCorrection);
843 ATH_MSG_DEBUG("ADC non-linearity correction = " << m_doADCLinearityCorrection);
844 ATH_MSG_DEBUG("leakage correction for photons = " << m_doLeakageCorrection);
845 ATH_MSG_DEBUG("smearing = " << m_doSmearing);
846 ATH_MSG_DEBUG("insitu scales = " << m_doScaleCorrection);
847 ATH_MSG_DEBUG("ep combination = " << m_use_ep_combination);
848 ATH_MSG_DEBUG("use MVA calibration = " << m_use_mva_calibration);
850 "use temperature correction 2015 = " << m_use_temp_correction201215);
851 ATH_MSG_DEBUG("use uA2MeV correction 2015 1/2 week = "
853
855
857 .ignore(); // this set the flags for the internal tool without
858 // systematics
860 if (registry.registerSystematics(*this) != StatusCode::SUCCESS)
861 return StatusCode::FAILURE;
862
863 // For columnar, it is important only to set this accessor if it is
864 // needed, as it creates a hard data dependency on the column, which
865 // is not present in older PHYSLITE files, causing the tool to fail.
866 // An alternative would be to mark the column with `isOptional`, but
867 // since it is always required for the GNN calibration (and never
868 // otherwise), declaring it only for the GNN calibration seemed
869 // cleaner.
871 resetAccessor (m_accessors->gnn_energy_Acc, *this, "TransformerEnergy");
872 }
873 if (m_onlyElectrons.value() && m_onlyPhotons.value()) {
874 ATH_MSG_ERROR("Cannot select both onlyElectrons and onlyPhotons");
875 return StatusCode::FAILURE;
876 }
877 if (m_onlyElectrons.value()) {
878 resetElectron (m_accessors->momAcc, *m_accessors);
880 resetAccessor (m_accessors->electronTrackAcc, *this, "trackParticleLinks");
881 }
882 }
883 if (m_onlyPhotons.value()) {
884 resetPhoton (m_accessors->momAcc, *m_accessors);
885 resetAccessor (m_accessors->photonVertexAcc, *this, "vertexLinks");
886 }
887 if (m_decorateEmva)
888 resetAccessor (m_accessors->decEmva, *this, "E_mva_only");
889
890 ANA_CHECK (initializeColumns ());
891
892 return StatusCode::SUCCESS;
893}
894
895
897{
898 const Accessors& acc = *m_accessors;
899
900 // this is departing from the logic below, as we are now requiring the
901 // user to specify at configuration time whether we run on electrons
902 // or photons. this is necessary to configure the columns we need
903 // correctly.
904 if (m_onlyElectrons.value())
905 {
907 }
908 if (m_onlyPhotons.value())
909 {
910 if (acc.photonVertexAcc(particle).size() > 0)
911 {
913 }
914 else
915 {
917 }
918 }
919
920 // this is the old logic and should not be visited in columnar mode
921 // (disabled by turning on onlyElectrons or onlyPhotons)
923 //no ForwardElectron ptype: consider them as Electron
924 if (xAOD::EgammaHelpers::isElectron(&particle.getXAODObject()) || acc.authorAcc (particle) == xAOD::EgammaParameters::AuthorFwdElectron) { ptype = PATCore::ParticleType::Electron; }
925 else if (xAOD::EgammaHelpers::isPhoton(&particle.getXAODObject())) {
926 if (xAOD::EgammaHelpers::isConvertedPhoton(&particle.getXAODObject())) { ptype = PATCore::ParticleType::ConvertedPhoton; }
928 }
929 else {
930 ATH_MSG_ERROR("particle is not electron of photon");
931 throw std::runtime_error("particle is not electron or photon");
932 }
933 return ptype;
934}
935
937 const xAOD::Egamma& particle, bool withCT) const {
938 const auto ptype = xAOD2ptype(particle);
939 const auto cl_etaCalo =
940 xAOD::get_eta_calo(*particle.caloCluster(), particle.author());
941
942 return m_rootTool->resolution(particle.e(), particle.caloCluster()->eta(),
943 cl_etaCalo, ptype, withCT,
944 false); // TODO: always for full simulation
945}
946
948 double energy, double cl_eta, double cl_etaCalo,
949 PATCore::ParticleType::Type ptype, bool withCT) const {
950 return m_rootTool->resolution(energy, cl_eta, cl_etaCalo, ptype, withCT,
951 false);
952}
953
955 xAOD::Egamma& input) const {
956 // Retrieve the event information:
957 const xAOD::EventInfo* event_info = nullptr;
958 if (evtStore()->retrieve(event_info, "EventInfo").isFailure()) {
959 ATH_MSG_ERROR("No EventInfo object could be retrieved");
961 }
962 return applyCorrection(input, *event_info);
963}
964
966 const xAOD::Electron& input, xAOD::Electron*& output) const {
967 // A sanity check:
968 if (output)
970 "Non-null pointer received. "
971 "There's a possible memory leak!");
972
973 output = new xAOD::Electron();
974 output->makePrivateStore(input);
975 return applyCorrection(*output);
976}
977
979 const xAOD::Photon& input, xAOD::Photon*& output) const {
980 // A sanity check:
981 if (output)
983 "Non-null pointer received. "
984 "There's a possible memory leak!");
985
986 output = new xAOD::Photon();
987 output->makePrivateStore(input);
988 return applyCorrection(*output);
989}
990
992 const xAOD::Photon& input) const {
993 xAOD::Photon* new_particle = nullptr;
994 ANA_CHECK_THROW(correctedCopy(input, new_particle));
995 const double e = new_particle->e();
996 delete new_particle;
997 return e;
998}
999
1001 const xAOD::Electron& input) const {
1002 xAOD::Electron* new_particle = nullptr;
1003 ANA_CHECK_THROW(correctedCopy(input, new_particle));
1004 const double e = new_particle->e();
1005 delete new_particle;
1006 return e;
1007}
1008
1010 columnar::MutableEgammaId input, columnar::EventInfoId event_info) const {
1011 const Accessors& acc = *m_accessors;
1012
1013 // only used in simulation (for the smearing)
1014 RandomNumber seed = m_set_seed_function(*this, input, event_info);
1015
1016 columnar::ClusterId inputCluster = acc.caloClusterAcc (input)[0].value();
1017
1018 if (m_layer_recalibration_tool && acc.authorAcc (input) !=
1020 ATH_MSG_DEBUG("applying energy recalibration before E0|E1|E2|E3 = "
1021 << acc.energyBEAcc (inputCluster, 0) << "|"
1022 << acc.energyBEAcc (inputCluster, 1) << "|"
1023 << acc.energyBEAcc (inputCluster, 2) << "|"
1024 << acc.energyBEAcc (inputCluster, 3));
1025 // for now just go back to the xAOD object to access the subtool
1026 const CP::CorrectionCode status_layer_recalibration = m_layer_recalibration_tool->applyCorrection(input.getXAODObject(), event_info.getXAODObject());
1027 if (status_layer_recalibration == CP::CorrectionCode::Error) { return CP::CorrectionCode::Error; }
1028 ATH_MSG_DEBUG("eta|phi = " << acc.etaAcc (input) << "|" << acc.phiAcc (input));
1029 if (status_layer_recalibration == CP::CorrectionCode::Ok) {
1030 ATH_MSG_DEBUG("decoration E0|E1|E2|E3 = "
1031 << acc.Es0Acc(inputCluster) << "|"
1032 << acc.Es1Acc(inputCluster) << "|"
1033 << acc.Es2Acc(inputCluster) << "|"
1034 << acc.Es3Acc(inputCluster) << "|");
1035 if (acc.Es2Acc(inputCluster) == 0 and acc.Es1Acc(inputCluster) == 0 and
1036 acc.Es3Acc(inputCluster) == 0 and acc.Es0Acc(inputCluster) == 0 and
1037 (std::abs(acc.etaAcc (input)) < 1.37 or (std::abs(acc.etaAcc (input)) > 1.55 and std::abs(acc.etaAcc (input)) < 2.47)))
1038 {
1039 ATH_MSG_WARNING("all layer energies are zero");
1040 }
1041 }
1042 }
1043
1044 double energy = acc.momAcc.e (input);
1045 // apply MVA calibration
1046 if (!m_MVACalibSvc.empty()) {
1048 if (acc.authorAcc (input) ==
1050 const xAOD::VertexContainer* pVtxCont = nullptr;
1051 if (evtStore()->retrieve(pVtxCont, m_pVtxKey).isFailure()) {
1052 ATH_MSG_ERROR("No primary vertex container " << m_pVtxKey << " could be retrieved");
1054 }
1055 unsigned int npv(0);
1056 for (const auto *vtx : *pVtxCont) {
1057 if (vtx->vertexType() == xAOD::VxType::PriVtx ||
1058 vtx->vertexType() == xAOD::VxType::PileUp) { ++npv; }
1059 }
1060 gei.nPV = npv;
1061 gei.acmu = acc.actIntPerXingAcc(event_info);
1062 ATH_MSG_DEBUG("Retrieved nPV = " << gei.nPV << " and mu = " << gei.acmu);
1063 }
1064 if (acc.authorAcc (input) !=
1066 if (m_MVACalibSvc->getEnergy(inputCluster.getXAODObject(), input.getXAODObject(), energy, gei)
1067 .isFailure()) {
1068 ATH_MSG_ERROR("Failure in MVACalib service");
1070 }
1071 ATH_MSG_DEBUG("energy after MVA calibration = " << std::format("{:.2f}", energy));
1072 }
1073 }
1075 // for now assume the input has already the layer calibration applied
1076 // and just take the decorated gnn_energy
1077 if (!acc.gnn_energy_Acc.isAvailable(input)) {
1078 ATH_MSG_ERROR("GNN energy requested but decoration TransformerEnergy not found");
1080 }
1081 energy = acc.gnn_energy_Acc(input);
1082 ATH_MSG_DEBUG("energy after GNN calibration = " << std::format("{:.2f}", energy));
1083
1084 }
1085 if (m_decorateEmva)
1086 {
1087 acc.decEmva(input) = energy;
1088 }
1089
1090 // For the time being, it is just the MVA calib
1091 if (acc.authorAcc (input) ==
1093 setPt(input, energy);
1095 }
1096
1098 // Crack calibation correction for es2011c (calibration hits calibration)
1099 const auto ptype = xAOD2ptype(input);
1100 const double etaden =
1102 ? static_cast<const xAOD::Electron&>(input.getXAODObject()).trackParticle()->eta()
1103 : acc.clusterEtaAcc(inputCluster);
1104 energy *= m_rootTool->applyMCCalibration(acc.clusterEtaAcc(inputCluster),
1105 energy / cosh(etaden), ptype);
1106 ATH_MSG_DEBUG("energy after crack calibration es2011c = "
1107 << std::format("{:.2f}", energy));
1108 }
1109
1110 /*
1111 * Here we check for each event the kind of data DATA vs FullSim
1112 * The m_simulation flavour has already been configured
1113 */
1115 (acc.eventTypeAcc(event_info,xAOD::EventInfo::IS_SIMULATION))
1116 ? m_simulation
1118
1119 unsigned int runNumber_for_tool = 0;
1120
1121 // apply uniformity corrections to data
1122 if (dataType == PATCore::ParticleDataType::Data) {
1123 // Get run number
1124 runNumber_for_tool = acc.runNumberAcc(event_info);
1125 // Get etaCalo, phiCalo
1126 const auto cl_eta = acc.clusterEtaAcc(inputCluster);
1127 double etaCalo = 0, phiCalo = 0;
1129 etaCalo = acc.etaCaloAcc(inputCluster, acc.authorAcc(input), false);
1131 phiCalo =
1132 acc.phiCaloAcc(inputCluster, acc.authorAcc(input), false);
1133 }
1134 }
1135
1136 // Intermodule
1138 energy =
1139 intermodule_correction(energy, acc.clusterPhiAcc(inputCluster), cl_eta);
1140 ATH_MSG_DEBUG("energy after intermodule correction = "
1141 << std::format("{:.2f}", energy));
1142 }
1143
1144 // Calo distortion
1150 double etaC = acc.clusterEtaAcc(inputCluster);
1151 double phiC = acc.clusterPhiAcc(inputCluster);
1152 int ieta = m_caloDistPhiUnifCorr->GetXaxis()->FindBin(etaC);
1153 ieta = ieta == 0 ? 1
1154 : (ieta > m_caloDistPhiUnifCorr->GetNbinsX()
1155 ? m_caloDistPhiUnifCorr->GetNbinsX()
1156 : ieta);
1157 int iphi = m_caloDistPhiUnifCorr->GetYaxis()->FindBin(phiC);
1158 iphi = iphi == 0 ? 1
1159 : (iphi > m_caloDistPhiUnifCorr->GetNbinsY()
1160 ? m_caloDistPhiUnifCorr->GetNbinsY()
1161 : iphi);
1162 energy *= m_caloDistPhiUnifCorr->GetBinContent(ieta, iphi);
1164 "energy after phi uniformity correction (for calo distortion) = "
1165 << std::format("{:.2f}", energy));
1166 }
1167
1168 // Phi
1170 energy *= correction_phi_unif(etaCalo, phiCalo);
1171 ATH_MSG_DEBUG("energy after uniformity correction = "
1172 << std::format("{:.2f}", energy));
1173 }
1174
1175 // ADC
1176 if (m_ADCLinearity_tool) {
1177 double et = energy / std::cosh(cl_eta);
1178 double corr =
1179 m_ADCLinearity_tool->getCorr(etaCalo, et, xAOD2ptype(input));
1180 energy *= corr;
1181 ATH_MSG_DEBUG("energy after ADC linearity correction = "
1182 << std::format("{:.2f}", energy));
1183 }
1184
1185 // Gain
1186 if (m_gain_tool) {
1187 const auto es2 = acc.Es2Acc.isAvailable(inputCluster)
1188 ? acc.Es2Acc(inputCluster)
1189 : acc.energyBEAcc (inputCluster,2);
1190 if (!(std::abs(cl_eta) < 1.52 and std::abs(cl_eta) > 1.37) and
1191 std::abs(cl_eta) < 2.4)
1192 energy = m_gain_tool->CorrectionGainTool(
1193 cl_eta, energy / GeV, es2 / GeV,
1194 xAOD2ptype(input)); // cl_eta ok, TODO: check corrected E2
1195 } else if (m_gain_tool_run2) {
1196 double et = energy / std::cosh(cl_eta);
1197 double corr = m_gain_tool_run2->getUncertainty(etaCalo, et,
1198 xAOD2ptype(input), true);
1199 energy /= (1 + corr);
1200 }
1201 ATH_MSG_DEBUG("energy after gain correction = " << std::format("{:.2f}", energy));
1202 } else {
1203 if (m_user_random_run_number == 0) {
1204 if (acc.randomrunnumber_getter.isAvailable(event_info)) {
1205 runNumber_for_tool = acc.randomrunnumber_getter(event_info);
1206 } else {
1208 "Pileup tool not run before using "
1209 "ElectronPhotonFourMomentumCorrection! Assuming it is 2016. If you "
1210 "want to force a specific period set the property randomRunNumber "
1211 "of the tool, e.g. in the job option: "
1212 "tool.randomRunNumber = 123456 or "
1213 "tool.randomRunNumber = "
1214 "EgammaCalibrationAndSmearingToolRunNumbersExample.run_2016");
1216 }
1217 } else {
1218 runNumber_for_tool = m_user_random_run_number;
1219 }
1220 }
1221
1222 const double eraw = ((acc.Es0Acc.isAvailable(inputCluster)
1223 ? acc.Es0Acc(inputCluster)
1224 : acc.energyBEAcc(inputCluster,0)) +
1225 (acc.Es1Acc.isAvailable(inputCluster)
1226 ? acc.Es1Acc(inputCluster)
1227 : acc.energyBEAcc(inputCluster,1)) +
1228 (acc.Es2Acc.isAvailable(inputCluster)
1229 ? acc.Es2Acc(inputCluster)
1230 : acc.energyBEAcc(inputCluster,2)) +
1231 (acc.Es3Acc.isAvailable(inputCluster)
1232 ? acc.Es3Acc(inputCluster)
1233 : acc.energyBEAcc(inputCluster,3)));
1234
1235
1236 if (dataType == PATCore::ParticleDataType::Fast)
1237 ATH_MSG_DEBUG("is fast");
1238 else if (dataType == PATCore::ParticleDataType::Full)
1239 ATH_MSG_DEBUG("is full");
1240 else if (dataType == PATCore::ParticleDataType::Data)
1241 ATH_MSG_DEBUG("is data");
1242
1243 // apply scale factors or systematics
1244 energy = m_rootTool->getCorrectedEnergy(
1245 runNumber_for_tool, dataType, xAOD2ptype(input),
1246 inputCluster(acc.clusterEtaAcc),
1247 inputCluster(acc.clusterEtaBEAcc,2),
1248 acc.etaCaloAcc(inputCluster, acc.authorAcc (input), false), energy,
1249 acc.Es2Acc.isAvailable(inputCluster)
1250 ? acc.Es2Acc(inputCluster)
1251 : inputCluster(acc.energyBEAcc,2),
1252 eraw, seed, oldtool_scale_flag_this_event(input, event_info),
1254 m_varSF);
1255
1256 ATH_MSG_DEBUG("energy after scale/systematic correction = " << std::format("{:.2f}", energy));
1257
1258 // TODO: this check should be done before systematics variations
1259 setPt(input, energy);
1261}
1262
1264 const double new_energy2 = energy * energy;
1265 const double m = m_accessors->momAcc.m (input);
1266 const double m2 = m * m;
1267 const double p2 = new_energy2 > m2 ? new_energy2 - m2 : 0.;
1268 m_accessors->ptOutDec (input) = sqrt(p2) / cosh(m_accessors->etaAcc (input));
1269 ATH_MSG_DEBUG("after setting pt, energy = " << m_accessors->momAcc.e (input));
1270}
1271
1273 xAOD::Egamma* p, const xAOD::EventInfo* event_info) {
1274 ANA_CHECK_THROW(applyCorrection(*p, *event_info));
1275 ATH_MSG_DEBUG("returning " << p->e());
1276 return p->e();
1277}
1278
1290
1299
1301 const xAOD::Electron* el, const xAOD::EventInfo* event_info) {
1304 ? m_simulation
1306
1307 const xAOD::TrackParticle* eTrack = el->trackParticle();
1308
1309 // track momentum and eta
1310 const float el_tracketa = eTrack->eta();
1311 const float el_trackmomentum = eTrack->pt() * cosh(el->eta());
1312
1313 return m_rootTool->getCorrectedMomentum(
1314 dataType, PATCore::ParticleType::Electron, el_trackmomentum, el_tracketa,
1315 oldtool_scale_flag_this_event(*el, *event_info), m_varSF);
1316}
1317
1319 const CP::SystematicVariation& systematic) const {
1321 return sys.find(systematic) != sys.end();
1322}
1323
1325 const {
1326 CP::SystematicSet affecting_systematics;
1327 for (const auto& it : m_syst_description) {
1328 affecting_systematics.insert(it.first);
1329 }
1330 for (const auto& it : m_syst_description_resolution) {
1331 affecting_systematics.insert(it.first);
1332 }
1333
1334 return affecting_systematics;
1335}
1336
1338 const EgammaPredicate always = [](const EgammaCalibrationAndSmearingTool&, columnar::EgammaId) { return true; };
1339
1340 // Try to simplify a bit for the ones that are fully correlate in eta,
1341 // whatever the model and that are not included in the macros including
1342 // - ADC non linearity
1343 // - L2Gain
1344 // - Leakage
1345 // - Conversion related
1346 // - TopoCluster threshold
1347 // - AF2
1348 // - PS_BARREL_B12
1349 // - S12EXTRALASTETABINRUN2
1350 // - ZEESTAT
1351 // - Run3 pre OFC + EXTRA
1352 if (m_decorrelation_model_scale == ScaleDecorrelation::FULL_ETA_CORRELATED ||
1353 m_decorrelation_model_scale == ScaleDecorrelation::FULL) {
1354 // Electron leakage, ADCLin, convReco only in final run2 recommendations
1358 // systematic related to ADC non linearity correction. Before 2022, there
1359 // was not correction, nor related systematic
1361 m_syst_description[CP::SystematicVariation("EG_SCALE_ADCLIN", +1)] =
1363 m_syst_description[CP::SystematicVariation("EG_SCALE_ADCLIN", -1)] =
1365 }
1366 // Gain splitted uncertainty
1367 m_syst_description[CP::SystematicVariation("EG_SCALE_L2MEDIUMGAIN", +1)] =
1369 m_syst_description[CP::SystematicVariation("EG_SCALE_L2MEDIUMGAIN", -1)] =
1371 m_syst_description[CP::SystematicVariation("EG_SCALE_L2LOWGAIN", +1)] =
1373 m_syst_description[CP::SystematicVariation("EG_SCALE_L2LOWGAIN", -1)] =
1375
1376 // Electron leakage
1377 m_syst_description[CP::SystematicVariation("EG_SCALE_LEAKAGEELEC", +1)] =
1379 m_syst_description[CP::SystematicVariation("EG_SCALE_LEAKAGEELEC", -1)] =
1381
1382 // Conversion related
1383 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVRECO", +1)] =
1385 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVRECO", -1)] =
1387 }
1388 // The equivalent of convReco (convefficiency and convfakerate) for other
1389 // models
1390 else {
1391 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVEFFICIENCY",
1392 +1)] =
1394 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVEFFICIENCY",
1395 -1)] =
1397 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVFAKERATE", +1)] =
1399 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVFAKERATE", -1)] =
1401 }
1402
1403 // additional systematics for R22 OFC and MC21 pre and bulk
1405 m_syst_description[CP::SystematicVariation("EG_SCALE_OFC", +1)] =
1407 m_syst_description[CP::SystematicVariation("EG_SCALE_OFC", -1)] =
1409
1410 m_syst_description[CP::SystematicVariation("EG_SCALE_EXTRARUN3PRE", +1)] =
1412 m_syst_description[CP::SystematicVariation("EG_SCALE_EXTRARUN3PRE", -1)] =
1414 }
1415
1426
1427 // topo clustr threshold systematics aded to release 21 recommendations
1428 m_syst_description[CP::SystematicVariation("EG_SCALE_TOPOCLUSTER_THRES",
1429 +1)] =
1431 m_syst_description[CP::SystematicVariation("EG_SCALE_TOPOCLUSTER_THRES",
1432 -1)] =
1434
1435 // AF3 for run3 models: es2022_R22_PRE and esmodel >= es2023_R22_Run2_v1
1436 // although we prevent AF for es2022_R22_PRE and es2024_Run3_ofc0_v0
1437 // AF3 are still technically added in the tool
1438 // but normally uncertainty will be 0
1440 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", +1)] =
1442 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", -1)] =
1444 }
1445 else {
1446 // and extra AF2 systematics for release 21 recommendations - Moriond 2018
1447 // - pending proper AF2 to FullSim correction with release 21
1448 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", +1)] =
1450 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", -1)] =
1452 }
1453 }
1454
1455 // PS correlated barrel uncertainty
1464 m_syst_description[CP::SystematicVariation("EG_SCALE_PS_BARREL_B12",
1465 +1)] =
1467 m_syst_description[CP::SystematicVariation("EG_SCALE_PS_BARREL_B12",
1468 -1)] =
1470 }
1471
1472 // additional systematic for S12 last eta bin run2
1478 "EG_SCALE_S12EXTRALASTETABINRUN2", +1)] =
1481 "EG_SCALE_S12EXTRALASTETABINRUN2", -1)] =
1483 }
1484
1485 // Zee stat, if for FULL we do not ask for m_use_full_statistical_error
1487 ScaleDecorrelation::FULL_ETA_CORRELATED or
1489 // return 1 variation only, fully correlated in eta, equal to the correct
1490 // value but scaled by sqrt(number of bins) the scaling is done by the old
1491 // tool
1492 m_syst_description[CP::SystematicVariation("EG_SCALE_ZEESTAT", +1)] =
1494 m_syst_description[CP::SystematicVariation("EG_SCALE_ZEESTAT", -1)] =
1496 }
1497 }
1498 if (m_decorrelation_model_scale == ScaleDecorrelation::ONENP) {
1499 // TODO: independet implementation of ALL UP looping on all the variations
1500 m_syst_description[CP::SystematicVariation("EG_SCALE_ALL", +1)] =
1502 m_syst_description[CP::SystematicVariation("EG_SCALE_ALL", -1)] =
1504
1505 // to be consistent with other schemes, we add
1506 // extra AF systematics in addition to the 1NP
1513 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", +1)] =
1515 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", -1)] =
1517 }
1519 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", +1)] =
1521 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", -1)] =
1523 }
1524 }
1525 else if (m_decorrelation_model_scale ==
1526 ScaleDecorrelation::FULL_ETA_CORRELATED) {
1527// all the physical effects separately, considered as fully correlated in eta
1529#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1530 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1531 SysInfo{always, flagup}; \
1532 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1533 SysInfo{always, flagdown};
1534#include "ElectronPhotonFourMomentumCorrection/systematics_es2024_Run3_v0.def"
1535#undef SYSMACRO
1536 }
1537 else {
1538// common systematics for all the esmodels
1539#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1540 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1541 SysInfo{always, flagup}; \
1542 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1543 SysInfo{always, flagdown};
1544#include "ElectronPhotonFourMomentumCorrection/systematics_S12_2022.def"
1545#undef SYSMACRO
1546 }
1547
1551 m_syst_description[CP::SystematicVariation("EG_SCALE_LARCALIB", +1)] =
1553 m_syst_description[CP::SystematicVariation("EG_SCALE_LARCALIB", -1)] =
1555 m_syst_description[CP::SystematicVariation("EG_SCALE_L2GAIN", +1)] =
1557 m_syst_description[CP::SystematicVariation("EG_SCALE_L2GAIN", -1)] =
1559 }
1560
1561 // additional systematics for S12 run2
1572 "EG_SCALE_LARCALIB_EXTRA2015PRE", +1)] =
1575 "EG_SCALE_LARCALIB_EXTRA2015PRE", -1)] =
1577 }
1578
1579 // additional systematics for temperature run1->run2
1586 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE", +1)] =
1589 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE", -1)] =
1591 }
1592
1593 // additional systematic for temperature 2015->2016
1596 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE", +1)] =
1599 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE", -1)] =
1601 }
1602
1603 // additional systematic for PP0 region
1619 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0", +1)] =
1621 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0", -1)] =
1623 }
1624
1625 // systematic related to wtots1
1641 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", +1)] =
1643 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", -1)] =
1645 }
1646
1647 // systematic for the scintillators
1666 // scintillator systematics
1667 m_syst_description[CP::SystematicVariation("EG_SCALE_E4SCINTILLATOR",
1668 +1)] =
1670 m_syst_description[CP::SystematicVariation("EG_SCALE_E4SCINTILLATOR",
1671 -1)] =
1673 }
1674
1675 } else if (m_decorrelation_model_scale ==
1676 ScaleDecorrelation::ONENP_PLUS_UNCONR) {
1677// qsum of all variations correlated 8/13 TeV + uncorrelated (additional
1678// systematics for 2015PRE or 2016) all the physical effects separately,
1679// considered as fully correlated in eta
1680// TODO: fix for es2017
1681#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1682 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1683 SysInfo{always, flagup}; \
1684 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1685 SysInfo{always, flagdown};
1686#include "ElectronPhotonFourMomentumCorrection/systematics_1NPCOR_PLUS_UNCOR.def"
1687#undef SYSMACRO
1688
1689 // additional systematic for S12 last eta bin run2 - not needed anymore for
1690 // last 20.7 model since it is part of bin per bin E1/E2 uncertainty in root
1691 // file
1696 "EG_SCALE_S12EXTRALASTETABINRUN2", +1)] =
1699 "EG_SCALE_S12EXTRALASTETABINRUN2", -1)] =
1701 }
1702
1703 } else if (m_decorrelation_model_scale == ScaleDecorrelation::FULL) {
1704 using pairvector = std::vector<std::pair<double, double>>;
1705 const pairvector decorrelation_bins_BE = {{0., 1.45}, {1.52, 2.5}};
1706 const std::vector<double> decorrelation_edges_TWELVE = {
1707 0., 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4};
1708 std::vector<double> decorrelation_edges_MODULE = {
1709 0., 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.37, 1.52, 1.8};
1710 const std::vector<double> decorrelation_edges_MATERIAL = {0.0, 1.1, 1.5,
1711 2.1, 2.5};
1712 std::vector<double> decorrelation_edges_S12_EXTRARUN3 = {
1713 0., 0.8, 1.5, 2.5};
1714
1715 std::vector<double> decorrelation_edges_S12;
1716 // for es2018_R21_v1 : 4 eta bins for muon E1/E2 uncertainty correlation
1718 decorrelation_edges_S12.resize(5);
1719 decorrelation_edges_S12 = {0., 1.35, 1.5, 2.4, 2.5};
1723 decorrelation_edges_S12.resize(8);
1724 decorrelation_edges_S12 = {0., 0.6, 1.0, 1.35, 1.5, 1.8, 2.4, 2.5};
1725 //
1726 // PS scale from muons, so "crack" is a bit different
1727 decorrelation_edges_MODULE[7] = 1.4;
1728 decorrelation_edges_MODULE[8] = 1.5;
1729 }
1730 // for previous run 2 muon calibration with 20.7, 5 eta bins for E1/E2
1731 // uncertainty correlation
1732 else {
1733 decorrelation_edges_S12.resize(6);
1734 decorrelation_edges_S12 = {0., 0.6, 1.4, 1.5, 2.4, 2.5};
1735 }
1736
1748#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1749 if (bool(fullcorrelated)) { \
1750 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1751 SysInfo{always, flagup}; \
1752 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1753 SysInfo{always, flagdown}; \
1754 } else { \
1755 int i = 0; \
1756 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1757 m_syst_description[CP::SystematicVariation( \
1758 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1759 m_syst_description[CP::SystematicVariation( \
1760 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1761 i += 1; \
1762 } \
1763 }
1764#include "ElectronPhotonFourMomentumCorrection/systematics.def"
1765#undef SYSMACRO
1768#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1769 if (bool(fullcorrelated)) { \
1770 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1771 SysInfo{always, flagup}; \
1772 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1773 SysInfo{always, flagdown}; \
1774 } else { \
1775 int i = 0; \
1776 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1777 m_syst_description[CP::SystematicVariation( \
1778 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1779 m_syst_description[CP::SystematicVariation( \
1780 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1781 i += 1; \
1782 } \
1783 }
1784#include "ElectronPhotonFourMomentumCorrection/systematics_S12_2022.def"
1785#undef SYSMACRO
1787#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1788 if (bool(fullcorrelated)) { \
1789 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1790 SysInfo{always, flagup}; \
1791 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1792 SysInfo{always, flagdown}; \
1793 } else { \
1794 int i = 0; \
1795 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1796 m_syst_description[CP::SystematicVariation( \
1797 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1798 m_syst_description[CP::SystematicVariation( \
1799 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1800 i += 1; \
1801 } \
1802 }
1803#include "ElectronPhotonFourMomentumCorrection/systematics_es2024_Run3_v0.def"
1804#undef SYSMACRO
1805 } else {
1806#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1807 if (bool(fullcorrelated)) { \
1808 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1809 SysInfo{always, flagup}; \
1810 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1811 SysInfo{always, flagdown}; \
1812 } else { \
1813 int i = 0; \
1814 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1815 m_syst_description[CP::SystematicVariation( \
1816 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1817 m_syst_description[CP::SystematicVariation( \
1818 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1819 i += 1; \
1820 } \
1821 }
1822#include "ElectronPhotonFourMomentumCorrection/systematics_S12.def"
1823#undef SYSMACRO
1824 } // else
1825
1827 // statistical error, decorrelate in *all* the bins
1828 int i = 0;
1829 const TAxis& axis_statistical_error(m_rootTool->get_ZeeStat_eta_axis());
1830 for (int ibin = 1; ibin <= axis_statistical_error.GetNbins(); ++ibin) {
1831 auto p = EtaCaloPredicateFactory(
1832 axis_statistical_error.GetBinLowEdge(ibin),
1833 axis_statistical_error.GetBinLowEdge(ibin + 1));
1835 "EG_SCALE_ZEESTAT__ETABIN" + std::to_string(i), +1)] =
1838 "EG_SCALE_ZEESTAT__ETABIN" + std::to_string(i), -1)] =
1840 ++i;
1841 }
1842 }
1843
1844 // additional systematics for S12 run2
1855 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN0", +1)] =
1859 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN0", -1)] =
1863 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN1", +1)] =
1864 SysInfo{AbsEtaCaloPredicateFactory({1.45, 2.47}),
1867 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN1", -1)] =
1868 SysInfo{AbsEtaCaloPredicateFactory({1.45, 2.47}),
1871 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN2", +1)] =
1875 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN2", -1)] =
1878 }
1879
1880 // additional systematics for temperature run1->run2
1887 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN0", +1)] =
1888 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1891 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN0", -1)] =
1892 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1895 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN1", +1)] =
1896 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1899 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN1", -1)] =
1900 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1902 }
1903
1904 // additional systematic for temperature 2015->2016
1907 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN0", +1)] =
1908 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1911 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN1", +1)] =
1912 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1915 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN0", -1)] =
1916 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1919 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN1", -1)] =
1920 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1922 }
1923
1924 // additional systematic for PP0 region
1940 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN0",
1941 +1)] = SysInfo{
1943 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN1",
1944 +1)] = SysInfo{
1946 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN0",
1947 -1)] = SysInfo{
1949 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN1",
1950 -1)] =
1953 }
1954
1955 // systematic related to wtots1
1968 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", +1)] =
1970 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", -1)] =
1972 }
1973
1974 // systematic related to wtots1, decorrelate eta bin [1.52,1.82] from rest
1978 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN0",
1979 +1)] =
1980 SysInfo{DoubleOrAbsEtaCaloPredicate(0, 1.52, 1.82, 2.47),
1982 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN0",
1983 -1)] =
1984 SysInfo{DoubleOrAbsEtaCaloPredicate(0, 1.52, 1.82, 2.47),
1986 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN1",
1987 +1)] =
1988 SysInfo{AbsEtaCaloPredicateFactory({1.52, 1.82}),
1990 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN1",
1991 -1)] =
1992 SysInfo{AbsEtaCaloPredicateFactory({1.52, 1.82}),
1994 }
1995
1996 // systematic for the scintillators
2016 "EG_SCALE_E4SCINTILLATOR__ETABIN0", +1)] =
2020 "EG_SCALE_E4SCINTILLATOR__ETABIN1", +1)] =
2024 "EG_SCALE_E4SCINTILLATOR__ETABIN2", +1)] =
2028 "EG_SCALE_E4SCINTILLATOR__ETABIN0", -1)] =
2032 "EG_SCALE_E4SCINTILLATOR__ETABIN1", -1)] =
2036 "EG_SCALE_E4SCINTILLATOR__ETABIN2", -1)] =
2039 if (m_TESModel == egEnergyCorr::es2024_Run3_v0) { // extended E4 in Run 3
2041 "EG_SCALE_E4SCINTILLATOR__ETABIN3", +1)] =
2045 "EG_SCALE_E4SCINTILLATOR__ETABIN3", -1)] =
2048 }
2049 }
2050 } else {
2051 ATH_MSG_FATAL("scale decorrelation model invalid");
2052 }
2053
2054 // resolution systematics
2056 // ALL will not include AF2/AF3 systematic
2057 // individual AF NP is always provided
2058 // linghua.guo@cern.ch 2025-04-23
2060 "EG_RESOLUTION_ALL", +1)] = egEnergyCorr::Resolution::AllUp;
2062 "EG_RESOLUTION_ALL", -1)] = egEnergyCorr::Resolution::AllDown;
2066 "EG_RESOLUTION_ZSMEARING", +1)] = egEnergyCorr::Resolution::ZSmearingUp;
2068 "EG_RESOLUTION_ZSMEARING", -1)] =
2071 "EG_RESOLUTION_SAMPLINGTERM", +1)] =
2074 "EG_RESOLUTION_SAMPLINGTERM", -1)] =
2077 "EG_RESOLUTION_MATERIALID", +1)] =
2080 "EG_RESOLUTION_MATERIALID", -1)] =
2083 "EG_RESOLUTION_MATERIALCALO", +1)] =
2086 "EG_RESOLUTION_MATERIALCALO", -1)] =
2089 "EG_RESOLUTION_MATERIALGAP", +1)] =
2092 "EG_RESOLUTION_MATERIALGAP", -1)] =
2095 "EG_RESOLUTION_MATERIALCRYO", +1)] =
2098 "EG_RESOLUTION_MATERIALCRYO", -1)] =
2101 "EG_RESOLUTION_PILEUP", +1)] = egEnergyCorr::Resolution::PileUpUp;
2103 "EG_RESOLUTION_PILEUP", -1)] = egEnergyCorr::Resolution::PileUpDown;
2120 "EG_RESOLUTION_MATERIALIBL", +1)] =
2123 "EG_RESOLUTION_MATERIALIBL", -1)] =
2126 "EG_RESOLUTION_MATERIALPP0", +1)] =
2129 "EG_RESOLUTION_MATERIALPP0", -1)] =
2131
2132 if (m_TESModel == egEnergyCorr::es2022_R22_PRE) { // exta sys. for Run-3
2133 // pre-recommendations
2135 "EG_RESOLUTION_OFC", +1)] = egEnergyCorr::Resolution::OFCUp;
2137 "EG_RESOLUTION_OFC", -1)] = egEnergyCorr::Resolution::OFCDown;
2138 }
2139 }
2140 } else {
2141 ATH_MSG_FATAL("resolution decorrelation model invalid");
2142 }
2143
2144 // Always use individual AF2/AF3 systematics for resolution
2150 "EG_RESOLUTION_AF2", +1)] = egEnergyCorr::Resolution::afUp;
2152 "EG_RESOLUTION_AF2", -1)] = egEnergyCorr::Resolution::afDown;
2153 }
2156 "EG_RESOLUTION_AF3", +1)] = egEnergyCorr::Resolution::afUp;
2158 "EG_RESOLUTION_AF3", -1)] = egEnergyCorr::Resolution::afDown;
2159 }
2160
2161 // ep combination systematics
2163 m_syst_description[CP::SystematicVariation("EL_SCALE_MOMENTUM", +1)] =
2165 m_syst_description[CP::SystematicVariation("EL_SCALE_MOMENTUM", -1)] =
2167 }
2168}
2169
2174
2176 const CP::SystematicSet& systConfig) {
2177
2178 // set the nominal one (no systematics)
2188
2189 if (systConfig.empty())
2190 return StatusCode::SUCCESS;
2191
2192 // the following code allows only ONE systematic variation at a time (1 for
2193 // scale, 1 for resolution)
2194
2195 bool first_scale = true;
2196 bool first_resolution = true;
2197 for (const auto& it : systConfig) {
2198 const auto found_scale = m_syst_description.find(it);
2199 if (found_scale != m_syst_description.end()) {
2200 if (not first_scale) {
2201 ATH_MSG_ERROR("multiple scale variations not supported");
2202 throw std::runtime_error("multiple scale variations not supported");
2203 }
2204 first_scale = false;
2205 m_currentScaleVariation_MC = found_scale->second.effect;
2206 m_currentScalePredicate = found_scale->second.predicate;
2207 }
2208
2209 const auto found_resolution = m_syst_description_resolution.find(it);
2210 if (found_resolution != m_syst_description_resolution.end()) {
2211 if (not first_resolution) {
2212 ATH_MSG_ERROR("multiple resolution variations not supported");
2213 throw std::runtime_error(
2214 "multiple resolution variations not supported");
2215 }
2216 first_resolution = false;
2217 m_currentResolutionVariation_MC = found_resolution->second;
2218 }
2219 }
2220
2221 return StatusCode::SUCCESS;
2222}
2223
2225 double Ecl, double phi, double eta) const {
2226
2227 // Intermodule Widening Correction: E_corr = E / (a' - b' * ((1 / (1 +
2228 // exp((phi_mod - 2 * pi / 32) * c))) * (1 / (1 + exp((phi_mod - 2 * pi / 32)
2229 // * (d)))))) (phi_min, phi_max) : [a' = a / a, b' = b / a, c, d]
2230
2231 double Ecl_corr = 0.;
2232 int DivInt = 0;
2233 double pi = M_PI;
2234
2248
2249 double phi_mod = 0;
2250 if (phi < 0)
2251 phi_mod = fmod(phi, 2 * pi / 16.) + pi / 8.;
2252 else
2253 phi_mod = fmod(phi, 2 * pi / 16.);
2254
2255 // The correction concerns only the barrel
2256 if (std::abs(eta) <= 1.37) {
2257
2258 if (phi < (-7 * pi / 8) && phi > (-1 * pi))
2259 Ecl_corr =
2260 Ecl /
2261 (1 - 0.1086 *
2262 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 175.2759))) *
2263 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-189.3612))))));
2264 if (phi < (-6 * pi / 8) && phi > (-7 * pi / 8))
2265 Ecl_corr =
2266 Ecl /
2267 (1 - 0.0596 *
2268 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 170.8305))) *
2269 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-233.3782))))));
2270 if (phi < (-5 * pi / 8) && phi > (-6 * pi / 8))
2271 Ecl_corr =
2272 Ecl /
2273 (1 - 0.0596 *
2274 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 147.1451))) *
2275 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-139.3386))))));
2276 if (phi < (-4 * pi / 8) && phi > (-5 * pi / 8))
2277 Ecl_corr =
2278 Ecl /
2279 (1 - 0.0583 *
2280 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 168.4644))) *
2281 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-246.2897))))));
2282 if (phi < (-3 * pi / 8) && phi > (-4 * pi / 8))
2283 Ecl_corr =
2284 Ecl /
2285 (1 - 0.0530 *
2286 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 177.6703))) *
2287 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-198.3227))))));
2288 if (phi < (-2 * pi / 8) && phi > (-3 * pi / 8))
2289 Ecl_corr =
2290 Ecl /
2291 (1 - 0.0672 *
2292 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 145.0693))) *
2293 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-242.1771))))));
2294 if (phi < (-1 * pi / 8) && phi > (-2 * pi / 8))
2295 Ecl_corr =
2296 Ecl /
2297 (1 - 0.0871 *
2298 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 132.3303))) *
2299 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-166.1833))))));
2300 if (phi < (0 * pi / 8) && phi > (-1 * pi / 8))
2301 Ecl_corr =
2302 Ecl /
2303 (1 - 0.0948 *
2304 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 127.6780))) *
2305 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-150.0700))))));
2306 if (phi < (1 * pi / 8) && phi > (0 * pi / 8))
2307 Ecl_corr =
2308 Ecl /
2309 (1 - 0.1166 *
2310 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 172.0679))) *
2311 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-235.3293))))));
2312 if (phi < (2 * pi / 8) && phi > (1 * pi / 8))
2313 Ecl_corr =
2314 Ecl /
2315 (1 - 0.1172 *
2316 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 190.3524))) *
2317 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-198.9400))))));
2318 if (phi < (3 * pi / 8) && phi > (2 * pi / 8))
2319 Ecl_corr =
2320 Ecl /
2321 (1 - 0.1292 *
2322 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 158.0540))) *
2323 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-165.3893))))));
2324 if (phi < (4 * pi / 8) && phi > (3 * pi / 8))
2325 Ecl_corr =
2326 Ecl /
2327 (1 - 0.1557 *
2328 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 162.2793))) *
2329 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-133.5131))))));
2330 if (phi < (5 * pi / 8) && phi > (4 * pi / 8))
2331 Ecl_corr =
2332 Ecl /
2333 (1 - 0.1659 *
2334 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 180.5270))) *
2335 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-168.5074))))));
2336 if (phi < (6 * pi / 8) && phi > (5 * pi / 8))
2337 Ecl_corr =
2338 Ecl /
2339 (1 - 0.1123 *
2340 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 128.2277))) *
2341 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-154.4455))))));
2342 if (phi < (7 * pi / 8) && phi > (6 * pi / 8))
2343 Ecl_corr =
2344 Ecl /
2345 (1 - 0.1394 *
2346 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 192.1216))) *
2347 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-198.0727))))));
2348 if (phi < (8 * pi / 8) && phi > (7 * pi / 8))
2349 Ecl_corr =
2350 Ecl /
2351 (1 - 0.1001 *
2352 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 199.1735))) *
2353 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-176.4056))))));
2354 }
2355
2356 // No correction for the EC
2357 else {
2358 Ecl_corr = Ecl;
2359 }
2360
2361 }
2362
2363 else {
2364
2365 // Definitions of module folding into four quarters (top, left, bottom and
2366 // right)
2367
2368 DivInt = (int)(phi / ((2 * pi) / 16.));
2369 double phi_mod = phi - DivInt * (2 * pi / 16.);
2370
2371 // Centring on the intermodule --> phi_mod will now be in [0,0.4]
2372 if (phi_mod < 0)
2373 phi_mod += pi / 8.;
2374
2375 // The correction concerns only the barrel
2376 if (std::abs(eta) <= 1.4) {
2377
2378 // Top quarter
2379 if (phi < (3 * pi) / 4. && phi >= pi / 4.) {
2380 Ecl_corr =
2381 Ecl / (1 - 0.131 * ((1 / (1 + exp((phi_mod - 0.2) * 199.08))) *
2382 (1 / (1 + exp((phi_mod - 0.2) * (-130.36))))));
2383 }
2384
2385 // Right quarter
2386 if (phi < pi / 4. && phi >= -pi / 4.) {
2387 Ecl_corr =
2388 Ecl / (1 - 0.0879 * ((1 / (1 + exp((phi_mod - 0.2) * 221.01))) *
2389 (1 / (1 + exp((phi_mod - 0.2) * (-149.51))))));
2390 }
2391 // Bottom quarter
2392 if (phi < -pi / 4. && phi >= (-3 * pi) / 4.) {
2393 Ecl_corr =
2394 Ecl / (1 - 0.0605 * ((1 / (1 + exp((phi_mod - 0.2) * 281.37))) *
2395 (1 / (1 + exp((phi_mod - 0.2) * (-170.29))))));
2396 }
2397 // Left quarter
2398 if ((phi < (-3 * pi) / 4.) || (phi >= (3 * pi) / 4.)) {
2399 Ecl_corr =
2400 Ecl / (1 - 0.102 * ((1 / (1 + exp((phi_mod - 0.2) * 235.37))) *
2401 (1 / (1 + exp((phi_mod - 0.2) * (-219.04))))));
2402 }
2403 }
2404
2405 // No correction for the EC
2406 else {
2407 Ecl_corr = Ecl;
2408 }
2409 }
2410
2411 return Ecl_corr;
2412}
2413
2415 double phi) const {
2416 constexpr double PI = M_PI;
2417 double Fcorr = 1.0;
2418
2420 // wrong mapping HV -> sectors in run1
2421 if (eta < -0.4 && eta > -0.6) {
2422 if (phi < (14 * PI / 32.) && phi > (13 * PI / 32.)) {
2423 Fcorr += 0.035;
2424 } else if (phi < (13 * PI / 32.) && phi > (12 * PI / 32.)) {
2425 Fcorr -= 0.035;
2426 }
2427 }
2428 }
2429
2443
2444 if (eta < 0.2 && eta > 0.) {
2445 if (phi < (-7 * 2 * PI / 32.) && phi > (-8 * 2 * PI / 32.)) {
2446 Fcorr = 1.016314;
2447 }
2448 }
2449
2450 else if (eta < 0.6 && eta > 0.4) {
2451 if (phi < 0 && phi > (-2 * PI / 32.)) {
2452 Fcorr = 1.041591;
2453 } else if (phi < (-4 * 2 * PI / 32.) && phi > (-5 * 2 * PI / 32.)) {
2454 Fcorr = 1.067346;
2455 }
2456 }
2457
2458 else if (eta < 0.8 && eta > 0.6) {
2459 if (phi < (7 * 2 * PI / 32.) && phi > (6 * 2 * PI / 32.)) {
2460 Fcorr = 1.027980;
2461 }
2462 }
2463
2464 else if (eta < 1.4 && eta > 1.2) {
2465 if (phi < (-9 * 2 * PI / 32.) && phi > (-10 * 2 * PI / 32.)) {
2466 Fcorr = 1.020299;
2467 } else if (phi < (-11 * 2 * PI / 32.) && phi > (-12 * 2 * PI / 32.)) {
2468 Fcorr = 1.051426;
2469 }
2470 }
2471
2472 else if (eta < 2.3 && eta > 2.1) {
2473 if (phi < (-12 * 2 * PI / 32.) && phi > (-13 * 2 * PI / 32.)) {
2474 Fcorr = 1.071695;
2475 }
2476 }
2477
2478 else if (eta < 0. && eta > -0.2) {
2479 if (phi < (-12 * 2 * PI / 32.) && phi > (-13 * 2 * PI / 32.)) {
2480 Fcorr = 1.008227;
2481 } else if (phi < (-8 * 2 * PI / 32.) && phi > (-9 * 2 * PI / 32.)) {
2482 Fcorr = 1.013929;
2483 }
2484 }
2485
2486 else if (eta < -0.2 && eta > -0.4) {
2487 if (phi < (-9 * 2 * PI / 32.) && phi > (-10 * 2 * PI / 32.)) {
2488 Fcorr = 1.015749;
2489 }
2490 }
2491
2492 else if (eta < -1.2 && eta > -1.4) {
2493 if (phi < (-6 * 2 * PI / 32.) && phi > (-7 * 2 * PI / 32.)) {
2494 Fcorr = 1.064954;
2495 }
2496 }
2497
2498 else if (eta < -1.6 && eta > -1.8) {
2499 if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2500 Fcorr = 1.027448;
2501 }
2502 }
2503
2504 else if (eta < -2.3 && eta > -2.5) {
2505 if (phi < (-8 * 2 * PI / 32.) && phi > (-9 * 2 * PI / 32.)) {
2506 Fcorr = 1.025882;
2507 } else if (phi < (5 * 2 * PI / 32.) && phi > (4 * 2 * PI / 32.)) {
2508 Fcorr = 1.036616;
2509 } else if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2510 Fcorr = 1.053838;
2511 } else if (phi < (10 * 2 * PI / 32.) && phi > (9 * 2 * PI / 32.)) {
2512 Fcorr = 1.026856;
2513 } else if (phi < (11 * 2 * PI / 32.) && phi > (10 * 2 * PI / 32.)) {
2514 Fcorr = 0.994382;
2515 }
2516 }
2517
2518 } // es2017_summer_improved end
2519
2520 else {
2521 if (eta < 0.6 && eta > 0.4) {
2522 if (phi < 0 && phi > (-2 * PI / 32.)) {
2523 Fcorr = 1.028;
2524 } else if (phi < (-4 * 2 * PI / 32.) && phi > (-5 * 2 * PI / 32.)) {
2525 Fcorr = 1.044;
2526 }
2527 }
2528
2529 else if (eta < 0.8 && eta > 0.6) {
2530 if (phi < (7 * 2 * PI / 32.) && phi > (6 * 2 * PI / 32.)) {
2531 Fcorr = 1.022;
2532 }
2533 }
2534
2535 else if (eta < 1.4 && eta > 1.2) {
2536 if (phi < (-11 * 2 * PI / 32.) && phi > (-12 * 2 * PI / 32.)) {
2537 Fcorr = 1.038;
2538 }
2539 }
2540
2541 else if (eta < 2.0 && eta > 1.9) {
2542 if (phi < (10 * 2 * PI / 32.) && phi > (9 * 2 * PI / 32.)) {
2543 Fcorr = 1.029;
2544 }
2545 }
2546
2547 else if (eta < -1.2 && eta > -1.4) {
2548 if (phi < (-4 * 2 * PI / 32.) && phi > (-5 * 2 * PI / 32.)) {
2549 Fcorr = 1.048;
2550 } else if (phi < (-6 * 2 * PI / 32.) && phi > (-7 * 2 * PI / 32.)) {
2551 Fcorr = 1.048;
2552 }
2553 }
2554
2555 else if (eta < -1.6 && eta > -1.8) {
2556 if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2557 Fcorr = 1.024;
2558 }
2559 }
2560
2561 else if (eta < -2.3 && eta > -2.5) {
2562 if (phi < (-8 * 2 * PI / 32.) && phi > (-9 * 2 * PI / 32.)) {
2563 Fcorr = 1.037;
2564 } else if (phi < (5 * 2 * PI / 32.) && phi > (4 * 2 * PI / 32.)) {
2565 Fcorr = 1.031;
2566 } else if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2567 Fcorr = 1.040;
2568 } else if (phi < (10 * 2 * PI / 32.) && phi > (9 * 2 * PI / 32.)) {
2569 Fcorr = 1.030;
2570 } else if (phi < (11 * 2 * PI / 32.) && phi > (10 * 2 * PI / 32.)) {
2571 Fcorr = 1.020;
2572 }
2573 }
2574 }
2575
2576 return Fcorr;
2577}
2578
2579void EgammaCalibrationAndSmearingTool ::
2580callSingleEvent (columnar::MutableEgammaRange egammas, columnar::EventInfoId event) const
2581{
2582 for (auto egamma : egammas) {
2584 throw std::runtime_error ("EgammaCalibrationAndSmearingTool::callEvents: apply failed");
2585 }
2586}
2587
2588void EgammaCalibrationAndSmearingTool ::
2589callEvents (columnar::EventContextRange events) const
2590{
2591 const Accessors& acc = *m_accessors;
2592 for (auto event : events) {
2593 auto eventInfo = acc.m_eventHandle(event);
2594 callSingleEvent (acc.m_egammaHandle(event), eventInfo);
2595 }
2596}
2597
2598} // namespace CP
#define M_PI
Scalar eta() const
pseudorapidity method
#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)
Helper class to provide constant type-safe access to aux data.
#define ANA_CHECK(EXP)
check whether the given expression was successful
#define ANA_CHECK_THROW(EXP)
check whether the given expression was successful, throwing an exception on failure
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
@ None
#define pi
static const Attributes_t empty
ServiceHandle< StoreGateSvc > & evtStore()
Return value from object correction CP tools.
@ Error
Some error happened during the object correction.
@ Ok
The correction was done successfully.
egEnergyCorr::Resolution::Variation m_currentResolutionVariation_MC
egEnergyCorr::Scale::Variation m_currentScaleVariation_data
virtual double resolution(double energy, double cl_eta, double cl_etaCalo, PATCore::ParticleType::Type ptype=PATCore::ParticleType::Electron, bool withCT=false) const override
void callSingleEvent(columnar::MutableEgammaRange egammas, columnar::EventInfoId event) const
virtual CP::SystematicSet recommendedSystematics() const override
the list of all systematics this tool recommends to use
std::map< CP::SystematicVariation, SysInfo > m_syst_description
PATCore::ParticleDataType::DataType m_simulation
void setPt(columnar::MutableEgammaId input, double energy) const
const EgammaPredicate EtaCaloPredicateFactory(double eta_min, double eta_max) const
double intermodule_correction(double Ecl, double phi, double eta) const
egEnergyCorr::Scale::Variation m_currentScaleVariation_MC
virtual bool isAffectedBySystematic(const CP::SystematicVariation &systematic) const override
Declare the interface that this class provides.
egEnergyCorr::Scale::Variation oldtool_scale_flag_this_event(columnar::EgammaId p, columnar::EventInfoId event_info) const
std::unique_ptr< egGain::GainUncertainty > m_gain_tool_run2
PATCore::ParticleType::Type xAOD2ptype(columnar::EgammaId particle) const
virtual CP::CorrectionCode correctedCopy(const xAOD::Electron &, xAOD::Electron *&) const override
egEnergyCorr::Resolution::resolutionType m_TResolutionType
double getResolution(const xAOD::Egamma &particle, bool withCT=true) const override
virtual CP::CorrectionCode applyCorrection(xAOD::Egamma &) const override
const EgammaPredicate AbsEtaCaloPredicateFactory(double eta_min, double eta_max) const
double correction_phi_unif(double eta, double phi) const
virtual double getElectronMomentum(const xAOD::Electron *, const xAOD::EventInfo *)
std::map< CP::SystematicVariation, egEnergyCorr::Resolution::Variation > m_syst_description_resolution
virtual StatusCode applySystematicVariation(const CP::SystematicSet &systConfig) override
effects: configure this tool for the given list of systematic variations.
egEnergyCorr::Resolution::Variation oldtool_resolution_flag_this_event(columnar::EgammaId p, columnar::EventInfoId event_info) const
std::unique_ptr< AtlasRoot::egammaEnergyCorrectionTool > m_rootTool
std::function< bool(const EgammaCalibrationAndSmearingTool &, columnar::EgammaId)> EgammaPredicate
egEnergyCorr::Resolution::Variation m_currentResolutionVariation_data
virtual CP::SystematicSet affectingSystematics() const override
the list of all systematics this tool can be affected by
This module implements the central registry for handling systematic uncertainties with CP tools.
static SystematicRegistry & getInstance()
Get the singleton instance of the registry for the curren thread.
StatusCode registerSystematics(const IReentrantSystematicsTool &tool)
effects: register all the systematics from the tool
Class to wrap a set of SystematicVariations.
bool empty() const
returns: whether the set is empty
void insert(const SystematicVariation &systematic)
description: insert a systematic into the set
StatusCode setProperty(const std::string &name, const T &value)
set the given property
void setPropertyFromString(const std::string &name, const std::string &value)
set a given property from a string value
AsgMetadataTool(const std::string &name)
Normal ASG tool constructor with a name.
an object that can create a AsgService
an object that can create a AsgTool
elec/gamma data class.
Definition egamma.h:58
virtual double e() const override
The total energy of the particle.
Definition Egamma_v1.cxx:86
bool eventType(EventType type) const
Check for one particular bitmask value.
@ IS_SIMULATION
true: simulation, false: data
virtual double e() const override final
The total energy of the particle.
Definition Photon_v1.cxx:46
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
void Scale(TH1 *h, double d=1)
Select isolated Photons, Electrons and Muons.
std::unique_ptr< egGain::GainTool > gainToolFactory(egEnergyCorr::ESModel model)
std::string egammaMVAToolFolder(egEnergyCorr::ESModel model)
bool is_after_run1(egEnergyCorr::ESModel model)
bool use_intermodule_correction(egEnergyCorr::ESModel model)
std::unique_ptr< egammaLayerRecalibTool > egammaLayerRecalibToolFactory(egEnergyCorr::ESModel model, int enableSacc)
bool use_phi_uniform_correction(egEnergyCorr::ESModel model)
ObjectId< ContainerId::cluster > ClusterId
Definition ClusterDef.h:26
ObjectId< ContainerId::egamma > EgammaId
Definition EgammaDef.h:50
ObjectRange< ContainerId::eventContext > EventContextRange
ObjectRange< ContainerId::mutableEgamma > MutableEgammaRange
Definition EgammaDef.h:55
ObjectId< ContainerId::mutableEgamma > MutableEgammaId
Definition EgammaDef.h:56
ObjectId< ContainerId::eventInfo > EventInfoId
bool isConvertedPhoton(const xAOD::Egamma *eg, bool excludeTRT=false)
is the object a converted photon
bool isElectron(const xAOD::Egamma *eg)
is the object an electron (not Fwd)
bool isPhoton(const xAOD::Egamma *eg)
is the object a photon
const uint16_t AuthorFwdElectron
Electron reconstructed by the Forward cluster-based algorithm.
Definition EgammaDefs.h:30
@ PileUp
Pile-up vertex.
@ PriVtx
Primary vertex.
EventInfo_v1 EventInfo
Definition of the latest event info version.
setRawEt setRawPhi int
TrackParticle_v1 TrackParticle
Reference the current persistent version:
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)
Photon_v1 Photon
Definition of the current "egamma version".
setBGCode setTAP setLVL2ErrorBits bool
static const SG::AuxElement::Accessor< ElementLink< IParticleContainer > > acc("originalObjectLink")
Object used for setting/getting the dynamic decoration in question.
Electron_v1 Electron
Definition of the current "egamma version".
A structure holding some global event information.
MsgStream & msg
Definition testRead.cxx:32
const float PI