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 size_t dot = this->name().find('.');
644 size_t underscore = this->name().rfind('_', dot);
645 std::string collection = "";
646 if (dot != std::string::npos &&
647 underscore != std::string::npos &&
648 underscore < dot)
649 {
650 collection = this->name().substr(underscore + 1, dot - underscore - 1);
651 mva_service_name << "egammaMVASvc/service_mva_egamma_id"
652 << collection;;
653 }
654 else
655 {
656 mva_service_name << "egammaMVASvc/service_mva_egamma_id"
657 << (void const*)this;
658 }
659 asg::AsgServiceConfig config_mva_service(mva_service_name.str());
660 ATH_CHECK(config_mva_service.addPrivateTool("ElectronTool",
661 config_mva_electron));
662 ATH_CHECK(config_mva_service.addPrivateTool("UnconvertedPhotonTool",
663 config_mva_unconverted));
664 ATH_CHECK(config_mva_service.addPrivateTool("ConvertedPhotonTool",
665 config_mva_converted));
666 // fwd electron MVA tool
667 if (m_doFwdCalib) {
668 asg::AsgToolConfig config_mva_fwdelectron(
669 "egammaMVACalibTool/tool_mva_fwdelectron");
670 config_mva_fwdelectron.setPropertyFromString("folder", m_MVAfolder);
671 ATH_CHECK(config_mva_fwdelectron.setProperty(
673 ATH_CHECK(config_mva_fwdelectron.setProperty("ShiftType", 0));
674 ATH_CHECK(config_mva_fwdelectron.setProperty("OutputLevel", this->msg().level()));
675 ATH_CHECK(config_mva_service.addPrivateTool("FwdElectronTool",
676 config_mva_fwdelectron));
677 }
678 config_mva_service.setPropertyFromString("folder", m_MVAfolder);
679 ATH_CHECK(
680 config_mva_service.setProperty("OutputLevel", this->msg().level()));
681 ATH_CHECK(config_mva_service.makeService(m_MVACalibSvc));
684 "WIP: testing GNN based calibration for Run3,"
685 "requring decorated GNN energy (gnn_energy) from input,"
686 "which should already have the layer calibration applied");
687 } else {
688 m_use_mva_calibration = false;
689 }
690 }
691
692 // configure layer recalibration tool
693 // For now: layer recalibration not applied to PRE release 21 (using run 1
694 // based calibration applied at reco level)
695 // for following R21 recommendations, need to apply the run2/run1 layer
696 // calibration ratio
697 if (m_ESModel == "es2017_R21_PRE") {
698 ATH_MSG_INFO("Layer recalibration already applied at cell level");
699 m_useLayerCorrection = false;
700 } else if (!m_useLayerCorrection) {
701 ATH_MSG_INFO("Layer corrections disabled!");
702 } else {
703 ATH_MSG_DEBUG("initializing layer recalibration tool (if needed)");
705 .empty()) { // automatically configure layer recalibration tool
708 .release();
710 ATH_MSG_INFO("not using layer recalibration");
711 }
712 } else {
715 }
717 m_layer_recalibration_tool->msg().setLevel(this->msg().level());
719 if (!m_usePSCorrection) {
720 ATH_MSG_INFO("PS corrections disabled!");
721 m_layer_recalibration_tool->disable_PSCorrections();
722 }
723 if (!m_useS12Correction) {
724 ATH_MSG_INFO("S12 corrections disabled!");
725 m_layer_recalibration_tool->disable_S12Corrections();
726 }
727 if (!m_useSaccCorrection) {
728 ATH_MSG_INFO("Sacc corrections disabled!");
729 m_layer_recalibration_tool->disable_SaccCorrections();
730 }
731 }
732 }
733
735 m_rootTool->use_temp_correction201215(m_use_temp_correction201215);
737 m_rootTool->use_uA2MeV_2015_first2weeks_correction(
740 m_decorrelation_model_scale == ScaleDecorrelation::FULL) {
741 m_rootTool->useStatErrorScaling(true);
742 }
743
745 ATH_MSG_ERROR("ep combination not supported yet");
746 throw std::runtime_error("ep combination not supported yet");
747 }
748
751 }
754 }
756
757 if (m_useGainCorrection == AUTO) {
762 }
763 else {
764 ATH_MSG_DEBUG("initializing gain tool");
767 }
768 }
769 else if (m_useGainCorrection == 1) {
775 "cannot instantiate gain tool for this model (you can only disable "
776 "the gain tool, but not enable it)");
777 }
778 else {
780 "initializing gain tool for run2 final precision recommendations");
782 "Gain corrections required but Zee scales are derived without Gain, "
783 "will cause inconsistency!");
784 std::string gain_tool_run_2_filename = PathResolverFindCalibFile(
785 "ElectronPhotonFourMomentumCorrection/v29/"
786 "gain_uncertainty_specialRun.root");
787 m_gain_tool_run2 = std::make_unique<egGain::GainUncertainty>(
788 gain_tool_run_2_filename, false, "GainCorrection",
790 m_gain_tool_run2->msg().setLevel(this->msg().level());
791 }
792 }
793
798 // ADC non linearity correction
801 std::string adcLinearityCorr_filename = PathResolverFindCalibFile(
802 "ElectronPhotonFourMomentumCorrection/v25/linearity_ADC.root");
803 m_ADCLinearity_tool = std::make_shared<LinearityADC>(adcLinearityCorr_filename);
804 m_ADCLinearity_tool->msg().setLevel(this->msg().level());
805 m_rootTool->setADCTool(m_ADCLinearity_tool);
806 } else {
808 m_ESModel + " recommendations use ADC corrections for scale "
809 "derivation. Disabling the ADCLinearity flag will create "
810 "inconsistency!");
811 }
812
815 m_rootTool->setApplyLeakageCorrection(true);
816 }
817
818 // Calo distortion phi unif correction
822 std::string phiUnifCorrfileName = PathResolverFindCalibFile(
823 "ElectronPhotonFourMomentumCorrection/v33/"
824 "egammaEnergyCorrectionData.root");
825 std::unique_ptr<TFile> fCorr(
826 TFile::Open(phiUnifCorrfileName.c_str(), "READ"));
828 dynamic_cast<TH2*>(fCorr->Get("CaloDistortionPhiUniformityCorrection/"
829 "es2023_R22_Run2_v0/h2DcorrPhiUnif")));
830 m_caloDistPhiUnifCorr->SetDirectory(nullptr);
831 } else {
833 m_ESModel + " recommendations use CaloDistPhiUnif for scale "
834 "derivation. Disabling the CaloDistPhiUnif flag will create "
835 "inconsistency!");
836 }
837 }
838
839 // No scale correction for release 21 ==> obsolete
840 /*if (m_ESModel == "es2017_R21_PRE"){
841 m_doScaleCorrection = 0;
842 }
843 */
844
845 ATH_MSG_INFO("ESModel: " << m_ESModel);
846 ATH_MSG_INFO("ResolutionType: " << m_ResolutionType);
847 ATH_MSG_INFO("decorrelation Model: " << m_decorrelation_model_name);
848 ATH_MSG_DEBUG("layer correction = " << m_useLayerCorrection);
849 ATH_MSG_DEBUG("PS correction = " << m_usePSCorrection);
850 ATH_MSG_DEBUG("S12 correction = " << m_useS12Correction);
851 ATH_MSG_DEBUG("Sacc correction = " << m_useSaccCorrection);
852 ATH_MSG_DEBUG("intermodule correction = " << m_useIntermoduleCorrection);
853 ATH_MSG_DEBUG("phi uniformity correction = " << m_usePhiUniformCorrection);
854 ATH_MSG_DEBUG("distorted calo phi uniformity correction = "
856 ATH_MSG_DEBUG("gain correction = " << m_useGainCorrection);
857 ATH_MSG_DEBUG("ADC non-linearity correction = " << m_doADCLinearityCorrection);
858 ATH_MSG_DEBUG("leakage correction for photons = " << m_doLeakageCorrection);
859 ATH_MSG_DEBUG("smearing = " << m_doSmearing);
860 ATH_MSG_DEBUG("insitu scales = " << m_doScaleCorrection);
861 ATH_MSG_DEBUG("ep combination = " << m_use_ep_combination);
862 ATH_MSG_DEBUG("use MVA calibration = " << m_use_mva_calibration);
864 "use temperature correction 2015 = " << m_use_temp_correction201215);
865 ATH_MSG_DEBUG("use uA2MeV correction 2015 1/2 week = "
867
869
871 .ignore(); // this set the flags for the internal tool without
872 // systematics
874 if (registry.registerSystematics(*this) != StatusCode::SUCCESS)
875 return StatusCode::FAILURE;
876
877 // For columnar, it is important only to set this accessor if it is
878 // needed, as it creates a hard data dependency on the column, which
879 // is not present in older PHYSLITE files, causing the tool to fail.
880 // An alternative would be to mark the column with `isOptional`, but
881 // since it is always required for the GNN calibration (and never
882 // otherwise), declaring it only for the GNN calibration seemed
883 // cleaner.
885 resetAccessor (m_accessors->gnn_energy_Acc, *this, "TransformerEnergy");
886 }
887 if (m_onlyElectrons.value() && m_onlyPhotons.value()) {
888 ATH_MSG_ERROR("Cannot select both onlyElectrons and onlyPhotons");
889 return StatusCode::FAILURE;
890 }
891 if (m_onlyElectrons.value()) {
892 resetElectron (m_accessors->momAcc, *m_accessors);
894 resetAccessor (m_accessors->electronTrackAcc, *this, "trackParticleLinks");
895 }
896 }
897 if (m_onlyPhotons.value()) {
898 resetPhoton (m_accessors->momAcc, *m_accessors);
899 resetAccessor (m_accessors->photonVertexAcc, *this, "vertexLinks");
900 }
901 if (m_decorateEmva)
902 resetAccessor (m_accessors->decEmva, *this, "E_mva_only");
903
904 ANA_CHECK (initializeColumns ());
905
906 return StatusCode::SUCCESS;
907}
908
909
911{
912 const Accessors& acc = *m_accessors;
913
914 // this is departing from the logic below, as we are now requiring the
915 // user to specify at configuration time whether we run on electrons
916 // or photons. this is necessary to configure the columns we need
917 // correctly.
918 if (m_onlyElectrons.value())
919 {
921 }
922 if (m_onlyPhotons.value())
923 {
924 if (acc.photonVertexAcc(particle).size() > 0)
925 {
927 }
928 else
929 {
931 }
932 }
933
934 // this is the old logic and should not be visited in columnar mode
935 // (disabled by turning on onlyElectrons or onlyPhotons)
937 //no ForwardElectron ptype: consider them as Electron
938 if (xAOD::EgammaHelpers::isElectron(&particle.getXAODObject()) || acc.authorAcc (particle) == xAOD::EgammaParameters::AuthorFwdElectron) { ptype = PATCore::ParticleType::Electron; }
939 else if (xAOD::EgammaHelpers::isPhoton(&particle.getXAODObject())) {
940 if (xAOD::EgammaHelpers::isConvertedPhoton(&particle.getXAODObject())) { ptype = PATCore::ParticleType::ConvertedPhoton; }
942 }
943 else {
944 ATH_MSG_ERROR("particle is not electron of photon");
945 throw std::runtime_error("particle is not electron or photon");
946 }
947 return ptype;
948}
949
951 const xAOD::Egamma& particle, bool withCT) const {
952 const auto ptype = xAOD2ptype(particle);
953 const auto cl_etaCalo =
954 xAOD::get_eta_calo(*particle.caloCluster(), particle.author());
955
956 return m_rootTool->resolution(particle.e(), particle.caloCluster()->eta(),
957 cl_etaCalo, ptype, withCT,
958 false); // TODO: always for full simulation
959}
960
962 double energy, double cl_eta, double cl_etaCalo,
963 PATCore::ParticleType::Type ptype, bool withCT) const {
964 return m_rootTool->resolution(energy, cl_eta, cl_etaCalo, ptype, withCT,
965 false);
966}
967
969 xAOD::Egamma& input) const {
970 // Retrieve the event information:
971 const xAOD::EventInfo* event_info = nullptr;
972 if (evtStore()->retrieve(event_info, "EventInfo").isFailure()) {
973 ATH_MSG_ERROR("No EventInfo object could be retrieved");
975 }
976 return applyCorrection(input, *event_info);
977}
978
980 const xAOD::Electron& input, xAOD::Electron*& output) const {
981 // A sanity check:
982 if (output)
984 "Non-null pointer received. "
985 "There's a possible memory leak!");
986
987 output = new xAOD::Electron();
988 output->makePrivateStore(input);
989 return applyCorrection(*output);
990}
991
993 const xAOD::Photon& input, xAOD::Photon*& output) const {
994 // A sanity check:
995 if (output)
997 "Non-null pointer received. "
998 "There's a possible memory leak!");
999
1000 output = new xAOD::Photon();
1001 output->makePrivateStore(input);
1002 return applyCorrection(*output);
1003}
1004
1006 const xAOD::Photon& input) const {
1007 xAOD::Photon* new_particle = nullptr;
1008 ANA_CHECK_THROW(correctedCopy(input, new_particle));
1009 const double e = new_particle->e();
1010 delete new_particle;
1011 return e;
1012}
1013
1015 const xAOD::Electron& input) const {
1016 xAOD::Electron* new_particle = nullptr;
1017 ANA_CHECK_THROW(correctedCopy(input, new_particle));
1018 const double e = new_particle->e();
1019 delete new_particle;
1020 return e;
1021}
1022
1024 columnar::MutableEgammaId input, columnar::EventInfoId event_info) const {
1025 const Accessors& acc = *m_accessors;
1026
1027 // only used in simulation (for the smearing)
1028 RandomNumber seed = m_set_seed_function(*this, input, event_info);
1029
1030 columnar::ClusterId inputCluster = acc.caloClusterAcc (input)[0].value();
1031
1032 if (m_layer_recalibration_tool && acc.authorAcc (input) !=
1034 ATH_MSG_DEBUG("applying energy recalibration before E0|E1|E2|E3 = "
1035 << acc.energyBEAcc (inputCluster, 0) << "|"
1036 << acc.energyBEAcc (inputCluster, 1) << "|"
1037 << acc.energyBEAcc (inputCluster, 2) << "|"
1038 << acc.energyBEAcc (inputCluster, 3));
1039 // for now just go back to the xAOD object to access the subtool
1040 const CP::CorrectionCode status_layer_recalibration = m_layer_recalibration_tool->applyCorrection(input.getXAODObject(), event_info.getXAODObject());
1041 if (status_layer_recalibration == CP::CorrectionCode::Error) { return CP::CorrectionCode::Error; }
1042 ATH_MSG_DEBUG("eta|phi = " << acc.etaAcc (input) << "|" << acc.phiAcc (input));
1043 if (status_layer_recalibration == CP::CorrectionCode::Ok) {
1044 ATH_MSG_DEBUG("decoration E0|E1|E2|E3 = "
1045 << acc.Es0Acc(inputCluster) << "|"
1046 << acc.Es1Acc(inputCluster) << "|"
1047 << acc.Es2Acc(inputCluster) << "|"
1048 << acc.Es3Acc(inputCluster) << "|");
1049 if (acc.Es2Acc(inputCluster) == 0 and acc.Es1Acc(inputCluster) == 0 and
1050 acc.Es3Acc(inputCluster) == 0 and acc.Es0Acc(inputCluster) == 0 and
1051 (std::abs(acc.etaAcc (input)) < 1.37 or (std::abs(acc.etaAcc (input)) > 1.55 and std::abs(acc.etaAcc (input)) < 2.47)))
1052 {
1053 ATH_MSG_WARNING("all layer energies are zero");
1054 }
1055 }
1056 }
1057
1058 double energy = acc.momAcc.e (input);
1059 // apply MVA calibration
1060 if (!m_MVACalibSvc.empty()) {
1062 if (acc.authorAcc (input) ==
1064 const xAOD::VertexContainer* pVtxCont = nullptr;
1065 if (evtStore()->retrieve(pVtxCont, m_pVtxKey).isFailure()) {
1066 ATH_MSG_ERROR("No primary vertex container " << m_pVtxKey << " could be retrieved");
1068 }
1069 unsigned int npv(0);
1070 for (const auto *vtx : *pVtxCont) {
1071 if (vtx->vertexType() == xAOD::VxType::PriVtx ||
1072 vtx->vertexType() == xAOD::VxType::PileUp) { ++npv; }
1073 }
1074 gei.nPV = npv;
1075 gei.acmu = acc.actIntPerXingAcc(event_info);
1076 ATH_MSG_DEBUG("Retrieved nPV = " << gei.nPV << " and mu = " << gei.acmu);
1077 }
1078 if (acc.authorAcc (input) !=
1080 if (m_MVACalibSvc->getEnergy(inputCluster.getXAODObject(), input.getXAODObject(), energy, gei)
1081 .isFailure()) {
1082 ATH_MSG_ERROR("Failure in MVACalib service");
1084 }
1085 ATH_MSG_DEBUG("energy after MVA calibration = " << std::format("{:.2f}", energy));
1086 }
1087 }
1089 // for now assume the input has already the layer calibration applied
1090 // and just take the decorated gnn_energy
1091 if (!acc.gnn_energy_Acc.isAvailable(input)) {
1092 ATH_MSG_ERROR("GNN energy requested but decoration TransformerEnergy not found");
1094 }
1095 energy = acc.gnn_energy_Acc(input);
1096 ATH_MSG_DEBUG("energy after GNN calibration = " << std::format("{:.2f}", energy));
1097
1098 }
1099 if (m_decorateEmva)
1100 {
1101 acc.decEmva(input) = energy;
1102 }
1103
1104 // For the time being, it is just the MVA calib
1105 if (acc.authorAcc (input) ==
1107 setPt(input, energy);
1109 }
1110
1112 // Crack calibation correction for es2011c (calibration hits calibration)
1113 const auto ptype = xAOD2ptype(input);
1114 const double etaden =
1116 ? static_cast<const xAOD::Electron&>(input.getXAODObject()).trackParticle()->eta()
1117 : acc.clusterEtaAcc(inputCluster);
1118 energy *= m_rootTool->applyMCCalibration(acc.clusterEtaAcc(inputCluster),
1119 energy / cosh(etaden), ptype);
1120 ATH_MSG_DEBUG("energy after crack calibration es2011c = "
1121 << std::format("{:.2f}", energy));
1122 }
1123
1124 /*
1125 * Here we check for each event the kind of data DATA vs FullSim
1126 * The m_simulation flavour has already been configured
1127 */
1129 (acc.eventTypeAcc(event_info,xAOD::EventInfo::IS_SIMULATION))
1130 ? m_simulation
1132
1133 unsigned int runNumber_for_tool = 0;
1134
1135 // apply uniformity corrections to data
1136 if (dataType == PATCore::ParticleDataType::Data) {
1137 // Get run number
1138 runNumber_for_tool = acc.runNumberAcc(event_info);
1139 // Get etaCalo, phiCalo
1140 const auto cl_eta = acc.clusterEtaAcc(inputCluster);
1141 double etaCalo = 0, phiCalo = 0;
1143 etaCalo = acc.etaCaloAcc(inputCluster, acc.authorAcc(input), false);
1145 phiCalo =
1146 acc.phiCaloAcc(inputCluster, acc.authorAcc(input), false);
1147 }
1148 }
1149
1150 // Intermodule
1152 energy =
1153 intermodule_correction(energy, acc.clusterPhiAcc(inputCluster), cl_eta);
1154 ATH_MSG_DEBUG("energy after intermodule correction = "
1155 << std::format("{:.2f}", energy));
1156 }
1157
1158 // Calo distortion
1164 double etaC = acc.clusterEtaAcc(inputCluster);
1165 double phiC = acc.clusterPhiAcc(inputCluster);
1166 int ieta = m_caloDistPhiUnifCorr->GetXaxis()->FindBin(etaC);
1167 ieta = ieta == 0 ? 1
1168 : (ieta > m_caloDistPhiUnifCorr->GetNbinsX()
1169 ? m_caloDistPhiUnifCorr->GetNbinsX()
1170 : ieta);
1171 int iphi = m_caloDistPhiUnifCorr->GetYaxis()->FindBin(phiC);
1172 iphi = iphi == 0 ? 1
1173 : (iphi > m_caloDistPhiUnifCorr->GetNbinsY()
1174 ? m_caloDistPhiUnifCorr->GetNbinsY()
1175 : iphi);
1176 energy *= m_caloDistPhiUnifCorr->GetBinContent(ieta, iphi);
1178 "energy after phi uniformity correction (for calo distortion) = "
1179 << std::format("{:.2f}", energy));
1180 }
1181
1182 // Phi
1184 energy *= correction_phi_unif(etaCalo, phiCalo);
1185 ATH_MSG_DEBUG("energy after uniformity correction = "
1186 << std::format("{:.2f}", energy));
1187 }
1188
1189 // ADC
1190 if (m_ADCLinearity_tool) {
1191 double et = energy / std::cosh(cl_eta);
1192 double corr =
1193 m_ADCLinearity_tool->getCorr(etaCalo, et, xAOD2ptype(input));
1194 energy *= corr;
1195 ATH_MSG_DEBUG("energy after ADC linearity correction = "
1196 << std::format("{:.2f}", energy));
1197 }
1198
1199 // Gain
1200 if (m_gain_tool) {
1201 const auto es2 = acc.Es2Acc.isAvailable(inputCluster)
1202 ? acc.Es2Acc(inputCluster)
1203 : acc.energyBEAcc (inputCluster,2);
1204 if (!(std::abs(cl_eta) < 1.52 and std::abs(cl_eta) > 1.37) and
1205 std::abs(cl_eta) < 2.4)
1206 energy = m_gain_tool->CorrectionGainTool(
1207 cl_eta, energy / GeV, es2 / GeV,
1208 xAOD2ptype(input)); // cl_eta ok, TODO: check corrected E2
1209 } else if (m_gain_tool_run2) {
1210 double et = energy / std::cosh(cl_eta);
1211 double corr = m_gain_tool_run2->getUncertainty(etaCalo, et,
1212 xAOD2ptype(input), true);
1213 energy /= (1 + corr);
1214 }
1215 ATH_MSG_DEBUG("energy after gain correction = " << std::format("{:.2f}", energy));
1216 } else {
1217 if (m_user_random_run_number == 0) {
1218 if (acc.randomrunnumber_getter.isAvailable(event_info)) {
1219 runNumber_for_tool = acc.randomrunnumber_getter(event_info);
1220 } else {
1222 "Pileup tool not run before using "
1223 "ElectronPhotonFourMomentumCorrection! Assuming it is 2016. If you "
1224 "want to force a specific period set the property randomRunNumber "
1225 "of the tool, e.g. in the job option: "
1226 "tool.randomRunNumber = 123456 or "
1227 "tool.randomRunNumber = "
1228 "EgammaCalibrationAndSmearingToolRunNumbersExample.run_2016");
1230 }
1231 } else {
1232 runNumber_for_tool = m_user_random_run_number;
1233 }
1234 }
1235
1236 const double eraw = ((acc.Es0Acc.isAvailable(inputCluster)
1237 ? acc.Es0Acc(inputCluster)
1238 : acc.energyBEAcc(inputCluster,0)) +
1239 (acc.Es1Acc.isAvailable(inputCluster)
1240 ? acc.Es1Acc(inputCluster)
1241 : acc.energyBEAcc(inputCluster,1)) +
1242 (acc.Es2Acc.isAvailable(inputCluster)
1243 ? acc.Es2Acc(inputCluster)
1244 : acc.energyBEAcc(inputCluster,2)) +
1245 (acc.Es3Acc.isAvailable(inputCluster)
1246 ? acc.Es3Acc(inputCluster)
1247 : acc.energyBEAcc(inputCluster,3)));
1248
1249
1250 if (dataType == PATCore::ParticleDataType::Fast)
1251 ATH_MSG_DEBUG("is fast");
1252 else if (dataType == PATCore::ParticleDataType::Full)
1253 ATH_MSG_DEBUG("is full");
1254 else if (dataType == PATCore::ParticleDataType::Data)
1255 ATH_MSG_DEBUG("is data");
1256
1257 // apply scale factors or systematics
1258 energy = m_rootTool->getCorrectedEnergy(
1259 runNumber_for_tool, dataType, xAOD2ptype(input),
1260 inputCluster(acc.clusterEtaAcc),
1261 inputCluster(acc.clusterEtaBEAcc,2),
1262 acc.etaCaloAcc(inputCluster, acc.authorAcc (input), false), energy,
1263 acc.Es2Acc.isAvailable(inputCluster)
1264 ? acc.Es2Acc(inputCluster)
1265 : inputCluster(acc.energyBEAcc,2),
1266 eraw, seed, oldtool_scale_flag_this_event(input, event_info),
1268 m_varSF);
1269
1270 ATH_MSG_DEBUG("energy after scale/systematic correction = " << std::format("{:.2f}", energy));
1271
1272 // TODO: this check should be done before systematics variations
1273 setPt(input, energy);
1275}
1276
1278 const double new_energy2 = energy * energy;
1279 const auto ptype = xAOD2ptype(input);
1281 const double m2 = m * m;
1282 const double p2 = new_energy2 > m2 ? new_energy2 - m2 : 0.;
1283 m_accessors->ptOutDec (input) = sqrt(p2) / cosh(m_accessors->etaAcc (input));
1284 ATH_MSG_DEBUG("after setting pt, energy = " << m_accessors->momAcc.e (input));
1285}
1286
1288 xAOD::Egamma* p, const xAOD::EventInfo* event_info) {
1289 ANA_CHECK_THROW(applyCorrection(*p, *event_info));
1290 ATH_MSG_DEBUG("returning " << p->e());
1291 return p->e();
1292}
1293
1305
1314
1316 const xAOD::Electron* el, const xAOD::EventInfo* event_info) {
1319 ? m_simulation
1321
1322 const xAOD::TrackParticle* eTrack = el->trackParticle();
1323
1324 // track momentum and eta
1325 const float el_tracketa = eTrack->eta();
1326 const float el_trackmomentum = eTrack->pt() * cosh(el->eta());
1327
1328 return m_rootTool->getCorrectedMomentum(
1329 dataType, PATCore::ParticleType::Electron, el_trackmomentum, el_tracketa,
1330 oldtool_scale_flag_this_event(*el, *event_info), m_varSF);
1331}
1332
1334 const CP::SystematicVariation& systematic) const {
1336 return sys.find(systematic) != sys.end();
1337}
1338
1340 const {
1341 CP::SystematicSet affecting_systematics;
1342 for (const auto& it : m_syst_description) {
1343 affecting_systematics.insert(it.first);
1344 }
1345 for (const auto& it : m_syst_description_resolution) {
1346 affecting_systematics.insert(it.first);
1347 }
1348
1349 return affecting_systematics;
1350}
1351
1353 const EgammaPredicate always = [](const EgammaCalibrationAndSmearingTool&, columnar::EgammaId) { return true; };
1354
1355 // Try to simplify a bit for the ones that are fully correlate in eta,
1356 // whatever the model and that are not included in the macros including
1357 // - ADC non linearity
1358 // - L2Gain
1359 // - Leakage
1360 // - Conversion related
1361 // - TopoCluster threshold
1362 // - AF2
1363 // - PS_BARREL_B12
1364 // - S12EXTRALASTETABINRUN2
1365 // - ZEESTAT
1366 // - Run3 pre OFC + EXTRA
1367 if (m_decorrelation_model_scale == ScaleDecorrelation::FULL_ETA_CORRELATED ||
1368 m_decorrelation_model_scale == ScaleDecorrelation::FULL) {
1369 // Electron leakage, ADCLin, convReco only in final run2 recommendations
1373 // systematic related to ADC non linearity correction. Before 2022, there
1374 // was not correction, nor related systematic
1376 m_syst_description[CP::SystematicVariation("EG_SCALE_ADCLIN", +1)] =
1378 m_syst_description[CP::SystematicVariation("EG_SCALE_ADCLIN", -1)] =
1380 }
1381 // Gain splitted uncertainty
1382 m_syst_description[CP::SystematicVariation("EG_SCALE_L2MEDIUMGAIN", +1)] =
1384 m_syst_description[CP::SystematicVariation("EG_SCALE_L2MEDIUMGAIN", -1)] =
1386 m_syst_description[CP::SystematicVariation("EG_SCALE_L2LOWGAIN", +1)] =
1388 m_syst_description[CP::SystematicVariation("EG_SCALE_L2LOWGAIN", -1)] =
1390
1391 // Electron leakage
1392 m_syst_description[CP::SystematicVariation("EG_SCALE_LEAKAGEELEC", +1)] =
1394 m_syst_description[CP::SystematicVariation("EG_SCALE_LEAKAGEELEC", -1)] =
1396
1397 // Conversion related
1398 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVRECO", +1)] =
1400 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVRECO", -1)] =
1402 }
1403 // The equivalent of convReco (convefficiency and convfakerate) for other
1404 // models
1405 else {
1406 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVEFFICIENCY",
1407 +1)] =
1409 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVEFFICIENCY",
1410 -1)] =
1412 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVFAKERATE", +1)] =
1414 m_syst_description[CP::SystematicVariation("PH_SCALE_CONVFAKERATE", -1)] =
1416 }
1417
1418 // additional systematics for R22 OFC and MC21 pre and bulk
1420 m_syst_description[CP::SystematicVariation("EG_SCALE_OFC", +1)] =
1422 m_syst_description[CP::SystematicVariation("EG_SCALE_OFC", -1)] =
1424
1425 m_syst_description[CP::SystematicVariation("EG_SCALE_EXTRARUN3PRE", +1)] =
1427 m_syst_description[CP::SystematicVariation("EG_SCALE_EXTRARUN3PRE", -1)] =
1429 }
1430
1441
1442 // topo clustr threshold systematics aded to release 21 recommendations
1443 m_syst_description[CP::SystematicVariation("EG_SCALE_TOPOCLUSTER_THRES",
1444 +1)] =
1446 m_syst_description[CP::SystematicVariation("EG_SCALE_TOPOCLUSTER_THRES",
1447 -1)] =
1449
1450 // AF3 for run3 models: es2022_R22_PRE and esmodel >= es2023_R22_Run2_v1
1451 // although we prevent AF for es2022_R22_PRE and es2024_Run3_ofc0_v0
1452 // AF3 are still technically added in the tool
1453 // but normally uncertainty will be 0
1455 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", +1)] =
1457 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", -1)] =
1459 }
1460 else {
1461 // and extra AF2 systematics for release 21 recommendations - Moriond 2018
1462 // - pending proper AF2 to FullSim correction with release 21
1463 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", +1)] =
1465 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", -1)] =
1467 }
1468 }
1469
1470 // PS correlated barrel uncertainty
1479 m_syst_description[CP::SystematicVariation("EG_SCALE_PS_BARREL_B12",
1480 +1)] =
1482 m_syst_description[CP::SystematicVariation("EG_SCALE_PS_BARREL_B12",
1483 -1)] =
1485 }
1486
1487 // additional systematic for S12 last eta bin run2
1493 "EG_SCALE_S12EXTRALASTETABINRUN2", +1)] =
1496 "EG_SCALE_S12EXTRALASTETABINRUN2", -1)] =
1498 }
1499
1500 // Zee stat, if for FULL we do not ask for m_use_full_statistical_error
1502 ScaleDecorrelation::FULL_ETA_CORRELATED or
1504 // return 1 variation only, fully correlated in eta, equal to the correct
1505 // value but scaled by sqrt(number of bins) the scaling is done by the old
1506 // tool
1507 m_syst_description[CP::SystematicVariation("EG_SCALE_ZEESTAT", +1)] =
1509 m_syst_description[CP::SystematicVariation("EG_SCALE_ZEESTAT", -1)] =
1511 }
1512 }
1513 if (m_decorrelation_model_scale == ScaleDecorrelation::ONENP) {
1514 // TODO: independet implementation of ALL UP looping on all the variations
1515 m_syst_description[CP::SystematicVariation("EG_SCALE_ALL", +1)] =
1517 m_syst_description[CP::SystematicVariation("EG_SCALE_ALL", -1)] =
1519
1520 // to be consistent with other schemes, we add
1521 // extra AF systematics in addition to the 1NP
1528 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", +1)] =
1530 m_syst_description[CP::SystematicVariation("EG_SCALE_AF2", -1)] =
1532 }
1534 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", +1)] =
1536 m_syst_description[CP::SystematicVariation("EG_SCALE_AF3", -1)] =
1538 }
1539 }
1540 else if (m_decorrelation_model_scale ==
1541 ScaleDecorrelation::FULL_ETA_CORRELATED) {
1542// all the physical effects separately, considered as fully correlated in eta
1544#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1545 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1546 SysInfo{always, flagup}; \
1547 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1548 SysInfo{always, flagdown};
1549#include "ElectronPhotonFourMomentumCorrection/systematics_es2024_Run3_v0.def"
1550#undef SYSMACRO
1551 }
1552 else {
1553// common systematics for all the esmodels
1554#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1555 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1556 SysInfo{always, flagup}; \
1557 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1558 SysInfo{always, flagdown};
1559#include "ElectronPhotonFourMomentumCorrection/systematics_S12_2022.def"
1560#undef SYSMACRO
1561 }
1562
1566 m_syst_description[CP::SystematicVariation("EG_SCALE_LARCALIB", +1)] =
1568 m_syst_description[CP::SystematicVariation("EG_SCALE_LARCALIB", -1)] =
1570 m_syst_description[CP::SystematicVariation("EG_SCALE_L2GAIN", +1)] =
1572 m_syst_description[CP::SystematicVariation("EG_SCALE_L2GAIN", -1)] =
1574 }
1575
1576 // additional systematics for S12 run2
1587 "EG_SCALE_LARCALIB_EXTRA2015PRE", +1)] =
1590 "EG_SCALE_LARCALIB_EXTRA2015PRE", -1)] =
1592 }
1593
1594 // additional systematics for temperature run1->run2
1601 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE", +1)] =
1604 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE", -1)] =
1606 }
1607
1608 // additional systematic for temperature 2015->2016
1611 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE", +1)] =
1614 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE", -1)] =
1616 }
1617
1618 // additional systematic for PP0 region
1634 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0", +1)] =
1636 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0", -1)] =
1638 }
1639
1640 // systematic related to wtots1
1656 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", +1)] =
1658 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", -1)] =
1660 }
1661
1662 // systematic for the scintillators
1681 // scintillator systematics
1682 m_syst_description[CP::SystematicVariation("EG_SCALE_E4SCINTILLATOR",
1683 +1)] =
1685 m_syst_description[CP::SystematicVariation("EG_SCALE_E4SCINTILLATOR",
1686 -1)] =
1688 }
1689
1690 } else if (m_decorrelation_model_scale ==
1691 ScaleDecorrelation::ONENP_PLUS_UNCONR) {
1692// qsum of all variations correlated 8/13 TeV + uncorrelated (additional
1693// systematics for 2015PRE or 2016) all the physical effects separately,
1694// considered as fully correlated in eta
1695// TODO: fix for es2017
1696#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1697 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1698 SysInfo{always, flagup}; \
1699 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1700 SysInfo{always, flagdown};
1701#include "ElectronPhotonFourMomentumCorrection/systematics_1NPCOR_PLUS_UNCOR.def"
1702#undef SYSMACRO
1703
1704 // additional systematic for S12 last eta bin run2 - not needed anymore for
1705 // last 20.7 model since it is part of bin per bin E1/E2 uncertainty in root
1706 // file
1711 "EG_SCALE_S12EXTRALASTETABINRUN2", +1)] =
1714 "EG_SCALE_S12EXTRALASTETABINRUN2", -1)] =
1716 }
1717
1718 } else if (m_decorrelation_model_scale == ScaleDecorrelation::FULL) {
1719 using pairvector = std::vector<std::pair<double, double>>;
1720 const pairvector decorrelation_bins_BE = {{0., 1.45}, {1.52, 2.5}};
1721 const std::vector<double> decorrelation_edges_TWELVE = {
1722 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};
1723 std::vector<double> decorrelation_edges_MODULE = {
1724 0., 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.37, 1.52, 1.8};
1725 const std::vector<double> decorrelation_edges_MATERIAL = {0.0, 1.1, 1.5,
1726 2.1, 2.5};
1727 std::vector<double> decorrelation_edges_S12_EXTRARUN3 = {
1728 0., 0.8, 1.5, 2.5};
1729
1730 std::vector<double> decorrelation_edges_S12;
1731 // for es2018_R21_v1 : 4 eta bins for muon E1/E2 uncertainty correlation
1733 decorrelation_edges_S12.resize(5);
1734 decorrelation_edges_S12 = {0., 1.35, 1.5, 2.4, 2.5};
1738 decorrelation_edges_S12.resize(8);
1739 decorrelation_edges_S12 = {0., 0.6, 1.0, 1.35, 1.5, 1.8, 2.4, 2.5};
1740 //
1741 // PS scale from muons, so "crack" is a bit different
1742 decorrelation_edges_MODULE[7] = 1.4;
1743 decorrelation_edges_MODULE[8] = 1.5;
1744 }
1745 // for previous run 2 muon calibration with 20.7, 5 eta bins for E1/E2
1746 // uncertainty correlation
1747 else {
1748 decorrelation_edges_S12.resize(6);
1749 decorrelation_edges_S12 = {0., 0.6, 1.4, 1.5, 2.4, 2.5};
1750 }
1751
1763#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1764 if (bool(fullcorrelated)) { \
1765 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1766 SysInfo{always, flagup}; \
1767 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1768 SysInfo{always, flagdown}; \
1769 } else { \
1770 int i = 0; \
1771 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1772 m_syst_description[CP::SystematicVariation( \
1773 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1774 m_syst_description[CP::SystematicVariation( \
1775 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1776 i += 1; \
1777 } \
1778 }
1779#include "ElectronPhotonFourMomentumCorrection/systematics.def"
1780#undef SYSMACRO
1783#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1784 if (bool(fullcorrelated)) { \
1785 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1786 SysInfo{always, flagup}; \
1787 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1788 SysInfo{always, flagdown}; \
1789 } else { \
1790 int i = 0; \
1791 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1792 m_syst_description[CP::SystematicVariation( \
1793 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1794 m_syst_description[CP::SystematicVariation( \
1795 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1796 i += 1; \
1797 } \
1798 }
1799#include "ElectronPhotonFourMomentumCorrection/systematics_S12_2022.def"
1800#undef SYSMACRO
1802#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1803 if (bool(fullcorrelated)) { \
1804 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1805 SysInfo{always, flagup}; \
1806 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1807 SysInfo{always, flagdown}; \
1808 } else { \
1809 int i = 0; \
1810 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1811 m_syst_description[CP::SystematicVariation( \
1812 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1813 m_syst_description[CP::SystematicVariation( \
1814 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1815 i += 1; \
1816 } \
1817 }
1818#include "ElectronPhotonFourMomentumCorrection/systematics_es2024_Run3_v0.def"
1819#undef SYSMACRO
1820 } else {
1821#define SYSMACRO(name, fullcorrelated, decorrelation, flagup, flagdown) \
1822 if (bool(fullcorrelated)) { \
1823 m_syst_description[CP::SystematicVariation(#name, +1)] = \
1824 SysInfo{always, flagup}; \
1825 m_syst_description[CP::SystematicVariation(#name, -1)] = \
1826 SysInfo{always, flagdown}; \
1827 } else { \
1828 int i = 0; \
1829 for (const auto& p : AbsEtaCaloPredicatesFactory(decorrelation)) { \
1830 m_syst_description[CP::SystematicVariation( \
1831 #name "__ETABIN" + std::to_string(i), +1)] = SysInfo{p, flagup}; \
1832 m_syst_description[CP::SystematicVariation( \
1833 #name "__ETABIN" + std::to_string(i), -1)] = SysInfo{p, flagdown}; \
1834 i += 1; \
1835 } \
1836 }
1837#include "ElectronPhotonFourMomentumCorrection/systematics_S12.def"
1838#undef SYSMACRO
1839 } // else
1840
1842 // statistical error, decorrelate in *all* the bins
1843 int i = 0;
1844 const TAxis& axis_statistical_error(m_rootTool->get_ZeeStat_eta_axis());
1845 for (int ibin = 1; ibin <= axis_statistical_error.GetNbins(); ++ibin) {
1846 auto p = EtaCaloPredicateFactory(
1847 axis_statistical_error.GetBinLowEdge(ibin),
1848 axis_statistical_error.GetBinLowEdge(ibin + 1));
1850 "EG_SCALE_ZEESTAT__ETABIN" + std::to_string(i), +1)] =
1853 "EG_SCALE_ZEESTAT__ETABIN" + std::to_string(i), -1)] =
1855 ++i;
1856 }
1857 }
1858
1859 // additional systematics for S12 run2
1870 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN0", +1)] =
1874 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN0", -1)] =
1878 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN1", +1)] =
1879 SysInfo{AbsEtaCaloPredicateFactory({1.45, 2.47}),
1882 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN1", -1)] =
1883 SysInfo{AbsEtaCaloPredicateFactory({1.45, 2.47}),
1886 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN2", +1)] =
1890 "EG_SCALE_LARCALIB_EXTRA2015PRE__ETABIN2", -1)] =
1893 }
1894
1895 // additional systematics for temperature run1->run2
1902 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN0", +1)] =
1903 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1906 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN0", -1)] =
1907 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1910 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN1", +1)] =
1911 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1914 "EG_SCALE_LARTEMPERATURE_EXTRA2015PRE__ETABIN1", -1)] =
1915 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1917 }
1918
1919 // additional systematic for temperature 2015->2016
1922 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN0", +1)] =
1923 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1926 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN1", +1)] =
1927 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1930 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN0", -1)] =
1931 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[0]),
1934 "EG_SCALE_LARTEMPERATURE_EXTRA2016PRE__ETABIN1", -1)] =
1935 SysInfo{AbsEtaCaloPredicateFactory(decorrelation_bins_BE[1]),
1937 }
1938
1939 // additional systematic for PP0 region
1955 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN0",
1956 +1)] = SysInfo{
1958 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN1",
1959 +1)] = SysInfo{
1961 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN0",
1962 -1)] = SysInfo{
1964 m_syst_description[CP::SystematicVariation("EG_SCALE_MATPP0__ETABIN1",
1965 -1)] =
1968 }
1969
1970 // systematic related to wtots1
1983 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", +1)] =
1985 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1", -1)] =
1987 }
1988
1989 // systematic related to wtots1, decorrelate eta bin [1.52,1.82] from rest
1993 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN0",
1994 +1)] =
1995 SysInfo{DoubleOrAbsEtaCaloPredicate(0, 1.52, 1.82, 2.47),
1997 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN0",
1998 -1)] =
1999 SysInfo{DoubleOrAbsEtaCaloPredicate(0, 1.52, 1.82, 2.47),
2001 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN1",
2002 +1)] =
2003 SysInfo{AbsEtaCaloPredicateFactory({1.52, 1.82}),
2005 m_syst_description[CP::SystematicVariation("EG_SCALE_WTOTS1__ETABIN1",
2006 -1)] =
2007 SysInfo{AbsEtaCaloPredicateFactory({1.52, 1.82}),
2009 }
2010
2011 // systematic for the scintillators
2031 "EG_SCALE_E4SCINTILLATOR__ETABIN0", +1)] =
2035 "EG_SCALE_E4SCINTILLATOR__ETABIN1", +1)] =
2039 "EG_SCALE_E4SCINTILLATOR__ETABIN2", +1)] =
2043 "EG_SCALE_E4SCINTILLATOR__ETABIN0", -1)] =
2047 "EG_SCALE_E4SCINTILLATOR__ETABIN1", -1)] =
2051 "EG_SCALE_E4SCINTILLATOR__ETABIN2", -1)] =
2054 if (m_TESModel == egEnergyCorr::es2024_Run3_v0) { // extended E4 in Run 3
2056 "EG_SCALE_E4SCINTILLATOR__ETABIN3", +1)] =
2060 "EG_SCALE_E4SCINTILLATOR__ETABIN3", -1)] =
2063 }
2064 }
2065 } else {
2066 ATH_MSG_FATAL("scale decorrelation model invalid");
2067 }
2068
2069 // resolution systematics
2071 // ALL will not include AF2/AF3 systematic
2072 // individual AF NP is always provided
2073 // linghua.guo@cern.ch 2025-04-23
2075 "EG_RESOLUTION_ALL", +1)] = egEnergyCorr::Resolution::AllUp;
2077 "EG_RESOLUTION_ALL", -1)] = egEnergyCorr::Resolution::AllDown;
2081 "EG_RESOLUTION_ZSMEARING", +1)] = egEnergyCorr::Resolution::ZSmearingUp;
2083 "EG_RESOLUTION_ZSMEARING", -1)] =
2086 "EG_RESOLUTION_SAMPLINGTERM", +1)] =
2089 "EG_RESOLUTION_SAMPLINGTERM", -1)] =
2092 "EG_RESOLUTION_MATERIALID", +1)] =
2095 "EG_RESOLUTION_MATERIALID", -1)] =
2098 "EG_RESOLUTION_MATERIALCALO", +1)] =
2101 "EG_RESOLUTION_MATERIALCALO", -1)] =
2104 "EG_RESOLUTION_MATERIALGAP", +1)] =
2107 "EG_RESOLUTION_MATERIALGAP", -1)] =
2110 "EG_RESOLUTION_MATERIALCRYO", +1)] =
2113 "EG_RESOLUTION_MATERIALCRYO", -1)] =
2116 "EG_RESOLUTION_PILEUP", +1)] = egEnergyCorr::Resolution::PileUpUp;
2118 "EG_RESOLUTION_PILEUP", -1)] = egEnergyCorr::Resolution::PileUpDown;
2135 "EG_RESOLUTION_MATERIALIBL", +1)] =
2138 "EG_RESOLUTION_MATERIALIBL", -1)] =
2141 "EG_RESOLUTION_MATERIALPP0", +1)] =
2144 "EG_RESOLUTION_MATERIALPP0", -1)] =
2146
2147 if (m_TESModel == egEnergyCorr::es2022_R22_PRE) { // exta sys. for Run-3
2148 // pre-recommendations
2150 "EG_RESOLUTION_OFC", +1)] = egEnergyCorr::Resolution::OFCUp;
2152 "EG_RESOLUTION_OFC", -1)] = egEnergyCorr::Resolution::OFCDown;
2153 }
2154 }
2155 } else {
2156 ATH_MSG_FATAL("resolution decorrelation model invalid");
2157 }
2158
2159 // Always use individual AF2/AF3 systematics for resolution
2165 "EG_RESOLUTION_AF2", +1)] = egEnergyCorr::Resolution::afUp;
2167 "EG_RESOLUTION_AF2", -1)] = egEnergyCorr::Resolution::afDown;
2168 }
2171 "EG_RESOLUTION_AF3", +1)] = egEnergyCorr::Resolution::afUp;
2173 "EG_RESOLUTION_AF3", -1)] = egEnergyCorr::Resolution::afDown;
2174 }
2175
2176 // ep combination systematics
2178 m_syst_description[CP::SystematicVariation("EL_SCALE_MOMENTUM", +1)] =
2180 m_syst_description[CP::SystematicVariation("EL_SCALE_MOMENTUM", -1)] =
2182 }
2183}
2184
2189
2191 const CP::SystematicSet& systConfig) {
2192
2193 // set the nominal one (no systematics)
2203
2204 if (systConfig.empty())
2205 return StatusCode::SUCCESS;
2206
2207 // the following code allows only ONE systematic variation at a time (1 for
2208 // scale, 1 for resolution)
2209
2210 bool first_scale = true;
2211 bool first_resolution = true;
2212 for (const auto& it : systConfig) {
2213 const auto found_scale = m_syst_description.find(it);
2214 if (found_scale != m_syst_description.end()) {
2215 if (not first_scale) {
2216 ATH_MSG_ERROR("multiple scale variations not supported");
2217 throw std::runtime_error("multiple scale variations not supported");
2218 }
2219 first_scale = false;
2220 m_currentScaleVariation_MC = found_scale->second.effect;
2221 m_currentScalePredicate = found_scale->second.predicate;
2222 }
2223
2224 const auto found_resolution = m_syst_description_resolution.find(it);
2225 if (found_resolution != m_syst_description_resolution.end()) {
2226 if (not first_resolution) {
2227 ATH_MSG_ERROR("multiple resolution variations not supported");
2228 throw std::runtime_error(
2229 "multiple resolution variations not supported");
2230 }
2231 first_resolution = false;
2232 m_currentResolutionVariation_MC = found_resolution->second;
2233 }
2234 }
2235
2236 return StatusCode::SUCCESS;
2237}
2238
2240 double Ecl, double phi, double eta) const {
2241
2242 // Intermodule Widening Correction: E_corr = E / (a' - b' * ((1 / (1 +
2243 // exp((phi_mod - 2 * pi / 32) * c))) * (1 / (1 + exp((phi_mod - 2 * pi / 32)
2244 // * (d)))))) (phi_min, phi_max) : [a' = a / a, b' = b / a, c, d]
2245
2246 double Ecl_corr = 0.;
2247 int DivInt = 0;
2248 double pi = M_PI;
2249
2263
2264 double phi_mod = 0;
2265 if (phi < 0)
2266 phi_mod = fmod(phi, 2 * pi / 16.) + pi / 8.;
2267 else
2268 phi_mod = fmod(phi, 2 * pi / 16.);
2269
2270 // The correction concerns only the barrel
2271 if (std::abs(eta) <= 1.37) {
2272
2273 if (phi < (-7 * pi / 8) && phi > (-1 * pi))
2274 Ecl_corr =
2275 Ecl /
2276 (1 - 0.1086 *
2277 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 175.2759))) *
2278 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-189.3612))))));
2279 if (phi < (-6 * pi / 8) && phi > (-7 * pi / 8))
2280 Ecl_corr =
2281 Ecl /
2282 (1 - 0.0596 *
2283 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 170.8305))) *
2284 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-233.3782))))));
2285 if (phi < (-5 * pi / 8) && phi > (-6 * pi / 8))
2286 Ecl_corr =
2287 Ecl /
2288 (1 - 0.0596 *
2289 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 147.1451))) *
2290 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-139.3386))))));
2291 if (phi < (-4 * pi / 8) && phi > (-5 * pi / 8))
2292 Ecl_corr =
2293 Ecl /
2294 (1 - 0.0583 *
2295 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 168.4644))) *
2296 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-246.2897))))));
2297 if (phi < (-3 * pi / 8) && phi > (-4 * pi / 8))
2298 Ecl_corr =
2299 Ecl /
2300 (1 - 0.0530 *
2301 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 177.6703))) *
2302 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-198.3227))))));
2303 if (phi < (-2 * pi / 8) && phi > (-3 * pi / 8))
2304 Ecl_corr =
2305 Ecl /
2306 (1 - 0.0672 *
2307 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 145.0693))) *
2308 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-242.1771))))));
2309 if (phi < (-1 * pi / 8) && phi > (-2 * pi / 8))
2310 Ecl_corr =
2311 Ecl /
2312 (1 - 0.0871 *
2313 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 132.3303))) *
2314 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-166.1833))))));
2315 if (phi < (0 * pi / 8) && phi > (-1 * pi / 8))
2316 Ecl_corr =
2317 Ecl /
2318 (1 - 0.0948 *
2319 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 127.6780))) *
2320 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-150.0700))))));
2321 if (phi < (1 * pi / 8) && phi > (0 * pi / 8))
2322 Ecl_corr =
2323 Ecl /
2324 (1 - 0.1166 *
2325 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 172.0679))) *
2326 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-235.3293))))));
2327 if (phi < (2 * pi / 8) && phi > (1 * pi / 8))
2328 Ecl_corr =
2329 Ecl /
2330 (1 - 0.1172 *
2331 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 190.3524))) *
2332 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-198.9400))))));
2333 if (phi < (3 * pi / 8) && phi > (2 * pi / 8))
2334 Ecl_corr =
2335 Ecl /
2336 (1 - 0.1292 *
2337 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 158.0540))) *
2338 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-165.3893))))));
2339 if (phi < (4 * pi / 8) && phi > (3 * pi / 8))
2340 Ecl_corr =
2341 Ecl /
2342 (1 - 0.1557 *
2343 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 162.2793))) *
2344 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-133.5131))))));
2345 if (phi < (5 * pi / 8) && phi > (4 * pi / 8))
2346 Ecl_corr =
2347 Ecl /
2348 (1 - 0.1659 *
2349 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 180.5270))) *
2350 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-168.5074))))));
2351 if (phi < (6 * pi / 8) && phi > (5 * pi / 8))
2352 Ecl_corr =
2353 Ecl /
2354 (1 - 0.1123 *
2355 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 128.2277))) *
2356 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-154.4455))))));
2357 if (phi < (7 * pi / 8) && phi > (6 * pi / 8))
2358 Ecl_corr =
2359 Ecl /
2360 (1 - 0.1394 *
2361 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 192.1216))) *
2362 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-198.0727))))));
2363 if (phi < (8 * pi / 8) && phi > (7 * pi / 8))
2364 Ecl_corr =
2365 Ecl /
2366 (1 - 0.1001 *
2367 ((1 / (1 + exp((phi_mod - 2 * pi / 32.) * 199.1735))) *
2368 (1 / (1 + exp((phi_mod - 2 * pi / 32.) * (-176.4056))))));
2369 }
2370
2371 // No correction for the EC
2372 else {
2373 Ecl_corr = Ecl;
2374 }
2375
2376 }
2377
2378 else {
2379
2380 // Definitions of module folding into four quarters (top, left, bottom and
2381 // right)
2382
2383 DivInt = (int)(phi / ((2 * pi) / 16.));
2384 double phi_mod = phi - DivInt * (2 * pi / 16.);
2385
2386 // Centring on the intermodule --> phi_mod will now be in [0,0.4]
2387 if (phi_mod < 0)
2388 phi_mod += pi / 8.;
2389
2390 // The correction concerns only the barrel
2391 if (std::abs(eta) <= 1.4) {
2392
2393 // Top quarter
2394 if (phi < (3 * pi) / 4. && phi >= pi / 4.) {
2395 Ecl_corr =
2396 Ecl / (1 - 0.131 * ((1 / (1 + exp((phi_mod - 0.2) * 199.08))) *
2397 (1 / (1 + exp((phi_mod - 0.2) * (-130.36))))));
2398 }
2399
2400 // Right quarter
2401 if (phi < pi / 4. && phi >= -pi / 4.) {
2402 Ecl_corr =
2403 Ecl / (1 - 0.0879 * ((1 / (1 + exp((phi_mod - 0.2) * 221.01))) *
2404 (1 / (1 + exp((phi_mod - 0.2) * (-149.51))))));
2405 }
2406 // Bottom quarter
2407 if (phi < -pi / 4. && phi >= (-3 * pi) / 4.) {
2408 Ecl_corr =
2409 Ecl / (1 - 0.0605 * ((1 / (1 + exp((phi_mod - 0.2) * 281.37))) *
2410 (1 / (1 + exp((phi_mod - 0.2) * (-170.29))))));
2411 }
2412 // Left quarter
2413 if ((phi < (-3 * pi) / 4.) || (phi >= (3 * pi) / 4.)) {
2414 Ecl_corr =
2415 Ecl / (1 - 0.102 * ((1 / (1 + exp((phi_mod - 0.2) * 235.37))) *
2416 (1 / (1 + exp((phi_mod - 0.2) * (-219.04))))));
2417 }
2418 }
2419
2420 // No correction for the EC
2421 else {
2422 Ecl_corr = Ecl;
2423 }
2424 }
2425
2426 return Ecl_corr;
2427}
2428
2430 double phi) const {
2431 constexpr double PI = M_PI;
2432 double Fcorr = 1.0;
2433
2435 // wrong mapping HV -> sectors in run1
2436 if (eta < -0.4 && eta > -0.6) {
2437 if (phi < (14 * PI / 32.) && phi > (13 * PI / 32.)) {
2438 Fcorr += 0.035;
2439 } else if (phi < (13 * PI / 32.) && phi > (12 * PI / 32.)) {
2440 Fcorr -= 0.035;
2441 }
2442 }
2443 }
2444
2458
2459 if (eta < 0.2 && eta > 0.) {
2460 if (phi < (-7 * 2 * PI / 32.) && phi > (-8 * 2 * PI / 32.)) {
2461 Fcorr = 1.016314;
2462 }
2463 }
2464
2465 else if (eta < 0.6 && eta > 0.4) {
2466 if (phi < 0 && phi > (-2 * PI / 32.)) {
2467 Fcorr = 1.041591;
2468 } else if (phi < (-4 * 2 * PI / 32.) && phi > (-5 * 2 * PI / 32.)) {
2469 Fcorr = 1.067346;
2470 }
2471 }
2472
2473 else if (eta < 0.8 && eta > 0.6) {
2474 if (phi < (7 * 2 * PI / 32.) && phi > (6 * 2 * PI / 32.)) {
2475 Fcorr = 1.027980;
2476 }
2477 }
2478
2479 else if (eta < 1.4 && eta > 1.2) {
2480 if (phi < (-9 * 2 * PI / 32.) && phi > (-10 * 2 * PI / 32.)) {
2481 Fcorr = 1.020299;
2482 } else if (phi < (-11 * 2 * PI / 32.) && phi > (-12 * 2 * PI / 32.)) {
2483 Fcorr = 1.051426;
2484 }
2485 }
2486
2487 else if (eta < 2.3 && eta > 2.1) {
2488 if (phi < (-12 * 2 * PI / 32.) && phi > (-13 * 2 * PI / 32.)) {
2489 Fcorr = 1.071695;
2490 }
2491 }
2492
2493 else if (eta < 0. && eta > -0.2) {
2494 if (phi < (-12 * 2 * PI / 32.) && phi > (-13 * 2 * PI / 32.)) {
2495 Fcorr = 1.008227;
2496 } else if (phi < (-8 * 2 * PI / 32.) && phi > (-9 * 2 * PI / 32.)) {
2497 Fcorr = 1.013929;
2498 }
2499 }
2500
2501 else if (eta < -0.2 && eta > -0.4) {
2502 if (phi < (-9 * 2 * PI / 32.) && phi > (-10 * 2 * PI / 32.)) {
2503 Fcorr = 1.015749;
2504 }
2505 }
2506
2507 else if (eta < -1.2 && eta > -1.4) {
2508 if (phi < (-6 * 2 * PI / 32.) && phi > (-7 * 2 * PI / 32.)) {
2509 Fcorr = 1.064954;
2510 }
2511 }
2512
2513 else if (eta < -1.6 && eta > -1.8) {
2514 if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2515 Fcorr = 1.027448;
2516 }
2517 }
2518
2519 else if (eta < -2.3 && eta > -2.5) {
2520 if (phi < (-8 * 2 * PI / 32.) && phi > (-9 * 2 * PI / 32.)) {
2521 Fcorr = 1.025882;
2522 } else if (phi < (5 * 2 * PI / 32.) && phi > (4 * 2 * PI / 32.)) {
2523 Fcorr = 1.036616;
2524 } else if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2525 Fcorr = 1.053838;
2526 } else if (phi < (10 * 2 * PI / 32.) && phi > (9 * 2 * PI / 32.)) {
2527 Fcorr = 1.026856;
2528 } else if (phi < (11 * 2 * PI / 32.) && phi > (10 * 2 * PI / 32.)) {
2529 Fcorr = 0.994382;
2530 }
2531 }
2532
2533 } // es2017_summer_improved end
2534
2535 else {
2536 if (eta < 0.6 && eta > 0.4) {
2537 if (phi < 0 && phi > (-2 * PI / 32.)) {
2538 Fcorr = 1.028;
2539 } else if (phi < (-4 * 2 * PI / 32.) && phi > (-5 * 2 * PI / 32.)) {
2540 Fcorr = 1.044;
2541 }
2542 }
2543
2544 else if (eta < 0.8 && eta > 0.6) {
2545 if (phi < (7 * 2 * PI / 32.) && phi > (6 * 2 * PI / 32.)) {
2546 Fcorr = 1.022;
2547 }
2548 }
2549
2550 else if (eta < 1.4 && eta > 1.2) {
2551 if (phi < (-11 * 2 * PI / 32.) && phi > (-12 * 2 * PI / 32.)) {
2552 Fcorr = 1.038;
2553 }
2554 }
2555
2556 else if (eta < 2.0 && eta > 1.9) {
2557 if (phi < (10 * 2 * PI / 32.) && phi > (9 * 2 * PI / 32.)) {
2558 Fcorr = 1.029;
2559 }
2560 }
2561
2562 else if (eta < -1.2 && eta > -1.4) {
2563 if (phi < (-4 * 2 * PI / 32.) && phi > (-5 * 2 * PI / 32.)) {
2564 Fcorr = 1.048;
2565 } else if (phi < (-6 * 2 * PI / 32.) && phi > (-7 * 2 * PI / 32.)) {
2566 Fcorr = 1.048;
2567 }
2568 }
2569
2570 else if (eta < -1.6 && eta > -1.8) {
2571 if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2572 Fcorr = 1.024;
2573 }
2574 }
2575
2576 else if (eta < -2.3 && eta > -2.5) {
2577 if (phi < (-8 * 2 * PI / 32.) && phi > (-9 * 2 * PI / 32.)) {
2578 Fcorr = 1.037;
2579 } else if (phi < (5 * 2 * PI / 32.) && phi > (4 * 2 * PI / 32.)) {
2580 Fcorr = 1.031;
2581 } else if (phi < (9 * 2 * PI / 32.) && phi > (8 * 2 * PI / 32.)) {
2582 Fcorr = 1.040;
2583 } else if (phi < (10 * 2 * PI / 32.) && phi > (9 * 2 * PI / 32.)) {
2584 Fcorr = 1.030;
2585 } else if (phi < (11 * 2 * PI / 32.) && phi > (10 * 2 * PI / 32.)) {
2586 Fcorr = 1.020;
2587 }
2588 }
2589 }
2590
2591 return Fcorr;
2592}
2593
2594void EgammaCalibrationAndSmearingTool ::
2595callSingleEvent (columnar::MutableEgammaRange egammas, columnar::EventInfoId event) const
2596{
2597 for (auto egamma : egammas) {
2599 throw std::runtime_error ("EgammaCalibrationAndSmearingTool::callEvents: apply failed");
2600 }
2601}
2602
2603void EgammaCalibrationAndSmearingTool ::
2604callEvents (columnar::EventContextRange events) const
2605{
2606 const Accessors& acc = *m_accessors;
2607 for (auto event : events) {
2608 auto eventInfo = acc.m_eventHandle(event);
2609 callSingleEvent (acc.m_egammaHandle(event), eventInfo);
2610 }
2611}
2612
2613} // 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.
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
StatusCode addPrivateTool(const std::string &name, AsgComponentConfig toolConfig)
add a private tool from the given configuration
AsgMetadataTool(const std::string &name)
Normal ASG tool constructor with a name.
an object that can create a AsgService
::StatusCode makeService(std::shared_ptr< T > &service) const
make a service with the given configuration
an object that can create a AsgTool
elec/gamma data class.
Definition egamma.h:59
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)
constexpr double electronMassInMeV
the mass of the electron (in MeV)
constexpr double photonMassInMeV
various mass-less particles
ObjectRange< MutableEgammaDef > MutableEgammaRange
Definition EgammaDef.h:52
ObjectId< MutableEgammaDef > MutableEgammaId
Definition EgammaDef.h:53
ObjectRange< EventContextDef > EventContextRange
ObjectId< ClusterDef > ClusterId
Definition ClusterDef.h:23
ObjectId< EgammaDef > EgammaId
Definition EgammaDef.h:47
ObjectId< EventInfoDef > EventInfoId
Definition dot.py:1
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
Electron_v1 Electron
Definition of the current "egamma version".
static const SG::AuxElement::Accessor< ElementLink< IParticleContainer > > acc("originalObjectLink")
Object used for setting/getting the dynamic decoration in question.
A structure holding some global event information.
MsgStream & msg
Definition testRead.cxx:32
const float PI