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;
232 return true;
233 case egEnergyCorr::UNDEFINED: // TODO: find better logic
234 return false;
235 }
236 assert(false);
237 return false;
238}
239
241 return use_intermodule_correction(model); // they are equal
242}
243
287
289 const std::string& name)
291 m_TESModel(egEnergyCorr::UNDEFINED),
292 m_TResolutionType(egEnergyCorr::Resolution::SigmaEff90),
296 m_currentResolutionVariation_MC(egEnergyCorr::Resolution::Nominal),
299 columnar::EgammaId egamma,
300 columnar::EventInfoId ei) {
301 const Accessors& acc = *tool.m_accessors;
302 // avoid 0 as result, see
303 // https://root.cern.ch/root/html/TRandom3.html#TRandom3:SetSeed
304 auto cluster = acc.caloClusterAcc(egamma)[0].value();
305 return 1 + static_cast<RandomNumber>(
306 std::abs(acc.clusterPhiAcc(cluster)) * 1E6 +
307 std::abs(acc.clusterEtaAcc(cluster)) * 1E3 +
308 acc.eventNumberAcc(ei));
309 }),
310 m_accessors(std::make_unique<Accessors>(*this)) {
311
312 declareProperty("ESModel", m_ESModel = "");
313 declareProperty("decorrelationModel", m_decorrelation_model_name = "");
314 declareProperty("decorrelationModelScale",
315 m_decorrelation_model_scale_name = "");
316 declareProperty("decorrelationModelResolution",
317 m_decorrelation_model_resolution_name = "");
318 declareProperty("ResolutionType", m_ResolutionType = "SigmaEff90");
319 declareProperty("varSF", m_varSF = 1.0);
320 declareProperty("doScaleCorrection", m_doScaleCorrection = AUTO);
321 declareProperty("doSmearing", m_doSmearing = AUTO);
322 declareProperty("useLayerCorrection", m_useLayerCorrection = AUTO);
323 declareProperty("usePSCorrection", m_usePSCorrection = AUTO);
324 declareProperty("useS12Correction", m_useS12Correction = AUTO);
325 declareProperty("useSaccCorrection", m_useSaccCorrection = AUTO);
326 declareProperty("useIntermoduleCorrection",
327 m_useIntermoduleCorrection = AUTO);
328 declareProperty("usePhiUniformCorrection", m_usePhiUniformCorrection = AUTO);
329 declareProperty("useCaloDistPhiUnifCorrection",
330 m_useCaloDistPhiUnifCorrection = AUTO);
331 declareProperty("useGainCorrection", m_useGainCorrection = AUTO);
332 declareProperty("useGainInterpolation", m_useGainInterpolation = AUTO);
333 declareProperty("doADCLinearityCorrection",
334 m_doADCLinearityCorrection = AUTO);
335 declareProperty("doLeakageCorrection", m_doLeakageCorrection = AUTO);
336 declareProperty("MVAfolder", m_MVAfolder = "");
337 declareProperty("layerRecalibrationTune", m_layer_recalibration_tune = "");
338 declareProperty("useEPCombination", m_use_ep_combination = false);
339 declareProperty("useMVACalibration", m_use_mva_calibration = AUTO);
340 declareProperty("use_full_statistical_error",
341 m_use_full_statistical_error = false);
342 declareProperty("use_temp_correction201215",
343 m_use_temp_correction201215 = AUTO);
344 declareProperty("use_uA2MeV_2015_first2weeks_correction",
345 m_use_uA2MeV_2015_first2weeks_correction = AUTO);
346 declareProperty("randomRunNumber", m_user_random_run_number = 0);
347 // this is the user input, it is never changed by the tool. The tool uses
348 // m_simulation.
349 declareProperty("useFastSim", m_useFastSim = -1,
350 "This should be explicitly set by the user depending on the "
351 "data type (int)0=full sim, (int)1=fast sim");
352 declareProperty(
353 "useAFII", m_use_AFII = -1,
354 "This is now deprecated. Kept for explicit error message for now");
355 declareProperty("decorateEmva", m_decorateEmva = false, "whether to decorate the eMVA value");
356}
357
363
365 ATH_MSG_INFO("Initialization");
366
367 if (m_ESModel == "es2015XX") {
368 ATH_MSG_ERROR("es2015XX is deprecated. Use es2015PRE");
369 }
370
371 if (m_ESModel == "es2010") {
373 } // legacy
374 else if (m_ESModel == "es2011c") {
376 } // mc11c : faulty G4; old geometry
377 else if (m_ESModel == "es2011d") {
379 } // mc11d : corrected G4; new geometry == final Run1 scheme
380 else if (m_ESModel == "es2012a") {
382 } // mc12a : "crude" G4 fix; old geometry
383 else if (m_ESModel == "es2012c") {
385 } // mc12c : corrected G4; new geometry == final Run1 scheme
386 else if (m_ESModel == "es2012XX") {
388 } else if (m_ESModel == "es2015PRE") {
390 } else if (m_ESModel == "es2015PRE_res_improved") {
392 } else if (m_ESModel == "es2015cPRE") {
394 } else if (m_ESModel == "es2015cPRE_res_improved") {
396 } else if (m_ESModel == "es2015c_summer") {
398 } else if (m_ESModel == "es2016PRE") {
400 } else if (m_ESModel == "es2016data_mc15c") {
402 } else if (m_ESModel == "es2016data_mc15c_summer") {
404 } else if (m_ESModel == "es2016data_mc15c_summer_improved") {
406 } else if (m_ESModel == "es2016data_mc15c_final") {
408 } else if (m_ESModel == "es2015_5TeV") {
410 } else if (m_ESModel == "es2017_R21_PRE") {
412 } else if (m_ESModel == "es2017_R21_v0") {
414 } else if (m_ESModel == "es2017_R21_v1") {
416 } else if (m_ESModel == "es2017_R21_ofc0_v1") {
418 } else if (m_ESModel == "es2018_R21_v0") {
420 } else if (m_ESModel == "es2018_R21_v1") {
422 } else if (m_ESModel == "es2022_R22_PRE") {
424 } else if (m_ESModel == "es2023_R22_Run2_v0") {
426 } else if (m_ESModel == "es2023_R22_Run2_v1") {
428 } else if (m_ESModel == "es2024_Run3_ofc0_v0") {
430 } else if (m_ESModel == "es2024_Run3_v0") {
432 } else if (m_ESModel.empty()) {
433 ATH_MSG_ERROR("you must set ESModel property");
434 return StatusCode::FAILURE;
435 } else {
436 ATH_MSG_ERROR("Cannot understand model " << m_ESModel);
437 return StatusCode::FAILURE;
438 }
439
440 if (m_ResolutionType == "Gaussian") {
442 } else if (m_ResolutionType == "SigmaEff80") {
444 } else if (m_ResolutionType == "SigmaEff90") {
446 } else {
447 ATH_MSG_ERROR("Cannot understand resolution " << m_ResolutionType);
448 return StatusCode::FAILURE;
449 }
450
451 if (m_use_AFII != -1) {
453 "Property useAFII is deprecated. It is now replaced with useFastSim, "
454 "which should be explicitly configured");
455 return StatusCode::FAILURE;
456 }
457
458 if (m_useFastSim == 1) {
460 } else if (m_useFastSim == 0) {
462 } else {
463 ATH_MSG_ERROR("Property useFastSim should be explicitly configured");
464 return StatusCode::FAILURE;
465 }
466
470 "Sample is FastSim but no AF3 calibration is supported with "
471 "MC23 pre-recommendations (es2022_R22_PRE and es2024_Run3_ofc0_v0). "
472 "Please swtich to Run3 consolidated recommendations (es2024_Run3_v0), "
473 "or get in touch with the EGamma CP group in case you are using this");
474 return StatusCode::FAILURE;
475 }
476
477 // configure decorrelation model, translate string property to internal class
478 // enum
479 /* S R SR
480 0. 0 0 0 WARNING Full, Full (this is the default without configuration)
481 1. 0 0 1 SR
482 2. 0 1 0 FATAL
483 3. 0 1 1 WARNING SR then R
484 4. 1 0 0 FATAL
485 5. 1 0 1 WARNING SR then S
486 6. 1 1 0 S, R
487 7. 1 1 1 FATAL
488 */
489 if (m_decorrelation_model_name.empty() and
492 // case 0
493 ATH_MSG_WARNING("no decorrelation model specified, assuming full model");
494 m_decorrelation_model_scale = ScaleDecorrelation::FULL;
496 m_decorrelation_model_name = "FULL_v1";
497 } else if (not m_decorrelation_model_name.empty() and
500 // case 7
501 ATH_MSG_FATAL("too many flags for the decorrelation model");
502 return StatusCode::FAILURE;
503 } else {
504 // set scale decorrelation model
505 if (not m_decorrelation_model_scale_name.empty()) { // case 4, 5, 6, (7)
506 if (not m_decorrelation_model_name.empty()) {
508 "flag decorrelation model ignored for scale decorrelation model");
509 } // case 5
510 if (m_decorrelation_model_scale_name == "1NP_v1")
511 m_decorrelation_model_scale = ScaleDecorrelation::ONENP;
512 else if (m_decorrelation_model_scale_name == "FULL_ETACORRELATED_v1")
513 m_decorrelation_model_scale = ScaleDecorrelation::FULL_ETA_CORRELATED;
514 else if (m_decorrelation_model_scale_name == "1NPCOR_PLUS_UNCOR")
515 m_decorrelation_model_scale = ScaleDecorrelation::ONENP_PLUS_UNCONR;
516 else if (m_decorrelation_model_scale_name == "FULL_v1")
517 m_decorrelation_model_scale = ScaleDecorrelation::FULL;
518 else {
519 ATH_MSG_FATAL("cannot understand the scale decorrelation model '"
520 << m_decorrelation_model_scale_name << "'(typo?)");
521 return StatusCode::FAILURE;
522 }
523 } else if (not m_decorrelation_model_name.empty()) { // case 1, 3
524 if (m_decorrelation_model_name == "1NP_v1")
525 m_decorrelation_model_scale = ScaleDecorrelation::ONENP;
526 else if (m_decorrelation_model_name == "FULL_ETACORRELATED_v1")
527 m_decorrelation_model_scale = ScaleDecorrelation::FULL_ETA_CORRELATED;
528 else if (m_decorrelation_model_name == "1NPCOR_PLUS_UNCOR")
529 m_decorrelation_model_scale = ScaleDecorrelation::ONENP_PLUS_UNCONR;
530 else if (m_decorrelation_model_name == "FULL_v1")
531 m_decorrelation_model_scale = ScaleDecorrelation::FULL;
532 else {
533 ATH_MSG_FATAL("cannot understand the decorrelation model '"
534 << m_decorrelation_model_name << "'(typo?)");
535 return StatusCode::FAILURE;
536 }
537 } else { // case 2, (7)
539 "not information how to initialize the scale decorrelation model");
540 return StatusCode::FAILURE;
541 }
542
543 // set resolution decorralation model
545 .empty()) { // case 2, 3, 6, (7)
546 if (not m_decorrelation_model_name.empty()) {
548 "flag decorrelation model ignored for resolution decorrelation "
549 "model");
550 } // case 3
553 else if (m_decorrelation_model_resolution_name == "FULL_v1")
555 else {
556 ATH_MSG_FATAL("cannot understand the resolution decorrelation model '"
558 return StatusCode::FAILURE;
559 }
560 } else if (not m_decorrelation_model_name.empty()) { // case 1, 5
561 if (m_decorrelation_model_name == "1NP_v1")
563 else if (m_decorrelation_model_name == "FULL_ETACORRELATED_v1")
565 else if (m_decorrelation_model_name == "1NPCOR_PLUS_UNCOR")
567 else if (m_decorrelation_model_name == "FULL_v1")
569 else {
570 ATH_MSG_FATAL("cannot understand the decorrelation model '"
571 << m_decorrelation_model_name << "'(typo?)");
572 return StatusCode::FAILURE;
573 }
574 }
575 }
576
577 // create correction tool
578 ATH_MSG_DEBUG("creating internal correction tool");
579 m_rootTool = std::make_unique<AtlasRoot::egammaEnergyCorrectionTool>();
580 if (!m_rootTool) {
581 ATH_MSG_ERROR("Cannot initialize underlying tool");
582 return StatusCode::FAILURE;
583 }
584 m_rootTool->setESModel(m_TESModel);
585
591 "Using linear interpolation in the gain tool (uncertainties only)");
593 m_rootTool->setApplyL2GainInterpolation();
594 }
595 m_rootTool->msg().setLevel(this->msg().level());
596 m_rootTool->initialize();
597
598 // configure MVA calibration
599 if (m_use_mva_calibration != 0) {
600 ATH_MSG_DEBUG("creating MVA calibration tool (if needed)");
601 if (m_MVAfolder.empty()) { // automatically configure MVA tool
603 }
604
605 if (not m_MVAfolder.empty()) {
606
607 // electron MVA tool
608 asg::AsgToolConfig config_mva_electron(
609 "egammaMVACalibTool/tool_mva_electron");
610 config_mva_electron.setPropertyFromString("folder", m_MVAfolder);
611 ATH_CHECK(config_mva_electron.setProperty("use_layer_corrected", true));
612 ATH_CHECK(config_mva_electron.setProperty(
613 "ParticleType", xAOD::EgammaParameters::electron));
614
615 // unconverted photon MVA tool
616 asg::AsgToolConfig config_mva_unconverted(
617 "egammaMVACalibTool/tool_mva_unconverted");
618 config_mva_unconverted.setPropertyFromString("folder", m_MVAfolder);
619 ATH_CHECK(
620 config_mva_unconverted.setProperty("use_layer_corrected", true));
621 ATH_CHECK(config_mva_unconverted.setProperty(
623 ATH_CHECK(config_mva_unconverted.setProperty("OutputLevel",
624 this->msg().level()));
625
626 // converted photon MVA tool
627 asg::AsgToolConfig config_mva_converted(
628 "egammaMVACalibTool/tool_mva_converted");
629 config_mva_converted.setPropertyFromString("folder", m_MVAfolder);
630 ATH_CHECK(config_mva_converted.setProperty("use_layer_corrected", true));
631 ATH_CHECK(config_mva_converted.setProperty(
633 ATH_CHECK(config_mva_converted.setProperty("OutputLevel",
634 this->msg().level()));
635
636 // initialize the ServiceHandler egammaMVASvc
637 // make the name unique
638 std::ostringstream mva_service_name;
639 mva_service_name << "egammaMVASvc/service_mva_egamma_id"
640 << (void const*)this;
641 asg::AsgServiceConfig config_mva_service(mva_service_name.str());
642 ATH_CHECK(config_mva_service.addPrivateTool("ElectronTool",
643 config_mva_electron));
644 ATH_CHECK(config_mva_service.addPrivateTool("UnconvertedPhotonTool",
645 config_mva_unconverted));
646 ATH_CHECK(config_mva_service.addPrivateTool("ConvertedPhotonTool",
647 config_mva_converted));
648 // fwd electron MVA tool
649 if (m_doFwdCalib) {
650 asg::AsgToolConfig config_mva_fwdelectron(
651 "egammaMVACalibTool/tool_mva_fwdelectron");
652 config_mva_fwdelectron.setPropertyFromString("folder", m_MVAfolder);
653 ATH_CHECK(config_mva_fwdelectron.setProperty(
655 ATH_CHECK(config_mva_fwdelectron.setProperty("ShiftType", 0));
656 ATH_CHECK(config_mva_fwdelectron.setProperty("OutputLevel", this->msg().level()));
657 ATH_CHECK(config_mva_service.addPrivateTool("FwdElectronTool",
658 config_mva_fwdelectron));
659 }
660 config_mva_service.setPropertyFromString("folder", m_MVAfolder);
661 ATH_CHECK(
662 config_mva_service.setProperty("OutputLevel", this->msg().level()));
663 ATH_CHECK(config_mva_service.makeService(m_MVACalibSvc));
664 } else {
665 m_use_mva_calibration = false;
666 }
667 }
668
669 // configure layer recalibration tool
670 // For now: layer recalibration not applied to PRE release 21 (using run 1
671 // based calibration applied at reco level)
672 // for following R21 recommendations, need to apply the run2/run1 layer
673 // calibration ratio
674 if (m_ESModel == "es2017_R21_PRE") {
675 ATH_MSG_INFO("Layer recalibration already applied at cell level");
676 m_useLayerCorrection = false;
677 } else if (!m_useLayerCorrection) {
678 ATH_MSG_INFO("Layer corrections disabled!");
679 } else {
680 ATH_MSG_DEBUG("initializing layer recalibration tool (if needed)");
682 .empty()) { // automatically configure layer recalibration tool
685 .release();
687 ATH_MSG_INFO("not using layer recalibration");
688 }
689 } else {
692 }
694 m_layer_recalibration_tool->msg().setLevel(this->msg().level());
696 if (!m_usePSCorrection) {
697 ATH_MSG_INFO("PS corrections disabled!");
698 m_layer_recalibration_tool->disable_PSCorrections();
699 }
700 if (!m_useS12Correction) {
701 ATH_MSG_INFO("S12 corrections disabled!");
702 m_layer_recalibration_tool->disable_S12Corrections();
703 }
704 if (!m_useSaccCorrection) {
705 ATH_MSG_INFO("Sacc corrections disabled!");
706 m_layer_recalibration_tool->disable_SaccCorrections();
707 }
708 }
709 }
710
712 m_rootTool->use_temp_correction201215(m_use_temp_correction201215);
714 m_rootTool->use_uA2MeV_2015_first2weeks_correction(
717 m_decorrelation_model_scale == ScaleDecorrelation::FULL) {
718 m_rootTool->useStatErrorScaling(true);
719 }
720
722 ATH_MSG_ERROR("ep combination not supported yet");
723 throw std::runtime_error("ep combination not supported yet");
724 }
725
728 }
731 }
733
734 if (m_useGainCorrection == AUTO) {
739 }
740 else {
741 ATH_MSG_DEBUG("initializing gain tool");
744 }
745 }
746 else if (m_useGainCorrection == 1) {
752 "cannot instantiate gain tool for this model (you can only disable "
753 "the gain tool, but not enable it)");
754 }
755 else {
757 "initializing gain tool for run2 final precision recommendations");
759 "Gain corrections required but Zee scales are derived without Gain, "
760 "will cause inconsistency!");
761 std::string gain_tool_run_2_filename = PathResolverFindCalibFile(
762 "ElectronPhotonFourMomentumCorrection/v29/"
763 "gain_uncertainty_specialRun.root");
764 m_gain_tool_run2 = std::make_unique<egGain::GainUncertainty>(
765 gain_tool_run_2_filename, false, "GainCorrection",
767 m_gain_tool_run2->msg().setLevel(this->msg().level());
768 }
769 }
770
774 // ADC non linearity correction
777 std::string adcLinearityCorr_filename = PathResolverFindCalibFile(
778 "ElectronPhotonFourMomentumCorrection/v25/linearity_ADC.root");
779 m_ADCLinearity_tool = std::make_shared<LinearityADC>(adcLinearityCorr_filename);
780 m_ADCLinearity_tool->msg().setLevel(this->msg().level());
781 m_rootTool->setADCTool(m_ADCLinearity_tool);
782 } else {
784 m_ESModel + " recommendations use ADC corrections for scale "
785 "derivation. Disabling the ADCLinearity flag will create "
786 "inconsistency!");
787 }
788
791 m_rootTool->setApplyLeakageCorrection(true);
792 }
793
794 // Calo distortion phi unif correction
798 std::string phiUnifCorrfileName = PathResolverFindCalibFile(
799 "ElectronPhotonFourMomentumCorrection/v33/"
800 "egammaEnergyCorrectionData.root");
801 std::unique_ptr<TFile> fCorr(
802 TFile::Open(phiUnifCorrfileName.c_str(), "READ"));
804 dynamic_cast<TH2*>(fCorr->Get("CaloDistortionPhiUniformityCorrection/"
805 "es2023_R22_Run2_v0/h2DcorrPhiUnif")));
806 m_caloDistPhiUnifCorr->SetDirectory(nullptr);
807 } else {
809 m_ESModel + " recommendations use CaloDistPhiUnif for scale "
810 "derivation. Disabling the CaloDistPhiUnif flag will create "
811 "inconsistency!");
812 }
813 }
814
815 // No scale correction for release 21 ==> obsolete
816 /*if (m_ESModel == "es2017_R21_PRE"){
817 m_doScaleCorrection = 0;
818 }
819 */
820
821 ATH_MSG_INFO("ESModel: " << m_ESModel);
822 ATH_MSG_INFO("ResolutionType: " << m_ResolutionType);
823 ATH_MSG_INFO("decorrelation Model: " << m_decorrelation_model_name);
824 ATH_MSG_DEBUG("layer correction = " << m_useLayerCorrection);
825 ATH_MSG_DEBUG("PS correction = " << m_usePSCorrection);
826 ATH_MSG_DEBUG("S12 correction = " << m_useS12Correction);
827 ATH_MSG_DEBUG("Sacc correction = " << m_useSaccCorrection);
828 ATH_MSG_DEBUG("intermodule correction = " << m_useIntermoduleCorrection);
829 ATH_MSG_DEBUG("phi uniformity correction = " << m_usePhiUniformCorrection);
830 ATH_MSG_DEBUG("distorted calo phi uniformity correction = "
832 ATH_MSG_DEBUG("gain correction = " << m_useGainCorrection);
833 ATH_MSG_DEBUG("ADC non-linearity correction = " << m_doADCLinearityCorrection);
834 ATH_MSG_DEBUG("leakage correction for photons = " << m_doLeakageCorrection);
835 ATH_MSG_DEBUG("smearing = " << m_doSmearing);
836 ATH_MSG_DEBUG("insitu scales = " << m_doScaleCorrection);
837 ATH_MSG_DEBUG("ep combination = " << m_use_ep_combination);
838 ATH_MSG_DEBUG("use MVA calibration = " << m_use_mva_calibration);
840 "use temperature correction 2015 = " << m_use_temp_correction201215);
841 ATH_MSG_DEBUG("use uA2MeV correction 2015 1/2 week = "
843
845
847 .ignore(); // this set the flags for the internal tool without
848 // systematics
850 if (registry.registerSystematics(*this) != StatusCode::SUCCESS)
851 return StatusCode::FAILURE;
852
853 if (m_onlyElectrons.value() && m_onlyPhotons.value()) {
854 ATH_MSG_ERROR("Cannot select both onlyElectrons and onlyPhotons");
855 return StatusCode::FAILURE;
856 }
857 if (m_onlyElectrons.value()) {
858 resetElectron (m_accessors->momAcc, *m_accessors);
860 resetAccessor (m_accessors->electronTrackAcc, *this, "trackParticleLinks");
861 }
862 }
863 if (m_onlyPhotons.value()) {
864 resetPhoton (m_accessors->momAcc, *m_accessors);
865 resetAccessor (m_accessors->photonVertexAcc, *this, "vertexLinks");
866 }
867 if (m_decorateEmva)
868 resetAccessor (m_accessors->decEmva, *this, "E_mva_only");
869
870 ANA_CHECK (initializeColumns ());
871
872 return StatusCode::SUCCESS;
873}
874
875
877{
878 const Accessors& acc = *m_accessors;
879
880 // this is departing from the logic below, as we are now requiring the
881 // user to specify at configuration time whether we run on electrons
882 // or photons. this is necessary to configure the columns we need
883 // correctly.
884 if (m_onlyElectrons.value())
885 {
887 }
888 if (m_onlyPhotons.value())
889 {
890 if (acc.photonVertexAcc(particle).size() > 0)
891 {
893 }
894 else
895 {
897 }
898 }
899
900 // this is the old logic and should not be visited in columnar mode
901 // (disabled by turning on onlyElectrons or onlyPhotons)
903 //no ForwardElectron ptype: consider them as Electron
904 if (xAOD::EgammaHelpers::isElectron(&particle.getXAODObject()) || acc.authorAcc (particle) == xAOD::EgammaParameters::AuthorFwdElectron) { ptype = PATCore::ParticleType::Electron; }
905 else if (xAOD::EgammaHelpers::isPhoton(&particle.getXAODObject())) {
906 if (xAOD::EgammaHelpers::isConvertedPhoton(&particle.getXAODObject())) { ptype = PATCore::ParticleType::ConvertedPhoton; }
908 }
909 else {
910 ATH_MSG_ERROR("particle is not electron of photon");
911 throw std::runtime_error("particle is not electron or photon");
912 }
913 return ptype;
914}
915
917 const xAOD::Egamma& particle, bool withCT) const {
918 const auto ptype = xAOD2ptype(particle);
919 const auto cl_etaCalo =
920 xAOD::get_eta_calo(*particle.caloCluster(), particle.author());
921
922 return m_rootTool->resolution(particle.e(), particle.caloCluster()->eta(),
923 cl_etaCalo, ptype, withCT,
924 false); // TODO: always for full simulation
925}
926
928 double energy, double cl_eta, double cl_etaCalo,
929 PATCore::ParticleType::Type ptype, bool withCT) const {
930 return m_rootTool->resolution(energy, cl_eta, cl_etaCalo, ptype, withCT,
931 false);
932}
933
935 xAOD::Egamma& input) const {
936 // Retrieve the event information:
937 const xAOD::EventInfo* event_info = nullptr;
938 if (evtStore()->retrieve(event_info, "EventInfo").isFailure()) {
939 ATH_MSG_ERROR("No EventInfo object could be retrieved");
941 }
942 return applyCorrection(input, *event_info);
943}
944
946 const xAOD::Electron& input, xAOD::Electron*& output) const {
947 // A sanity check:
948 if (output)
950 "Non-null pointer received. "
951 "There's a possible memory leak!");
952
953 output = new xAOD::Electron();
954 output->makePrivateStore(input);
955 return applyCorrection(*output);
956}
957
959 const xAOD::Photon& input, xAOD::Photon*& output) const {
960 // A sanity check:
961 if (output)
963 "Non-null pointer received. "
964 "There's a possible memory leak!");
965
966 output = new xAOD::Photon();
967 output->makePrivateStore(input);
968 return applyCorrection(*output);
969}
970
972 const xAOD::Photon& input) const {
973 xAOD::Photon* new_particle = nullptr;
974 ANA_CHECK_THROW(correctedCopy(input, new_particle));
975 const double e = new_particle->e();
976 delete new_particle;
977 return e;
978}
979
981 const xAOD::Electron& input) const {
982 xAOD::Electron* new_particle = nullptr;
983 ANA_CHECK_THROW(correctedCopy(input, new_particle));
984 const double e = new_particle->e();
985 delete new_particle;
986 return e;
987}
988
990 columnar::MutableEgammaId input, columnar::EventInfoId event_info) const {
991 const Accessors& acc = *m_accessors;
992
993 // only used in simulation (for the smearing)
994 RandomNumber seed = m_set_seed_function(*this, input, event_info);
995
996 columnar::ClusterId inputCluster = acc.caloClusterAcc (input)[0].value();
997
998 if (m_layer_recalibration_tool && acc.authorAcc (input) !=
1000 ATH_MSG_DEBUG("applying energy recalibration before E0|E1|E2|E3 = "
1001 << acc.energyBEAcc (inputCluster, 0) << "|"
1002 << acc.energyBEAcc (inputCluster, 1) << "|"
1003 << acc.energyBEAcc (inputCluster, 2) << "|"
1004 << acc.energyBEAcc (inputCluster, 3));
1005 // for now just go back to the xAOD object to access the subtool
1006 const CP::CorrectionCode status_layer_recalibration = m_layer_recalibration_tool->applyCorrection(input.getXAODObject(), event_info.getXAODObject());
1007 if (status_layer_recalibration == CP::CorrectionCode::Error) { return CP::CorrectionCode::Error; }
1008 ATH_MSG_DEBUG("eta|phi = " << acc.etaAcc (input) << "|" << acc.phiAcc (input));
1009 if (status_layer_recalibration == CP::CorrectionCode::Ok) {
1010 ATH_MSG_DEBUG("decoration E0|E1|E2|E3 = "
1011 << acc.Es0Acc(inputCluster) << "|"
1012 << acc.Es1Acc(inputCluster) << "|"
1013 << acc.Es2Acc(inputCluster) << "|"
1014 << acc.Es3Acc(inputCluster) << "|");
1015 if (acc.Es2Acc(inputCluster) == 0 and acc.Es1Acc(inputCluster) == 0 and
1016 acc.Es3Acc(inputCluster) == 0 and acc.Es0Acc(inputCluster) == 0 and
1017 (std::abs(acc.etaAcc (input)) < 1.37 or (std::abs(acc.etaAcc (input)) > 1.55 and std::abs(acc.etaAcc (input)) < 2.47)))
1018 {
1019 ATH_MSG_WARNING("all layer energies are zero");
1020 }
1021 }
1022 }
1023
1024 double energy = acc.momAcc.e (input);
1025 // apply MVA calibration
1026 if (!m_MVACalibSvc.empty()) {
1028 if (acc.authorAcc (input) ==
1030 const xAOD::VertexContainer* pVtxCont = nullptr;
1031 if (evtStore()->retrieve(pVtxCont, m_pVtxKey).isFailure()) {
1032 ATH_MSG_ERROR("No primary vertex container " << m_pVtxKey << " could be retrieved");
1034 }
1035 unsigned int npv(0);
1036 for (const auto *vtx : *pVtxCont) {
1037 if (vtx->vertexType() == xAOD::VxType::PriVtx ||
1038 vtx->vertexType() == xAOD::VxType::PileUp) { ++npv; }
1039 }
1040 gei.nPV = npv;
1041 gei.acmu = acc.actIntPerXingAcc(event_info);
1042 ATH_MSG_DEBUG("Retrieved nPV = " << gei.nPV << " and mu = " << gei.acmu);
1043 }
1044 if (acc.authorAcc (input) !=
1046 if (m_MVACalibSvc->getEnergy(inputCluster.getXAODObject(), input.getXAODObject(), energy, gei)
1047 .isFailure()) {
1048 ATH_MSG_ERROR("Failure in MVACalib service");
1050 }
1051 ATH_MSG_DEBUG("energy after MVA calibration = " << std::format("{:.2f}", energy));
1052 }
1053 }
1054 if (m_decorateEmva)
1055 {
1056 acc.decEmva(input) = energy;
1057 }
1058
1059 // For the time being, it is just the MVA calib
1060 if (acc.authorAcc (input) ==
1062 setPt(input, energy);
1064 }
1065
1067 // Crack calibation correction for es2011c (calibration hits calibration)
1068 const auto ptype = xAOD2ptype(input);
1069 const double etaden =
1071 ? static_cast<const xAOD::Electron&>(input.getXAODObject()).trackParticle()->eta()
1072 : acc.clusterEtaAcc(inputCluster);
1073 energy *= m_rootTool->applyMCCalibration(acc.clusterEtaAcc(inputCluster),
1074 energy / cosh(etaden), ptype);
1075 ATH_MSG_DEBUG("energy after crack calibration es2011c = "
1076 << std::format("{:.2f}", energy));
1077 }
1078
1079 /*
1080 * Here we check for each event the kind of data DATA vs FullSim
1081 * The m_simulation flavour has already been configured
1082 */
1084 (acc.eventTypeAcc(event_info,xAOD::EventInfo::IS_SIMULATION))
1085 ? m_simulation
1087
1088 unsigned int runNumber_for_tool = 0;
1089
1090 // apply uniformity corrections to data
1091 if (dataType == PATCore::ParticleDataType::Data) {
1092 // Get run number
1093 runNumber_for_tool = acc.runNumberAcc(event_info);
1094 // Get etaCalo, phiCalo
1095 const auto cl_eta = acc.clusterEtaAcc(inputCluster);
1096 double etaCalo = 0, phiCalo = 0;
1098 etaCalo = acc.etaCaloAcc(inputCluster, acc.authorAcc(input), false);
1100 phiCalo =
1101 acc.phiCaloAcc(inputCluster, acc.authorAcc(input), false);
1102 }
1103 }
1104
1105 // Intermodule
1107 energy =
1108 intermodule_correction(energy, acc.clusterPhiAcc(inputCluster), cl_eta);
1109 ATH_MSG_DEBUG("energy after intermodule correction = "
1110 << std::format("{:.2f}", energy));
1111 }
1112
1113 // Calo distortion
1118 double etaC = acc.clusterEtaAcc(inputCluster);
1119 double phiC = acc.clusterPhiAcc(inputCluster);
1120 int ieta = m_caloDistPhiUnifCorr->GetXaxis()->FindBin(etaC);
1121 ieta = ieta == 0 ? 1
1122 : (ieta > m_caloDistPhiUnifCorr->GetNbinsX()
1123 ? m_caloDistPhiUnifCorr->GetNbinsX()
1124 : ieta);
1125 int iphi = m_caloDistPhiUnifCorr->GetYaxis()->FindBin(phiC);
1126 iphi = iphi == 0 ? 1
1127 : (iphi > m_caloDistPhiUnifCorr->GetNbinsY()
1128 ? m_caloDistPhiUnifCorr->GetNbinsY()
1129 : iphi);
1130 energy *= m_caloDistPhiUnifCorr->GetBinContent(ieta, iphi);
1132 "energy after phi uniformity correction (for calo distortion) = "
1133 << std::format("{:.2f}", energy));
1134 }
1135
1136 // Phi
1138 energy *= correction_phi_unif(etaCalo, phiCalo);
1139 ATH_MSG_DEBUG("energy after uniformity correction = "
1140 << std::format("{:.2f}", energy));
1141 }
1142
1143 // ADC
1144 if (m_ADCLinearity_tool) {
1145 double et = energy / std::cosh(cl_eta);
1146 double corr =
1147 m_ADCLinearity_tool->getCorr(etaCalo, et, xAOD2ptype(input));
1148 energy *= corr;
1149 ATH_MSG_DEBUG("energy after ADC linearity correction = "
1150 << std::format("{:.2f}", energy));
1151 }
1152
1153 // Gain
1154 if (m_gain_tool) {
1155 const auto es2 = acc.Es2Acc.isAvailable(inputCluster)
1156 ? acc.Es2Acc(inputCluster)
1157 : acc.energyBEAcc (inputCluster,2);
1158 if (!(std::abs(cl_eta) < 1.52 and std::abs(cl_eta) > 1.37) and
1159 std::abs(cl_eta) < 2.4)
1160 energy = m_gain_tool->CorrectionGainTool(
1161 cl_eta, energy / GeV, es2 / GeV,
1162 xAOD2ptype(input)); // cl_eta ok, TODO: check corrected E2
1163 } else if (m_gain_tool_run2) {
1164 double et = energy / std::cosh(cl_eta);
1165 double corr = m_gain_tool_run2->getUncertainty(etaCalo, et,
1166 xAOD2ptype(input), true);
1167 energy /= (1 + corr);
1168 }
1169 ATH_MSG_DEBUG("energy after gain correction = " << std::format("{:.2f}", energy));
1170 } else {
1171 if (m_user_random_run_number == 0) {
1172 if (acc.randomrunnumber_getter.isAvailable(event_info)) {
1173 runNumber_for_tool = acc.randomrunnumber_getter(event_info);
1174 } else {
1176 "Pileup tool not run before using "
1177 "ElectronPhotonFourMomentumCorrection! Assuming it is 2016. If you "
1178 "want to force a specific period set the property randomRunNumber "
1179 "of the tool, e.g. in the job option: "
1180 "tool.randomRunNumber = 123456 or "
1181 "tool.randomRunNumber = "
1182 "EgammaCalibrationAndSmearingToolRunNumbersExample.run_2016");
1184 }
1185 } else {
1186 runNumber_for_tool = m_user_random_run_number;
1187 }
1188 }
1189
1190 const double eraw = ((acc.Es0Acc.isAvailable(inputCluster)
1191 ? acc.Es0Acc(inputCluster)
1192 : acc.energyBEAcc(inputCluster,0)) +
1193 (acc.Es1Acc.isAvailable(inputCluster)
1194 ? acc.Es1Acc(inputCluster)
1195 : acc.energyBEAcc(inputCluster,1)) +
1196 (acc.Es2Acc.isAvailable(inputCluster)
1197 ? acc.Es2Acc(inputCluster)
1198 : acc.energyBEAcc(inputCluster,2)) +
1199 (acc.Es3Acc.isAvailable(inputCluster)
1200 ? acc.Es3Acc(inputCluster)
1201 : acc.energyBEAcc(inputCluster,3)));
1202
1203
1204 if (dataType == PATCore::ParticleDataType::Fast)
1205 ATH_MSG_DEBUG("is fast");
1206 else if (dataType == PATCore::ParticleDataType::Full)
1207 ATH_MSG_DEBUG("is full");
1208 else if (dataType == PATCore::ParticleDataType::Data)
1209 ATH_MSG_DEBUG("is data");
1210
1211 // apply scale factors or systematics
1212 energy = m_rootTool->getCorrectedEnergy(
1213 runNumber_for_tool, dataType, xAOD2ptype(input),
1214 inputCluster(acc.clusterEtaAcc),
1215 inputCluster(acc.clusterEtaBEAcc,2),
1216 acc.etaCaloAcc(inputCluster, acc.authorAcc (input), false), energy,
1217 acc.Es2Acc.isAvailable(inputCluster)
1218 ? acc.Es2Acc(inputCluster)
1219 : inputCluster(acc.energyBEAcc,2),
1220 eraw, seed, oldtool_scale_flag_this_event(input, event_info),
1222 m_varSF);
1223
1224 ATH_MSG_DEBUG("energy after scale/systematic correction = " << std::format("{:.2f}", energy));
1225
1226 // TODO: this check should be done before systematics variations
1227 setPt(input, energy);
1229}
1230
1232 const double new_energy2 = energy * energy;
1233 const double m = m_accessors->momAcc.m (input);
1234 const double m2 = m * m;
1235 const double p2 = new_energy2 > m2 ? new_energy2 - m2 : 0.;
1236 m_accessors->ptOutDec (input) = sqrt(p2) / cosh(m_accessors->etaAcc (input));
1237 ATH_MSG_DEBUG("after setting pt, energy = " << m_accessors->momAcc.e (input));
1238}
1239
1241 xAOD::Egamma* p, const xAOD::EventInfo* event_info) {
1242 ANA_CHECK_THROW(applyCorrection(*p, *event_info));
1243 ATH_MSG_DEBUG("returning " << p->e());
1244 return p->e();
1245}
1246
1258
1267
1269 const xAOD::Electron* el, const xAOD::EventInfo* event_info) {
1272 ? m_simulation
1274
1275 const xAOD::TrackParticle* eTrack = el->trackParticle();
1276
1277 // track momentum and eta
1278 const float el_tracketa = eTrack->eta();
1279 const float el_trackmomentum = eTrack->pt() * cosh(el->eta());
1280
1281 return m_rootTool->getCorrectedMomentum(
1282 dataType, PATCore::ParticleType::Electron, el_trackmomentum, el_tracketa,
1283 oldtool_scale_flag_this_event(*el, *event_info), m_varSF);
1284}
1285
1287 const CP::SystematicVariation& systematic) const {
1289 return sys.find(systematic) != sys.end();
1290}
1291
1293 const {
1294 CP::SystematicSet affecting_systematics;
1295 for (const auto& it : m_syst_description) {
1296 affecting_systematics.insert(it.first);
1297 }
1298 for (const auto& it : m_syst_description_resolution) {
1299 affecting_systematics.insert(it.first);
1300 }
1301
1302 return affecting_systematics;
1303}
1304
1306 const EgammaPredicate always = [](const EgammaCalibrationAndSmearingTool&, columnar::EgammaId) { return true; };
1307
1308 // Try to simplify a bit for the ones that are fully correlate in eta,
1309 // whatever the model and that are not included in the macros including
1310 // - ADC non linearity
1311 // - L2Gain
1312 // - Leakage
1313 // - Conversion related
1314 // - TopoCluster threshold
1315 // - AF2
1316 // - PS_BARREL_B12
1317 // - S12EXTRALASTETABINRUN2
1318 // - ZEESTAT
1319 // - Run3 pre OFC + EXTRA
1320 if (m_decorrelation_model_scale == ScaleDecorrelation::FULL_ETA_CORRELATED ||
1321 m_decorrelation_model_scale == ScaleDecorrelation::FULL) {
1322 // Electron leakage, ADCLin, convReco only in final run2 recommendations
1326 // systematic related to ADC non linearity correction. Before 2022, there
1327 // was not correction, nor related systematic
1329 m_syst_description[CP::SystematicVariation("EG_SCALE_ADCLIN", +1)] =
1331 m_syst_description[CP::SystematicVariation("EG_SCALE_ADCLIN", -1)] =
1333 }
1334 // Gain splitted uncertainty
1335 m_syst_description[CP::SystematicVariation("EG_SCALE_L2MEDIUMGAIN", +1)] =
1337 m_syst_description[CP::SystematicVariation("EG_SCALE_L2MEDIUMGAIN", -1)] =
1339 m_syst_description[CP::SystematicVariation("EG_SCALE_L2LOWGAIN", +1)] =
1341 m_syst_description[CP::SystematicVariation("EG_SCALE_L2LOWGAIN", -1)] =
1343
1344 // Electron leakage
1345 m_syst_description[CP::SystematicVariation("EG_SCALE_LEAKAGEELEC", +1)] =
1347 m_syst_description[CP::SystematicVariation("EG_SCALE_LEAKAGEELEC", -1)] =
1349
1350 // Conversion related
1351 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVRECO", +1)] =
1353 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVRECO", -1)] =
1355 }
1356 // The equivalent of convReco (convefficiency and convfakerate) for other
1357 // models
1358 else {
1359 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVEFFICIENCY",
1360 +1)] =
1362 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVEFFICIENCY",
1363 -1)] =
1365 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVFAKERATE", +1)] =
1367 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVFAKERATE", -1)] =
1369 }
1370
1371 // additional systematics for R22 OFC and MC21 pre and bulk
1373 m_syst_description[CP::SystematicVariation("EG_SCALE_OFC", +1)] =
1375 m_syst_description[CP::SystematicVariation("EG_SCALE_OFC", -1)] =
1377
1378 m_syst_description[CP::SystematicVariation("EG_SCALE_EXTRARUN3PRE", +1)] =
1380 m_syst_description[CP::SystematicVariation("EG_SCALE_EXTRARUN3PRE", -1)] =
1382 }
1383
1394
1395 // topo clustr threshold systematics aded to release 21 recommendations
1396 m_syst_description[CP::SystematicVariation("EG_SCALE_TOPOCLUSTER_THRES",
1397 +1)] =
1399 m_syst_description[CP::SystematicVariation("EG_SCALE_TOPOCLUSTER_THRES",
1400 -1)] =
1402
1403 // AF3 for run3 models: es2022_R22_PRE and esmodel >= es2023_R22_Run2_v1
1404 // although we prevent AF for es2022_R22_PRE and es2024_Run3_ofc0_v0
1405 // AF3 are still technically added in the tool
1406 // but normally uncertainty will be 0
1408 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", +1)] =
1410 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", -1)] =
1412 }
1413 else {
1414 // and extra AF2 systematics for release 21 recommendations - Moriond 2018
1415 // - pending proper AF2 to FullSim correction with release 21
1416 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", +1)] =
1418 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", -1)] =
1420 }
1421 }
1422
1423 // PS correlated barrel uncertainty
1432 m_syst_description[CP::SystematicVariation("EG_SCALE_PS_BARREL_B12",
1433 +1)] =
1435 m_syst_description[CP::SystematicVariation("EG_SCALE_PS_BARREL_B12",
1436 -1)] =
1438 }
1439
1440 // additional systematic for S12 last eta bin run2
1446 "EG_SCALE_S12EXTRALASTETABINRUN2", +1)] =
1449 "EG_SCALE_S12EXTRALASTETABINRUN2", -1)] =
1451 }
1452
1453 // Zee stat, if for FULL we do not ask for m_use_full_statistical_error
1455 ScaleDecorrelation::FULL_ETA_CORRELATED or
1457 // return 1 variation only, fully correlated in eta, equal to the correct
1458 // value but scaled by sqrt(number of bins) the scaling is done by the old
1459 // tool
1460 m_syst_description[CP::SystematicVariation("EG_SCALE_ZEESTAT", +1)] =
1462 m_syst_description[CP::SystematicVariation("EG_SCALE_ZEESTAT", -1)] =
1464 }
1465 }
1466 if (m_decorrelation_model_scale == ScaleDecorrelation::ONENP) {
1467 // TODO: independet implementation of ALL UP looping on all the variations
1468 m_syst_description[CP::SystematicVariation("EG_SCALE_ALL", +1)] =
1470 m_syst_description[CP::SystematicVariation("EG_SCALE_ALL", -1)] =
1472
1473 // to be consistent with other schemes, we add
1474 // extra AF systematics in addition to the 1NP
1481 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", +1)] =
1483 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", -1)] =
1485 }
1487 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", +1)] =
1489 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", -1)] =
1491 }
1492 }
1493 else if (m_decorrelation_model_scale ==
1494 ScaleDecorrelation::FULL_ETA_CORRELATED) {
1495// all the physical effects separately, considered as fully correlated in eta
1497#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1498 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1499 SysInfo{always, flagup}; \
1500 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1501 SysInfo{always, flagdown};
1502#include "ElectronPhotonFourMomentumCorrection/systematics_es2024_Run3_v0.def"
1503#undef SYSMACRO
1504 }
1505 else {
1506// common systematics for all the esmodels
1507#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1508 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1509 SysInfo{always, flagup}; \
1510 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1511 SysInfo{always, flagdown};
1512#include "ElectronPhotonFourMomentumCorrection/systematics_S12_2022.def"
1513#undef SYSMACRO
1514 }
1515
1519 m_syst_description[CP::SystematicVariation("EG_SCALE_LARCALIB", +1)] =
1521 m_syst_description[CP::SystematicVariation("EG_SCALE_LARCALIB", -1)] =
1523 m_syst_description[CP::SystematicVariation("EG_SCALE_L2GAIN", +1)] =
1525 m_syst_description[CP::SystematicVariation("EG_SCALE_L2GAIN", -1)] =
1527 }
1528
1529 // additional systematics for S12 run2
1540 "EG_SCALE_LARCALIB_EXTRA2015PRE", +1)] =
1543 "EG_SCALE_LARCALIB_EXTRA2015PRE", -1)] =
1545 }
1546
1547 // additional systematics for temperature run1->run2
1554 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE", +1)] =
1557 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE", -1)] =
1559 }
1560
1561 // additional systematic for temperature 2015->2016
1564 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE", +1)] =
1567 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE", -1)] =
1569 }
1570
1571 // additional systematic for PP0 region
1587 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0", +1)] =
1589 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0", -1)] =
1591 }
1592
1593 // systematic related to wtots1
1609 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", +1)] =
1611 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", -1)] =
1613 }
1614
1615 // systematic for the scintillators
1634 // scintillator systematics
1635 m_syst_description[CP::SystematicVariation("EG_SCALE_E4SCINTILLATOR",
1636 +1)] =
1638 m_syst_description[CP::SystematicVariation("EG_SCALE_E4SCINTILLATOR",
1639 -1)] =
1641 }
1642
1643 } else if (m_decorrelation_model_scale ==
1644 ScaleDecorrelation::ONENP_PLUS_UNCONR) {
1645// qsum of all variations correlated 8/13 TeV + uncorrelated (additional
1646// systematics for 2015PRE or 2016) all the physical effects separately,
1647// considered as fully correlated in eta
1648// TODO: fix for es2017
1649#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1650 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1651 SysInfo{always, flagup}; \
1652 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1653 SysInfo{always, flagdown};
1654#include "ElectronPhotonFourMomentumCorrection/systematics_1NPCOR_PLUS_UNCOR.def"
1655#undef SYSMACRO
1656
1657 // additional systematic for S12 last eta bin run2 - not needed anymore for
1658 // last 20.7 model since it is part of bin per bin E1/E2 uncertainty in root
1659 // file
1664 "EG_SCALE_S12EXTRALASTETABINRUN2", +1)] =
1667 "EG_SCALE_S12EXTRALASTETABINRUN2", -1)] =
1669 }
1670
1671 } else if (m_decorrelation_model_scale == ScaleDecorrelation::FULL) {
1672 using pairvector = std::vector<std::pair<double, double>>;
1673 const pairvector decorrelation_bins_BE = {{0., 1.45}, {1.52, 2.5}};
1674 const std::vector<double> decorrelation_edges_TWELVE = {
1675 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};
1676 std::vector<double> decorrelation_edges_MODULE = {
1677 0., 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.37, 1.52, 1.8};
1678 const std::vector<double> decorrelation_edges_MATERIAL = {0.0, 1.1, 1.5,
1679 2.1, 2.5};
1680 std::vector<double> decorrelation_edges_S12_EXTRARUN3 = {
1681 0., 0.8, 1.5, 2.5};
1682
1683 std::vector<double> decorrelation_edges_S12;
1684 // for es2018_R21_v1 : 4 eta bins for muon E1/E2 uncertainty correlation
1686 decorrelation_edges_S12.resize(5);
1687 decorrelation_edges_S12 = {0., 1.35, 1.5, 2.4, 2.5};
1691 decorrelation_edges_S12.resize(8);
1692 decorrelation_edges_S12 = {0., 0.6, 1.0, 1.35, 1.5, 1.8, 2.4, 2.5};
1693 //
1694 // PS scale from muons, so "crack" is a bit different
1695 decorrelation_edges_MODULE[7] = 1.4;
1696 decorrelation_edges_MODULE[8] = 1.5;
1697 }
1698 // for previous run 2 muon calibration with 20.7, 5 eta bins for E1/E2
1699 // uncertainty correlation
1700 else {
1701 decorrelation_edges_S12.resize(6);
1702 decorrelation_edges_S12 = {0., 0.6, 1.4, 1.5, 2.4, 2.5};
1703 }
1704
1716#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1717 if (bool(fullcorrelated)) { \
1718 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1719 SysInfo{always, flagup}; \
1720 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1721 SysInfo{always, flagdown}; \
1722 } else { \
1723 int i = 0; \
1724 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1725 m_syst_description[CP::SystematicVariation( \
1726 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1727 m_syst_description[CP::SystematicVariation( \
1728 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1729 i += 1; \
1730 } \
1731 }
1732#include "ElectronPhotonFourMomentumCorrection/systematics.def"
1733#undef SYSMACRO
1736#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1737 if (bool(fullcorrelated)) { \
1738 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1739 SysInfo{always, flagup}; \
1740 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1741 SysInfo{always, flagdown}; \
1742 } else { \
1743 int i = 0; \
1744 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1745 m_syst_description[CP::SystematicVariation( \
1746 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1747 m_syst_description[CP::SystematicVariation( \
1748 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1749 i += 1; \
1750 } \
1751 }
1752#include "ElectronPhotonFourMomentumCorrection/systematics_S12_2022.def"
1753#undef SYSMACRO
1755#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1756 if (bool(fullcorrelated)) { \
1757 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1758 SysInfo{always, flagup}; \
1759 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1760 SysInfo{always, flagdown}; \
1761 } else { \
1762 int i = 0; \
1763 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1764 m_syst_description[CP::SystematicVariation( \
1765 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1766 m_syst_description[CP::SystematicVariation( \
1767 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1768 i += 1; \
1769 } \
1770 }
1771#include "ElectronPhotonFourMomentumCorrection/systematics_es2024_Run3_v0.def"
1772#undef SYSMACRO
1773 } else {
1774#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1775 if (bool(fullcorrelated)) { \
1776 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1777 SysInfo{always, flagup}; \
1778 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1779 SysInfo{always, flagdown}; \
1780 } else { \
1781 int i = 0; \
1782 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1783 m_syst_description[CP::SystematicVariation( \
1784 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1785 m_syst_description[CP::SystematicVariation( \
1786 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1787 i += 1; \
1788 } \
1789 }
1790#include "ElectronPhotonFourMomentumCorrection/systematics_S12.def"
1791#undef SYSMACRO
1792 } // else
1793
1795 // statistical error, decorrelate in *all* the bins
1796 int i = 0;
1797 const TAxis& axis_statistical_error(m_rootTool->get_ZeeStat_eta_axis());
1798 for (int ibin = 1; ibin <= axis_statistical_error.GetNbins(); ++ibin) {
1799 auto p = EtaCaloPredicateFactory(
1800 axis_statistical_error.GetBinLowEdge(ibin),
1801 axis_statistical_error.GetBinLowEdge(ibin + 1));
1803 "EG_SCALE_ZEESTAT__ETABIN" + std::to_string(i), +1)] =
1806 "EG_SCALE_ZEESTAT__ETABIN" + std::to_string(i), -1)] =
1808 ++i;
1809 }
1810 }
1811
1812 // additional systematics for S12 run2
1823 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN0", +1)] =
1827 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN0", -1)] =
1831 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN1", +1)] =
1832 SysInfo{AbsEtaCaloPredicateFactory({1.45, 2.47}),
1835 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN1", -1)] =
1836 SysInfo{AbsEtaCaloPredicateFactory({1.45, 2.47}),
1839 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN2", +1)] =
1843 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN2", -1)] =
1846 }
1847
1848 // additional systematics for temperature run1->run2
1855 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN0", +1)] =
1856 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1859 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN0", -1)] =
1860 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1863 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN1", +1)] =
1864 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1867 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN1", -1)] =
1868 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1870 }
1871
1872 // additional systematic for temperature 2015->2016
1875 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN0", +1)] =
1876 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1879 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN1", +1)] =
1880 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1883 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN0", -1)] =
1884 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1887 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN1", -1)] =
1888 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1890 }
1891
1892 // additional systematic for PP0 region
1908 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN0",
1909 +1)] = SysInfo{
1911 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN1",
1912 +1)] = SysInfo{
1914 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN0",
1915 -1)] = SysInfo{
1917 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN1",
1918 -1)] =
1921 }
1922
1923 // systematic related to wtots1
1936 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", +1)] =
1938 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", -1)] =
1940 }
1941
1942 // systematic related to wtots1, decorrelate eta bin [1.52,1.82] from rest
1946 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN0",
1947 +1)] =
1948 SysInfo{DoubleOrAbsEtaCaloPredicate(0, 1.52, 1.82, 2.47),
1950 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN0",
1951 -1)] =
1952 SysInfo{DoubleOrAbsEtaCaloPredicate(0, 1.52, 1.82, 2.47),
1954 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN1",
1955 +1)] =
1956 SysInfo{AbsEtaCaloPredicateFactory({1.52, 1.82}),
1958 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN1",
1959 -1)] =
1960 SysInfo{AbsEtaCaloPredicateFactory({1.52, 1.82}),
1962 }
1963
1964 // systematic for the scintillators
1984 "EG_SCALE_E4SCINTILLATOR__ETABIN0", +1)] =
1988 "EG_SCALE_E4SCINTILLATOR__ETABIN1", +1)] =
1992 "EG_SCALE_E4SCINTILLATOR__ETABIN2", +1)] =
1996 "EG_SCALE_E4SCINTILLATOR__ETABIN0", -1)] =
2000 "EG_SCALE_E4SCINTILLATOR__ETABIN1", -1)] =
2004 "EG_SCALE_E4SCINTILLATOR__ETABIN2", -1)] =
2007 if (m_TESModel == egEnergyCorr::es2024_Run3_v0) { // extended E4 in Run 3
2009 "EG_SCALE_E4SCINTILLATOR__ETABIN3", +1)] =
2013 "EG_SCALE_E4SCINTILLATOR__ETABIN3", -1)] =
2016 }
2017 }
2018 } else {
2019 ATH_MSG_FATAL("scale decorrelation model invalid");
2020 }
2021
2022 // resolution systematics
2024 // ALL will not include AF2/AF3 systematic
2025 // individual AF NP is always provided
2026 // linghua.guo@cern.ch 2025-04-23
2028 "EG_RESOLUTION_ALL", +1)] = egEnergyCorr::Resolution::AllUp;
2030 "EG_RESOLUTION_ALL", -1)] = egEnergyCorr::Resolution::AllDown;
2034 "EG_RESOLUTION_ZSMEARING", +1)] = egEnergyCorr::Resolution::ZSmearingUp;
2036 "EG_RESOLUTION_ZSMEARING", -1)] =
2039 "EG_RESOLUTION_SAMPLINGTERM", +1)] =
2042 "EG_RESOLUTION_SAMPLINGTERM", -1)] =
2045 "EG_RESOLUTION_MATERIALID", +1)] =
2048 "EG_RESOLUTION_MATERIALID", -1)] =
2051 "EG_RESOLUTION_MATERIALCALO", +1)] =
2054 "EG_RESOLUTION_MATERIALCALO", -1)] =
2057 "EG_RESOLUTION_MATERIALGAP", +1)] =
2060 "EG_RESOLUTION_MATERIALGAP", -1)] =
2063 "EG_RESOLUTION_MATERIALCRYO", +1)] =
2066 "EG_RESOLUTION_MATERIALCRYO", -1)] =
2069 "EG_RESOLUTION_PILEUP", +1)] = egEnergyCorr::Resolution::PileUpUp;
2071 "EG_RESOLUTION_PILEUP", -1)] = egEnergyCorr::Resolution::PileUpDown;
2088 "EG_RESOLUTION_MATERIALIBL", +1)] =
2091 "EG_RESOLUTION_MATERIALIBL", -1)] =
2094 "EG_RESOLUTION_MATERIALPP0", +1)] =
2097 "EG_RESOLUTION_MATERIALPP0", -1)] =
2099
2100 if (m_TESModel == egEnergyCorr::es2022_R22_PRE) { // exta sys. for Run-3
2101 // pre-recommendations
2103 "EG_RESOLUTION_OFC", +1)] = egEnergyCorr::Resolution::OFCUp;
2105 "EG_RESOLUTION_OFC", -1)] = egEnergyCorr::Resolution::OFCDown;
2106 }
2107 }
2108 } else {
2109 ATH_MSG_FATAL("resolution decorrelation model invalid");
2110 }
2111
2112 // Always use individual AF2/AF3 systematics for resolution
2118 "EG_RESOLUTION_AF2", +1)] = egEnergyCorr::Resolution::afUp;
2120 "EG_RESOLUTION_AF2", -1)] = egEnergyCorr::Resolution::afDown;
2121 }
2124 "EG_RESOLUTION_AF3", +1)] = egEnergyCorr::Resolution::afUp;
2126 "EG_RESOLUTION_AF3", -1)] = egEnergyCorr::Resolution::afDown;
2127 }
2128
2129 // ep combination systematics
2131 m_syst_description[CP::SystematicVariation("EL_SCALE_MOMENTUM", +1)] =
2133 m_syst_description[CP::SystematicVariation("EL_SCALE_MOMENTUM", -1)] =
2135 }
2136}
2137
2142
2144 const CP::SystematicSet& systConfig) {
2145
2146 // set the nominal one (no systematics)
2156
2157 if (systConfig.empty())
2158 return StatusCode::SUCCESS;
2159
2160 // the following code allows only ONE systematic variation at a time (1 for
2161 // scale, 1 for resolution)
2162
2163 bool first_scale = true;
2164 bool first_resolution = true;
2165 for (const auto& it : systConfig) {
2166 const auto found_scale = m_syst_description.find(it);
2167 if (found_scale != m_syst_description.end()) {
2168 if (not first_scale) {
2169 ATH_MSG_ERROR("multiple scale variations not supported");
2170 throw std::runtime_error("multiple scale variations not supported");
2171 }
2172 first_scale = false;
2173 m_currentScaleVariation_MC = found_scale->second.effect;
2174 m_currentScalePredicate = found_scale->second.predicate;
2175 }
2176
2177 const auto found_resolution = m_syst_description_resolution.find(it);
2178 if (found_resolution != m_syst_description_resolution.end()) {
2179 if (not first_resolution) {
2180 ATH_MSG_ERROR("multiple resolution variations not supported");
2181 throw std::runtime_error(
2182 "multiple resolution variations not supported");
2183 }
2184 first_resolution = false;
2185 m_currentResolutionVariation_MC = found_resolution->second;
2186 }
2187 }
2188
2189 return StatusCode::SUCCESS;
2190}
2191
2193 double Ecl, double phi, double eta) const {
2194
2195 // Intermodule Widening Correction: E_corr = E / (a' - b' * ((1 / (1 +
2196 // exp((phi_mod - 2 * pi / 32) * c))) * (1 / (1 + exp((phi_mod - 2 * pi / 32)
2197 // * (d)))))) (phi_min, phi_max) : [a' = a / a, b' = b / a, c, d]
2198
2199 double Ecl_corr = 0.;
2200 int DivInt = 0;
2201 double pi = M_PI;
2202
2215
2216 double phi_mod = 0;
2217 if (phi < 0)
2218 phi_mod = fmod(phi, 2 * pi / 16.) + pi / 8.;
2219 else
2220 phi_mod = fmod(phi, 2 * pi / 16.);
2221
2222 // The correction concerns only the barrel
2223 if (std::abs(eta) <= 1.37) {
2224
2225 if (phi < (-7 * pi / 8) && phi > (-1 * pi))
2226 Ecl_corr =
2227 Ecl /
2228 (1 - 0.1086 *
2229 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 175.2759))) *
2230 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-189.3612))))));
2231 if (phi < (-6 * pi / 8) && phi > (-7 * pi / 8))
2232 Ecl_corr =
2233 Ecl /
2234 (1 - 0.0596 *
2235 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 170.8305))) *
2236 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-233.3782))))));
2237 if (phi < (-5 * pi / 8) && phi > (-6 * pi / 8))
2238 Ecl_corr =
2239 Ecl /
2240 (1 - 0.0596 *
2241 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 147.1451))) *
2242 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-139.3386))))));
2243 if (phi < (-4 * pi / 8) && phi > (-5 * pi / 8))
2244 Ecl_corr =
2245 Ecl /
2246 (1 - 0.0583 *
2247 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 168.4644))) *
2248 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-246.2897))))));
2249 if (phi < (-3 * pi / 8) && phi > (-4 * pi / 8))
2250 Ecl_corr =
2251 Ecl /
2252 (1 - 0.0530 *
2253 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 177.6703))) *
2254 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-198.3227))))));
2255 if (phi < (-2 * pi / 8) && phi > (-3 * pi / 8))
2256 Ecl_corr =
2257 Ecl /
2258 (1 - 0.0672 *
2259 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 145.0693))) *
2260 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-242.1771))))));
2261 if (phi < (-1 * pi / 8) && phi > (-2 * pi / 8))
2262 Ecl_corr =
2263 Ecl /
2264 (1 - 0.0871 *
2265 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 132.3303))) *
2266 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-166.1833))))));
2267 if (phi < (0 * pi / 8) && phi > (-1 * pi / 8))
2268 Ecl_corr =
2269 Ecl /
2270 (1 - 0.0948 *
2271 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 127.6780))) *
2272 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-150.0700))))));
2273 if (phi < (1 * pi / 8) && phi > (0 * pi / 8))
2274 Ecl_corr =
2275 Ecl /
2276 (1 - 0.1166 *
2277 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 172.0679))) *
2278 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-235.3293))))));
2279 if (phi < (2 * pi / 8) && phi > (1 * pi / 8))
2280 Ecl_corr =
2281 Ecl /
2282 (1 - 0.1172 *
2283 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 190.3524))) *
2284 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-198.9400))))));
2285 if (phi < (3 * pi / 8) && phi > (2 * pi / 8))
2286 Ecl_corr =
2287 Ecl /
2288 (1 - 0.1292 *
2289 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 158.0540))) *
2290 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-165.3893))))));
2291 if (phi < (4 * pi / 8) && phi > (3 * pi / 8))
2292 Ecl_corr =
2293 Ecl /
2294 (1 - 0.1557 *
2295 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 162.2793))) *
2296 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-133.5131))))));
2297 if (phi < (5 * pi / 8) && phi > (4 * pi / 8))
2298 Ecl_corr =
2299 Ecl /
2300 (1 - 0.1659 *
2301 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 180.5270))) *
2302 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-168.5074))))));
2303 if (phi < (6 * pi / 8) && phi > (5 * pi / 8))
2304 Ecl_corr =
2305 Ecl /
2306 (1 - 0.1123 *
2307 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 128.2277))) *
2308 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-154.4455))))));
2309 if (phi < (7 * pi / 8) && phi > (6 * pi / 8))
2310 Ecl_corr =
2311 Ecl /
2312 (1 - 0.1394 *
2313 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 192.1216))) *
2314 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-198.0727))))));
2315 if (phi < (8 * pi / 8) && phi > (7 * pi / 8))
2316 Ecl_corr =
2317 Ecl /
2318 (1 - 0.1001 *
2319 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 199.1735))) *
2320 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-176.4056))))));
2321 }
2322
2323 // No correction for the EC
2324 else {
2325 Ecl_corr = Ecl;
2326 }
2327
2328 }
2329
2330 else {
2331
2332 // Definitions of module folding into four quarters (top, left, bottom and
2333 // right)
2334
2335 DivInt = (int)(phi / ((2 * pi) / 16.));
2336 double phi_mod = phi - DivInt * (2 * pi / 16.);
2337
2338 // Centring on the intermodule --> phi_mod will now be in [0,0.4]
2339 if (phi_mod < 0)
2340 phi_mod += pi / 8.;
2341
2342 // The correction concerns only the barrel
2343 if (std::abs(eta) <= 1.4) {
2344
2345 // Top quarter
2346 if (phi < (3 * pi) / 4. && phi >= pi / 4.) {
2347 Ecl_corr =
2348 Ecl / (1 - 0.131 * ((1 / (1 + exp((phi_mod - 0.2) * 199.08))) *
2349 (1 / (1 + exp((phi_mod - 0.2) * (-130.36))))));
2350 }
2351
2352 // Right quarter
2353 if (phi < pi / 4. && phi >= -pi / 4.) {
2354 Ecl_corr =
2355 Ecl / (1 - 0.0879 * ((1 / (1 + exp((phi_mod - 0.2) * 221.01))) *
2356 (1 / (1 + exp((phi_mod - 0.2) * (-149.51))))));
2357 }
2358 // Bottom quarter
2359 if (phi < -pi / 4. && phi >= (-3 * pi) / 4.) {
2360 Ecl_corr =
2361 Ecl / (1 - 0.0605 * ((1 / (1 + exp((phi_mod - 0.2) * 281.37))) *
2362 (1 / (1 + exp((phi_mod - 0.2) * (-170.29))))));
2363 }
2364 // Left quarter
2365 if ((phi < (-3 * pi) / 4.) || (phi >= (3 * pi) / 4.)) {
2366 Ecl_corr =
2367 Ecl / (1 - 0.102 * ((1 / (1 + exp((phi_mod - 0.2) * 235.37))) *
2368 (1 / (1 + exp((phi_mod - 0.2) * (-219.04))))));
2369 }
2370 }
2371
2372 // No correction for the EC
2373 else {
2374 Ecl_corr = Ecl;
2375 }
2376 }
2377
2378 return Ecl_corr;
2379}
2380
2382 double phi) const {
2383 constexpr double PI = M_PI;
2384 double Fcorr = 1.0;
2385
2387 // wrong mapping HV -> sectors in run1
2388 if (eta < -0.4 && eta > -0.6) {
2389 if (phi < (14 * PI / 32.) && phi > (13 * PI / 32.)) {
2390 Fcorr += 0.035;
2391 } else if (phi < (13 * PI / 32.) && phi > (12 * PI / 32.)) {
2392 Fcorr -= 0.035;
2393 }
2394 }
2395 }
2396
2409
2410 if (eta < 0.2 && eta > 0.) {
2411 if (phi < (-7 * 2 * PI / 32.) && phi > (-8 * 2 * PI / 32.)) {
2412 Fcorr = 1.016314;
2413 }
2414 }
2415
2416 else if (eta < 0.6 && eta > 0.4) {
2417 if (phi < 0 && phi > (-2 * PI / 32.)) {
2418 Fcorr = 1.041591;
2419 } else if (phi < (-4 * 2 * PI / 32.) && phi > (-5 * 2 * PI / 32.)) {
2420 Fcorr = 1.067346;
2421 }
2422 }
2423
2424 else if (eta < 0.8 && eta > 0.6) {
2425 if (phi < (7 * 2 * PI / 32.) && phi > (6 * 2 * PI / 32.)) {
2426 Fcorr = 1.027980;
2427 }
2428 }
2429
2430 else if (eta < 1.4 && eta > 1.2) {
2431 if (phi < (-9 * 2 * PI / 32.) && phi > (-10 * 2 * PI / 32.)) {
2432 Fcorr = 1.020299;
2433 } else if (phi < (-11 * 2 * PI / 32.) && phi > (-12 * 2 * PI / 32.)) {
2434 Fcorr = 1.051426;
2435 }
2436 }
2437
2438 else if (eta < 2.3 && eta > 2.1) {
2439 if (phi < (-12 * 2 * PI / 32.) && phi > (-13 * 2 * PI / 32.)) {
2440 Fcorr = 1.071695;
2441 }
2442 }
2443
2444 else if (eta < 0. && eta > -0.2) {
2445 if (phi < (-12 * 2 * PI / 32.) && phi > (-13 * 2 * PI / 32.)) {
2446 Fcorr = 1.008227;
2447 } else if (phi < (-8 * 2 * PI / 32.) && phi > (-9 * 2 * PI / 32.)) {
2448 Fcorr = 1.013929;
2449 }
2450 }
2451
2452 else if (eta < -0.2 && eta > -0.4) {
2453 if (phi < (-9 * 2 * PI / 32.) && phi > (-10 * 2 * PI / 32.)) {
2454 Fcorr = 1.015749;
2455 }
2456 }
2457
2458 else if (eta < -1.2 && eta > -1.4) {
2459 if (phi < (-6 * 2 * PI / 32.) && phi > (-7 * 2 * PI / 32.)) {
2460 Fcorr = 1.064954;
2461 }
2462 }
2463
2464 else if (eta < -1.6 && eta > -1.8) {
2465 if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2466 Fcorr = 1.027448;
2467 }
2468 }
2469
2470 else if (eta < -2.3 && eta > -2.5) {
2471 if (phi < (-8 * 2 * PI / 32.) && phi > (-9 * 2 * PI / 32.)) {
2472 Fcorr = 1.025882;
2473 } else if (phi < (5 * 2 * PI / 32.) && phi > (4 * 2 * PI / 32.)) {
2474 Fcorr = 1.036616;
2475 } else if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2476 Fcorr = 1.053838;
2477 } else if (phi < (10 * 2 * PI / 32.) && phi > (9 * 2 * PI / 32.)) {
2478 Fcorr = 1.026856;
2479 } else if (phi < (11 * 2 * PI / 32.) && phi > (10 * 2 * PI / 32.)) {
2480 Fcorr = 0.994382;
2481 }
2482 }
2483
2484 } // es2017_summer_improved end
2485
2486 else {
2487 if (eta < 0.6 && eta > 0.4) {
2488 if (phi < 0 && phi > (-2 * PI / 32.)) {
2489 Fcorr = 1.028;
2490 } else if (phi < (-4 * 2 * PI / 32.) && phi > (-5 * 2 * PI / 32.)) {
2491 Fcorr = 1.044;
2492 }
2493 }
2494
2495 else if (eta < 0.8 && eta > 0.6) {
2496 if (phi < (7 * 2 * PI / 32.) && phi > (6 * 2 * PI / 32.)) {
2497 Fcorr = 1.022;
2498 }
2499 }
2500
2501 else if (eta < 1.4 && eta > 1.2) {
2502 if (phi < (-11 * 2 * PI / 32.) && phi > (-12 * 2 * PI / 32.)) {
2503 Fcorr = 1.038;
2504 }
2505 }
2506
2507 else if (eta < 2.0 && eta > 1.9) {
2508 if (phi < (10 * 2 * PI / 32.) && phi > (9 * 2 * PI / 32.)) {
2509 Fcorr = 1.029;
2510 }
2511 }
2512
2513 else if (eta < -1.2 && eta > -1.4) {
2514 if (phi < (-4 * 2 * PI / 32.) && phi > (-5 * 2 * PI / 32.)) {
2515 Fcorr = 1.048;
2516 } else if (phi < (-6 * 2 * PI / 32.) && phi > (-7 * 2 * PI / 32.)) {
2517 Fcorr = 1.048;
2518 }
2519 }
2520
2521 else if (eta < -1.6 && eta > -1.8) {
2522 if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2523 Fcorr = 1.024;
2524 }
2525 }
2526
2527 else if (eta < -2.3 && eta > -2.5) {
2528 if (phi < (-8 * 2 * PI / 32.) && phi > (-9 * 2 * PI / 32.)) {
2529 Fcorr = 1.037;
2530 } else if (phi < (5 * 2 * PI / 32.) && phi > (4 * 2 * PI / 32.)) {
2531 Fcorr = 1.031;
2532 } else if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2533 Fcorr = 1.040;
2534 } else if (phi < (10 * 2 * PI / 32.) && phi > (9 * 2 * PI / 32.)) {
2535 Fcorr = 1.030;
2536 } else if (phi < (11 * 2 * PI / 32.) && phi > (10 * 2 * PI / 32.)) {
2537 Fcorr = 1.020;
2538 }
2539 }
2540 }
2541
2542 return Fcorr;
2543}
2544
2545void EgammaCalibrationAndSmearingTool ::
2546callSingleEvent (columnar::MutableEgammaRange egammas, columnar::EventInfoId event) const
2547{
2548 for (auto egamma : egammas) {
2550 throw std::runtime_error ("EgammaCalibrationAndSmearingTool::callEvents: apply failed");
2551 }
2552}
2553
2554void EgammaCalibrationAndSmearingTool ::
2555callEvents (columnar::EventContextRange events) const
2556{
2557 const Accessors& acc = *m_accessors;
2558 for (auto event : events) {
2559 auto eventInfo = acc.m_eventHandle(event);
2560 callSingleEvent (acc.m_egammaHandle(event), eventInfo);
2561 }
2562}
2563
2564} // 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