ATLAS Offline Software
Loading...
Searching...
No Matches
AsgElectronEfficiencyCorrectionTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4
9
10// Include this class's header
13// Library includes
14#include <algorithm>
15#include <cfloat>
16#include <iostream>
17#include <string>
18#include <utility>
19// xAOD includes
20#include "xAODEgamma/Electron.h"
22// PAT includes
23#ifndef XAOD_STANDALONE
25#endif
30// ROOT includes
31#include "TH2F.h"
32#include "TSystem.h"
33
34namespace {
35// Helper function Calculate and return at the spot
37HelperFunc(double& sf, const double input)
38{
39 sf = sf + input;
41}
42}
43
46{
48 MCTOYS = 1,
49 FULL = 2,
51 TOTAL = 4,
52 SYST = 5
53};
54}
55AsgElectronEfficiencyCorrectionTool::AsgElectronEfficiencyCorrectionTool(
56 const std::string& myname)
57 : asg::AsgMetadataTool(myname)
58 , m_affectedSys()
59 , m_appliedSystematics(nullptr)
60 , m_correlation_model(correlationModel::SIMPLIFIED)
61 , m_sysSubstring("")
62 , m_dataType(PATCore::ParticleDataType::Full)
63 , m_nCorrSyst(0)
64 , m_nUncorrSyst(0)
65 , m_UncorrRegions(nullptr)
66 , m_nSimpleUncorrSyst(0)
67 , m_toysBasename{}
68 , m_corrVarUp{}
69 , m_corrVarDown{}
70 , m_uncorrVarUp{}
71 , m_uncorrVarDown{}
72 , m_accessors{std::make_unique<Accessors>(*this)}
73{
74 // Create an instance of the underlying ROOT tool
75 m_rootTool = std::make_unique<Root::TElectronEfficiencyCorrectionTool>(
76 ("T" + (this->name())).c_str());
77 // Declare the needed properties
78 declareProperty(
79 "CorrectionFileNameList",
80 m_corrFileNameList,
81 "List of file names that store the correction factors for simulation.");
82 declareProperty("MapFilePath",
83 m_mapFile = "ElectronEfficiencyCorrection/2015_2025/rel22.2/2025_Run3_Consolidated_Recommendation_v4/map2.txt",
84 "Full path to the map file");
85 declareProperty(
86 "RecoKey", m_recoKey = "", "Key associated with reconstruction");
87 declareProperty(
88 "IdKey", m_idKey = "", "Key associated with identification working point");
89 declareProperty(
90 "IsoKey", m_isoKey = "", "Key associated with isolation working point");
91 declareProperty(
92 "TriggerKey", m_trigKey = "", "Key associated with trigger working point");
93 declareProperty("ForceDataType",
94 m_dataTypeOverwrite = -1,
95 "Force the DataType of the electron to specified value (to "
96 "circumvent problem of incorrect DataType for forward "
97 "electrons in some old releases)");
98 declareProperty(
99 "ResultPrefix", m_resultPrefix = "", "The prefix string for the result");
100 declareProperty("ResultName", m_resultName = "", "The string for the result");
101 declareProperty("CorrelationModel",
102 m_correlation_model_name = "SIMPLIFIED",
103 "Uncertainty correlation model. At the moment TOTAL, FULL, "
104 "SIMPLIFIED, SYST, MCTOYS and COMBMCTOYS are implemented. "
105 "SIMPLIFIED is the default option.");
106 declareProperty("NumberOfToys",
107 m_number_of_toys = 100,
108 "Number of ToyMC replica, affecting MCTOYS and COMBMCTOYS "
109 "correlation models only.");
110 declareProperty("MCToySeed",
111 m_seed_toys = 0,
112 "Seed for ToyMC replica, affecting MCTOYS and COMBMCTOYS "
113 "correlation models only.");
114 declareProperty("MCToyScale",
115 m_scale_toys = 1,
116 "Scales Toy systematics up by this factor, affecting MCTOYS "
117 "and COMBMCTOYS correlation models only.");
118 declareProperty(
119 "UncorrEtaBinsUser",
120 m_uncorrSimplfEtaBinsUser = { 0.0, 1.37, 4.9 },
121 "Custom Eta/Pt binning for the SIMPLIFIED correlation model.");
122 declareProperty(
123 "UncorrEtBinsUser",
124 m_uncorrSimplfEtBinsUser = { 4000,
125 7000,
126 10000,
127 15000,
128 20000,
129 25000,
130 30000,
131 60000,
132 80000,
133 13600000 },
134 "Custom Eta/Pt binning for the SIMPLIFIED correlation model.");
135 declareProperty("EventInfoCollectionName",
136 m_eventInfoCollectionName = "EventInfo",
137 "The EventInfo Collection Name");
138 declareProperty("UseRandomRunNumber", m_useRandomRunNumber = true);
139 declareProperty("DefaultRandomRunNumber", m_defaultRandomRunNumber = 999999);
140}
141
148
149StatusCode
151{
152 // Forward the message level
153 m_rootTool->msg().setLevel(this->msg().level());
154
155 if (m_corrFileNameList.empty() && m_recoKey.empty() && m_idKey.empty() &&
156 m_trigKey.empty() && m_isoKey.empty()) {
157 ATH_MSG_ERROR("CorrectionFileNameList as well as SFKeys are empty! Please "
158 "configure it properly...");
159 return StatusCode::FAILURE;
160 }
161 /*
162 * When metadata are available
163 * m_dataType will be whatever the metadata says i.e Full or Fast
164 * Its default value is Full.
165 * The user can overwrite all these ,using a flag,
166 * and force a specific dataType
167 */
168 if (m_dataTypeOverwrite != -1) {
170 static_cast<int>(PATCore::ParticleDataType::Full) &&
172 static_cast<int>(PATCore::ParticleDataType::Fast)) {
173 ATH_MSG_ERROR("Unsupported Particle Data Type Overwrite"
175 return StatusCode::FAILURE;
176 }
177 m_dataType =
179 }
180 // Find the relevant input files
181 // Fill the vector with filename using keys if the user
182 // has not passed the full filename as a property
183 if (m_corrFileNameList.empty()) {
184 if (getFile(m_recoKey, m_idKey, m_isoKey, m_trigKey).isFailure()) {
185 ATH_MSG_ERROR("No Root file input specified, and not available map file");
186 return StatusCode::FAILURE;
187 }
188 }
189 // Resolve the paths to the input files for the full Geant4 simualtion
190 // corrections
191 for (auto& ifile : m_corrFileNameList) {
192
193 std::string filename = PathResolverFindCalibFile(ifile);
194 if (filename.empty()) {
195 ATH_MSG_ERROR("Could NOT resolve file name " << ifile);
196 return StatusCode::FAILURE;
197 } else {
198 ATH_MSG_DEBUG(" Path found = " << filename);
199 }
200 m_rootTool->addFileName(filename);
201 // Determine the systematics substring according to the name of the input
202 // file
203 if (ifile.find("efficiencySF.") != std::string::npos) {
204 m_sysSubstring = "Trigger_";
205 }
206 if (ifile.find("efficiencySF.offline") != std::string::npos) {
207 m_sysSubstring = "ID_";
208 }
209 if (ifile.find("efficiencySF.offline.RecoTrk") != std::string::npos) {
210 m_sysSubstring = "Reco_";
211 }
212 if (ifile.find("efficiencySF.offline.Fwd") != std::string::npos) {
213 m_sysSubstring = "FwdID_";
214 }
215 if (ifile.find("efficiencySF.Isolation") != std::string::npos) {
216 m_sysSubstring = "Iso_";
217 }
218 if (ifile.find("efficiency.") != std::string::npos) {
219 m_sysSubstring = "TriggerEff_";
220 }
221 if (ifile.find("efficiencySF.ChargeID") != std::string::npos) {
222 m_sysSubstring = "ChargeIDSel_";
223 }
224 if (m_sysSubstring.empty()) {
225 ATH_MSG_ERROR("Could NOT find systematics Substring file name "
226 << m_sysSubstring);
227 return StatusCode::FAILURE;
228 }
229 }
230 //
231 // Find the proper correlation Model
232 if (m_correlation_model_name == "COMBMCTOYS") {
234 } else if (m_correlation_model_name == "MCTOYS") {
236 } else if (m_correlation_model_name == "FULL") {
238 } else if (m_correlation_model_name == "SIMPLIFIED") {
240 // a few checks on the binning that the user might have specified
242 m_uncorrSimplfEtBinsUser.size() < 2 ||
243 m_uncorrSimplfEtaBinsUser.size() < 2) {
244 ATH_MSG_ERROR("Something went wrong when specifying bins for the "
245 "SIMPLIFIED correlation model ");
246 return StatusCode::FAILURE;
247 }
248 } else if (m_correlation_model_name == "TOTAL") {
250 } else if (m_correlation_model_name == "SYST") {
252 } else {
253 ATH_MSG_ERROR("Unknown correlation model " + m_correlation_model_name);
254 return StatusCode::FAILURE;
255 }
256 ATH_MSG_DEBUG("Correlation model: " + m_correlation_model_name
257 << " Enum " << m_correlation_model);
258
259 // Histogram of simplified uncorrelated regions
261 m_UncorrRegions = new TH2F("UncorrRegions",
262 "UncorrRegions",
263 m_uncorrSimplfEtBinsUser.size() - 1,
265 m_uncorrSimplfEtaBinsUser.size() - 1,
267 m_UncorrRegions->SetDirectory(nullptr);
268
269 // bins not entries here
271 (m_uncorrSimplfEtBinsUser.size() - 1);
272 }
273 // Finish the preaparation of the underlying tool
274 if (m_seed_toys != 0) {
275 m_rootTool->setSeed(m_seed_toys);
276 }
277 //
279 m_rootTool->bookCombToyMCScaleFactors(m_number_of_toys);
280 }
281 //
283 m_rootTool->bookToyMCScaleFactors(m_number_of_toys);
284 }
285 // We need to initialize the underlying ROOT TSelectorTool
286 if (0 == m_rootTool->initialize()) {
288 "Could not initialize the TElectronEfficiencyCorrectionTool!");
289 return StatusCode::FAILURE;
290 }
291
292 // get Nsyst
293 m_nCorrSyst = m_rootTool->getNSyst();
294 std::map<float, std::vector<float>> tmp;
295 m_nUncorrSyst = m_rootTool->getNbins(tmp);
296 // copy over to vector for better access
297 for (const auto& i : tmp) {
298 m_pteta_bins.emplace_back(i.first, i.second);
299 }
300
301 // Check if the input contains uncorr/stat necessary
302 // to run non-total systematic model
304 m_rootTool->uncorrEmpty(m_dataType) ) {
305 ATH_MSG_ERROR("Called correlation model "+m_correlation_model_name+
306 " but input does not contain necessary histograms.");
307 return StatusCode::FAILURE;
308 }
309
310 // Initialize the systematics
311 if (InitSystematics() != StatusCode::SUCCESS) {
312 ATH_MSG_ERROR("(InitSystematics() != StatusCode::SUCCESS)");
313 return StatusCode::FAILURE;
314 }
315 // Add the recommended systematics to the registry
316 if (registerSystematics() != StatusCode::SUCCESS) {
317 ATH_MSG_ERROR("(registerSystematics() != StatusCode::SUCCESS)");
318 return StatusCode::FAILURE;
319 }
320 // Configure for nominal systematics
321 if (applySystematicVariation(CP::SystematicSet()) != StatusCode::SUCCESS) {
322 ATH_MSG_ERROR("Could not configure for nominal settings");
323 return StatusCode::FAILURE;
324 }
325
327 resetAccessor (m_accessors->randomrunnumber, *this, "RandomRunNumber");
328 }
329 ATH_CHECK (initializeColumns());
330 return StatusCode::SUCCESS;
331}
332
335 const xAOD::Electron& inputObject,
336 double& efficiencyScaleFactor) const
337{
338 const xAOD::EventInfo* eventInfo = nullptr;
339 if (evtStore()->retrieve(eventInfo, m_eventInfoCollectionName).isFailure()) {
340 ATH_MSG_ERROR("Could not retrieve EventInfo object!");
342 }
343 return getEfficiencyScaleFactor(columnar::ElectronId(inputObject), efficiencyScaleFactor, columnar::EventInfoId (*eventInfo));
344}
345
348 columnar::ElectronId inputObject,
349 double& efficiencyScaleFactor,
350 columnar::EventInfoId eventInfo) const
351{
352 const Accessors& acc = *m_accessors;
353
354 efficiencyScaleFactor = 1;
355 // Retrieve the proper random Run Number
356 unsigned int runNumber = m_defaultRandomRunNumber;
358 if (!acc.randomrunnumber.isAvailable(eventInfo)) {
360 "Pileup tool not run before using ElectronEfficiencyTool! SFs do not "
361 "reflect PU distribution in data");
363 }
364 runNumber = acc.randomrunnumber(eventInfo);
365 }
366 //
367 // Get the result
368 //
369 double cluster_eta(-9999.9);
370
371 auto cluster = acc.caloClusterAcc (inputObject) [0].value();
372
373 // we need to use different variables for central and forward electrons
374 if (acc.accAuthor.isAvailable(inputObject) &&
375 acc.accAuthor(inputObject) == xAOD::EgammaParameters::AuthorFwdElectron) {
376 cluster_eta = acc.clusterEtaAcc (cluster);
377 } else {
378 cluster_eta = acc.clusterEtaBEAcc (cluster, 2);
379 }
380
381 // use et from cluster because it is immutable under syst variations of
382 // electron energy scale
383 const double energy = acc.clusterEAcc(cluster);
384 const double parEta = acc.m_eta(inputObject);
385 const double coshEta = std::cosh(parEta);
386 double et = (coshEta != 0.) ? energy / coshEta : 0.;
387 // allow for a 5% margin at the lowest pT bin boundary (i.e. increase et by 5%
388 // for sub-threshold electrons). This assures that electrons that pass the
389 // threshold only under syst variations of energy get a scale factor assigned.
390 auto itr_pt = m_pteta_bins.begin();
391 if (itr_pt != m_pteta_bins.end() && et < itr_pt->first) {
392 et = et * 1.05;
393 }
394 return getEfficiencyScaleFactor(et, cluster_eta, runNumber,
395 efficiencyScaleFactor);
396}
397
400 const double et, /*in MeV*/
401 const double cluster_eta, /*cluster*/
402 const unsigned int runNumber,
403 double& efficiencyScaleFactor) const
404{
405 // We pass only one variation per time
406 // The applied systematic is always one systematic.
407 // Either is relevant and acquires a value
408 // or stays 0.
409 double sys(0);
410
411 // Let's try to figure already what we are to do
412 bool doSFOnly = appliedSystematics().empty();
417 bool isSimplified = (m_correlation_model == correlationModel::SIMPLIFIED);
418
419 // Lets see if we have an uncorrelated syst variation passed
420 int unCorrSign = 0;
421 // or a correlated one
422 int indexCorrelated = -999;
423 int correlatedSign = 0;
424 if (!(doSFOnly || doToys || isTotal) && (isFull || isSimplified)) {
425 const auto& sysName = appliedSystematics().begin()->name();
426 bool isUncorr = (sysName.find("UncorrUnc") != std::string::npos);
427 int currentUncorReg = -999;
428 if (isUncorr) {
429 // Can we find an uncorrelated region?
430 if (isFull) {
431 currentUncorReg = currentUncorrSystRegion(cluster_eta, et);
432 } else if (isSimplified) {
433 currentUncorReg = currentSimplifiedUncorrSystRegion(cluster_eta, et);
434 }
435 if (currentUncorReg < 0) {
437 }
438 // And use it to if we got the "right" syst variation
439 if (appliedSystematics().matchSystematic(
440 m_uncorrVarDown[currentUncorReg])) {
441 unCorrSign = -1;
442 } else if (appliedSystematics().matchSystematic(
443 m_uncorrVarUp[currentUncorReg])) {
444 unCorrSign = 1;
445 }
446 } else if (m_nCorrSyst != 0) {//if we have 0 we do not care ...
447 if (sysName.find("CorrUnc") != std::string::npos) {
448 // given the name convention we
449 const auto varNumEnd = sysName.rfind("__");
450 const auto varNumBegin = sysName.rfind("NP") + 2;
451 const int varIndex =
452 std::stoi(sysName.substr(varNumBegin, (varNumEnd - varNumBegin)));
453 if (appliedSystematics().matchSystematic(m_corrVarUp[varIndex])) {
454 indexCorrelated = varIndex;
455 correlatedSign = 1;
456 } else if (appliedSystematics().matchSystematic(
457 m_corrVarDown[varIndex])) {
458 indexCorrelated = varIndex;
459 correlatedSign = -1;
460 }
461 } // find CorrUncertainty in name
462 } // not Uncorr and we have CorrSyst
463 } // Not (SF or toys or total)
464
465 // Now lets do the call
466 // For now we more or less calculate on demand only
467 // the Correlated and the toys we can see if we want
468 // top opt also the "TOTAL"
470 const int status =
471 m_rootTool->calculate(m_dataType, runNumber, cluster_eta, et, /* in MeV */
472 result, isTotal);
473
474 // if status 0 something went wrong
475 if (!status) {
476 efficiencyScaleFactor = 1;
478 }
479 // At this point we have the SF
480 efficiencyScaleFactor = result.SF;
481 //And if all we need we can return
482 if (doSFOnly) {
484 }
485
486 // First the logic if the user requested toys
487 if (doToys) {
489 toy.second = m_scale_toys;
490 sys = result.toys[toy.first - 1] * m_scale_toys;
491 // return here for Toy variations
492 efficiencyScaleFactor = sys;
494 }
495 // The "TOTAL" single uncertainty uncorrelated+correlated
496 else if (isTotal) {
497 sys = result.Total;
498 if (appliedSystematics().matchSystematic(m_uncorrVarUp[0])) {
499 return HelperFunc(efficiencyScaleFactor, sys);
500 }
501 if (appliedSystematics().matchSystematic(m_uncorrVarDown[0])) {
502 return HelperFunc(efficiencyScaleFactor, -1 * sys);
503 }
504 }
505 // Then the uncorrelated part for the SiMPLIFIED/FULL models
506 else if (unCorrSign!=0) {
507 sys = unCorrSign * result.UnCorr;
508 return HelperFunc(efficiencyScaleFactor, sys);
509 }
510
511 // If we reach this point
512 // it means we need to do the correlated part
513 // for the FULL/SIMPLIFIED models.
514 // First if there are not correlated systematic
515 if (m_nCorrSyst == 0) {
516
517 if (appliedSystematics().matchSystematic(m_corrVarUp[0])) {
518 sys = std::sqrt(result.Total * result.Total -
519 result.UnCorr * result.UnCorr); // total
520 // -stat
521 return HelperFunc(efficiencyScaleFactor, sys);
522 }
523 if (appliedSystematics().matchSystematic(m_corrVarDown[0])) {
524 sys = -1 * std::sqrt(result.Total * result.Total -
525 result.UnCorr * result.UnCorr); // total
526 // -stat
527 return HelperFunc(efficiencyScaleFactor, sys);
528 }
529 }
530 //or if we had
531 if (correlatedSign != 0) {
532 sys = correlatedSign * result.Corr[indexCorrelated];
533 return HelperFunc(efficiencyScaleFactor, sys);
534 }
536}
537
540 const xAOD::Electron& inputObject) const
541{
542 double efficiencyScaleFactor = 1.0;
544 getEfficiencyScaleFactor(inputObject, efficiencyScaleFactor);
546 m_resultName + "SF");
547 dec(inputObject) = efficiencyScaleFactor;
548 return result;
549}
550
551/*
552 * Systematics Interface
553 */
555bool
557 const CP::SystematicVariation& systematic) const
558{
559 if (systematic.empty()) {
560 return false;
561 }
565 return (sys.begin()->ensembleContains(systematic));
566 } else {
567 return (sys.find(systematic) != sys.end());
568 }
569}
570
576// Register the systematics with the registry and add them to the recommended
577// list
578StatusCode
580{
582
583 if (registry.registerSystematics(*this) != StatusCode::SUCCESS) {
585 "Failed to add systematic to list of recommended systematics.");
586 return StatusCode::FAILURE;
587 }
588 return StatusCode::SUCCESS;
589}
590
596
597StatusCode
599 const CP::SystematicSet& systConfig)
600{
601 // First, check if this configuration exists in the filtered map/registy
602 auto itr = m_systFilter.find(systConfig);
603
604 if (itr != m_systFilter.end()) {
605 CP::SystematicSet& mySysConf = itr->second;
606 m_appliedSystematics = &mySysConf;
607 }
608 // if not, we should register it, after it passes sanity checks
609 else {
610 // If it's a new input set, we need to filter it
612 CP::SystematicSet filteredSys;
614 systConfig, affectingSys, filteredSys)) {
616 "Unsupported combination of systematic variations passed to the tool!");
617 return StatusCode::FAILURE;
618 }
619 // Does filtered make sense, only one per time
620 if (filteredSys.size() > 1) {
622 "More than one systematic variation passed at the same time");
623 return StatusCode::FAILURE;
624 }
625
626 if (filteredSys.empty() && !systConfig.empty()) {
627 ATH_MSG_DEBUG("systematics : ");
628 for (const auto& syst : systConfig) {
629 ATH_MSG_DEBUG(syst.name());
630 }
631 ATH_MSG_DEBUG(" Not supported ");
632 }
633 // insert to the registy
634 itr = m_systFilter.insert(std::make_pair(systConfig, filteredSys)).first;
635 // And return directly
636 CP::SystematicSet& mySysConf = itr->second;
637 m_appliedSystematics = &mySysConf;
638 }
639 return StatusCode::SUCCESS;
640}
641
642/*
643 * Helper Methods
644 */
645StatusCode
647{
648 const std::string prefix = "EL_EFF_" + m_sysSubstring;
649 const std::string prefixUncorr = prefix + m_correlation_model_name + "_";
650 // Toys
652 m_toysBasename = prefix + "COMBMCTOY";
653 m_affectedSys.insert(
656 m_toysBasename = prefix + "MCTOY";
657 m_affectedSys.insert(
659 // Correlated for the different models (1 or Full set)
661 if (m_nCorrSyst == 0) {
662 auto varUp = CP::SystematicVariation(prefix + "CorrUncertainty", 1);
663 auto varDown = CP::SystematicVariation(prefix + "CorrUncertainty", -1);
664 m_corrVarUp.push_back(varUp);
665 m_corrVarDown.push_back(varDown);
666 m_affectedSys.insert(varUp);
667 m_affectedSys.insert(varDown);
668 } else
669 for (int i = 0; i < m_nCorrSyst; ++i) {
670 auto varUp =
671 CP::SystematicVariation(prefix + Form("CorrUncertaintyNP%d", i), 1);
672 auto varDown =
673 CP::SystematicVariation(prefix + Form("CorrUncertaintyNP%d", i), -1);
674 m_corrVarUp.push_back(varUp);
675 m_corrVarDown.push_back(varDown);
676 m_affectedSys.insert(varUp);
677 m_affectedSys.insert(varDown);
678 }
679 }
680 // Different tratement for the uncorrelated per model
682 auto varUp = CP::SystematicVariation(prefixUncorr + "1NPCOR_PLUS_UNCOR", 1);
683 auto varDown =
684 CP::SystematicVariation(prefixUncorr + "1NPCOR_PLUS_UNCOR", -1);
685 m_uncorrVarUp.push_back(varUp);
686 m_uncorrVarDown.push_back(varDown);
687 m_affectedSys.insert(varUp);
688 m_affectedSys.insert(varDown);
690 for (int i = 0; i < m_nUncorrSyst; ++i) {
691 auto varUp = CP::SystematicVariation(
692 prefixUncorr + Form("UncorrUncertaintyNP%d", i), 1);
693 auto varDown = CP::SystematicVariation(
694 prefixUncorr + Form("UncorrUncertaintyNP%d", i), -1);
695 m_uncorrVarUp.push_back(varUp);
696 m_uncorrVarDown.push_back(varDown);
697 m_affectedSys.insert(varUp);
698 m_affectedSys.insert(varDown);
699 }
701 for (int i = 0; i < m_nSimpleUncorrSyst; ++i) {
702 auto varUp = CP::SystematicVariation(
703 prefixUncorr + Form("UncorrUncertaintyNP%d", i), 1);
704 auto varDown = CP::SystematicVariation(
705 prefixUncorr + Form("UncorrUncertaintyNP%d", i), -1);
706 m_uncorrVarUp.push_back(varUp);
707 m_uncorrVarDown.push_back(varDown);
708 m_affectedSys.insert(varUp);
709 m_affectedSys.insert(varDown);
710 }
711 }
712 return StatusCode::SUCCESS;
713}
714
715int
717 const double cluster_eta,
718 const double et) const
719{
720 int ptbin = std::as_const(*m_UncorrRegions).GetXaxis()->FindBin(et) - 1;
721 if (ptbin < 0 ||
722 ptbin >= std::as_const(*m_UncorrRegions).GetXaxis()->GetNbins()) {
724 " Found electron with Et = "
725 << et / 1000. << " GeV, where you specified boundaries of ["
726 << std::as_const(*m_UncorrRegions).GetXaxis()->GetBinLowEdge(1) << ","
727 << std::as_const(*m_UncorrRegions)
728 .GetXaxis()
729 ->GetBinUpEdge(
730 std::as_const(*m_UncorrRegions).GetXaxis()->GetNbins())
731 << "] for the SIMPLIFIED correlation model ");
732 return -1;
733 }
734 int etabin =
735 std::as_const(*m_UncorrRegions).GetYaxis()->FindBin(std::abs(cluster_eta)) -
736 1;
737 if (etabin < 0 ||
738 etabin >= std::as_const(*m_UncorrRegions).GetYaxis()->GetNbins()) {
740 " Found electron with |eta| = "
741 << std::abs(cluster_eta) << ", where you specified boundaries of ["
742 << std::as_const(*m_UncorrRegions).GetYaxis()->GetBinLowEdge(1) << ","
743 << std::as_const(*m_UncorrRegions)
744 .GetYaxis()
745 ->GetBinUpEdge(
746 std::as_const(*m_UncorrRegions).GetYaxis()->GetNbins())
747 << "] for the SIMPLIFIED correlation model ");
748 return -1;
749 }
750 int reg = ((etabin)*m_UncorrRegions->GetNbinsX() + ptbin);
751 return reg;
752}
753
754int
756 const double cluster_eta,
757 const double et) const
758{
759 int etabin = 0;
760 int reg = 0;
761 bool found = false;
762 float cluster_eta_electron = 0;
763 auto itr_ptBEGIN = m_pteta_bins.begin();
764 auto itr_ptEND = m_pteta_bins.end();
765 for (; itr_ptBEGIN != itr_ptEND; ++itr_ptBEGIN) {
766 auto itr_ptBEGINplusOne = itr_ptBEGIN;
767 ++itr_ptBEGINplusOne;
768 // Find the pt bin : Larger or equal from the current and the next one is
769 // the last or the next one is larger.
770 if (et >= itr_ptBEGIN->first &&
771 (itr_ptBEGINplusOne == itr_ptEND || et < itr_ptBEGINplusOne->first)) {
772 if ((itr_ptBEGIN->second).at(0) >= 0) {
773 cluster_eta_electron = std::abs(cluster_eta);
774 } else {
775 cluster_eta_electron = (cluster_eta);
776 };
777 for (unsigned int etab = 0; etab < ((itr_ptBEGIN->second).size());
778 ++etab) {
779 unsigned int etabnext = etab + 1;
780 // Find the eta bin : Larger or equal from the current and the next one
781 // is the last or the next one is larger:.
782 if ((cluster_eta_electron) >= (itr_ptBEGIN->second).at(etab) &&
783 (etabnext == itr_ptBEGIN->second.size() ||
784 cluster_eta_electron < itr_ptBEGIN->second.at(etabnext))) {
785 found = true;
786 break;
787 }
788 // We did not find it. Increment eta and continue looking
789 etabin++;
790 }
791 }
792 if (found) {
793 break;
794 }
795 // Add the full size of the "passed" eta row
796 reg += (itr_ptBEGIN->second).size();
797 }
798 if (!found) {
799 ATH_MSG_WARNING("No index for the uncorrelated systematic was found, "
800 "returning the maximum index");
801 return m_nCorrSyst;
802 }
803 reg = reg + etabin;
804 return reg;
805}
806
807int
813
814int
816 columnar::ElectronId inputObject) const
817{
818 const Accessors& acc = *m_accessors;
819 int currentSystRegion = -999;
820 double cluster_eta(-9999.9);
821 double et(0.0);
822
823 et = acc.m_pt(inputObject);
824 const auto cluster = acc.caloClusterAcc (inputObject) [0].value();
825 cluster_eta = acc.clusterEtaBEAcc (cluster, 2);
826 switch (m_correlation_model) {
828 currentSystRegion = currentSimplifiedUncorrSystRegion(cluster_eta, et);
829 break;
830 }
832 currentSystRegion = currentUncorrSystRegion(cluster_eta, et);
833 break;
834 }
835 default: {
836 // not there for the other models
837 break;
838 }
839 }
840 return currentSystRegion;
841}
842
844StatusCode
846 const std::string& idkey,
847 const std::string& isokey,
848 const std::string& trigkey)
849{
850
851 std::string mapFileName = PathResolverFindCalibFile(m_mapFile);
852 std::string key =
853 ElRecomFileHelpers::convertToOneKey(recokey, idkey, isokey, trigkey);
854 std::string value = ElRecomFileHelpers::getValueByKey(mapFileName, key);
855
856 if (!value.empty()) {
857 m_corrFileNameList.push_back(value);
858 } else {
859 if (mapFileName.empty()) {
861 "Map file does not exist, Please set the path and version properly..");
862 } else {
864 "Key "
865 << key
866 << " does not exist in the map file, Please configure it properly..");
867 }
868 return StatusCode::FAILURE;
869 }
870
871 ATH_MSG_DEBUG("Full File Name is " + value);
872 return StatusCode::SUCCESS;
873}
874/*
875 * Metadata methods.
876 * The tool operates in MC .
877 * The default type is Full sim.
878 *
879 * The user can override the MC type
880 * in which case we avoid doing anything.
881 *
882 * The typical scenario is :
883 * For every IncidentType::BeginInputFile we can check for metadata
884 * and try to employ them in determining the simulation Flavor.
885 * If we found metadata
886 * set m_metadata_retrieved= True else set it to False
887 *
888 * EndInputFile should not do something
889 *
890 * The beginEvent should kick in only if the beginInputFile has
891 * failed to find metadata and the user has no preference.
892 * Asg/base class has our back in cases where the 1st beginEvent
893 * happens before the 1st beginInputFile.
894 * For now we can not do something meaningfull in this method
895 * for this tool so can stay as a skeleton for the future
896 */
897StatusCode
899{
900
901 // User forced a particular dataType
902 if (m_dataTypeOverwrite != -1)
903 return StatusCode::SUCCESS;
904
905 PATCore::ParticleDataType::DataType dataType_metadata;
906 const StatusCode status = get_simType_from_metadata(dataType_metadata);
907 // Metadata got retrieved
908 if (status == StatusCode::SUCCESS) {
910 ATH_MSG_DEBUG("metadata from new file: "
911 << (dataType_metadata == PATCore::ParticleDataType::Data
912 ? "data"
913 : (dataType_metadata == PATCore::ParticleDataType::Full
914 ? "full simulation"
915 : "fast simulation")));
916
917 if (dataType_metadata != PATCore::ParticleDataType::Data) {
918 if (m_dataTypeOverwrite == -1) {
919 m_dataType = dataType_metadata;
920 } else {
922 "Applying SF corrections to data while they make sense only for MC");
923 }
924 }
925 } else { // not able to retrieve metadata
926 m_metadata_retrieved = false;
927 ATH_MSG_DEBUG("not able to retrieve metadata");
928 }
929 return StatusCode::SUCCESS;
930}
931
932StatusCode
934{
935
936 if (m_dataTypeOverwrite != -1)
937 return StatusCode::SUCCESS;
939 return StatusCode::SUCCESS;
940
942 return StatusCode::SUCCESS;
943}
944
945StatusCode
948{
949
950#ifndef XAOD_STANDALONE
951 // Determine MC/Data
952 std::string dataType("");
954 "/TagInfo", "project_name", dataType, inputMetaStore()))
955 .isSuccess()) {
956 if (!(dataType == "IS_SIMULATION")) {
958 ATH_MSG_DEBUG("Running on data");
959 return StatusCode::SUCCESS;
960 }
961 // Determine Fast/FullSim
962 if (dataType == "IS_SIMULATION") {
963 std::string simType("");
964 ATH_CHECK(AthAnalysisHelper::retrieveMetadata("/Simulation/Parameters",
965 "SimulationFlavour",
966 simType,
967 inputMetaStore()));
968 std::transform(simType.begin(), simType.end(), simType.begin(), ::toupper);
969 result = (simType.find("ATLFAST") == std::string::npos)
972 return StatusCode::SUCCESS;
973 }
974 }
975#endif
976 // Here's how things will work dual use, when file metadata is available in
977 // files
978 if (inputMetaStore()->contains<xAOD::FileMetaData>("FileMetaData")) {
979 const xAOD::FileMetaData* fmd = nullptr;
980 ATH_CHECK(inputMetaStore()->retrieve(fmd, "FileMetaData"));
981
982 std::string simType("");
983 const bool s = fmd->value(xAOD::FileMetaData::simFlavour, simType);
984 if (!s) {
985 ATH_MSG_DEBUG("no sim flavour from metadata: must be data");
987 return StatusCode::SUCCESS;
988 } else {
989 ATH_MSG_DEBUG("sim type = " + simType);
990 std::transform(simType.begin(), simType.end(), simType.begin(), ::toupper);
991 result = (simType.find("ATLFAST") == std::string::npos)
994 return StatusCode::SUCCESS;
995 }
996 } else { // no metadata in the file
997 ATH_MSG_DEBUG("no metadata found in the file");
998 return StatusCode::FAILURE;
999 }
1000}
1001
1002
1003
1005{
1006 const Accessors& acc = *m_accessors;
1007 for (columnar::ElectronId electron : electrons)
1008 {
1009 double sf = 0;
1010 switch (getEfficiencyScaleFactor(electron, sf, event).code())
1011 {
1013 acc.m_sfDec(electron) = sf;
1014 acc.m_validDec(electron) = true;
1015 break;
1017 acc.m_sfDec(electron) = sf;
1018 acc.m_validDec(electron) = false;
1019 break;
1020 default:
1021 throw std::runtime_error("Error in getEfficiencyScaleFactor");
1022 }
1023 }
1024}
1025
1027{
1028 const Accessors& acc = *m_accessors;
1029 for (columnar::EventContextId event : events)
1030 {
1031 auto eventInfo = acc.m_eventInfo(event);
1032 callSingleEvent (acc.m_electrons(event), eventInfo);
1033 }
1034}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Base class for elements of a container that can have aux data.
float et(const xAOD::jFexSRJetRoI *j)
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
void callSingleEvent(columnar::ElectronRange electrons, columnar::EventInfoId event) const
virtual StatusCode beginInputFile() override final
Function called when a new input file is opened.
int currentSimplifiedUncorrSystRegion(const double cluster_eta, const double et) const
std::string m_eventInfoCollectionName
The Event info collection name.
StatusCode InitSystematics()
initialize the systematics
std::vector< std::string > m_corrFileNameList
The list of file names.
virtual StatusCode applySystematicVariation(const CP::SystematicSet &systConfig) override final
Configure this tool for the given systematics.
virtual CP::CorrectionCode applyEfficiencyScaleFactor(const xAOD::Electron &inputObject) const override final
std::vector< CP::SystematicVariation > m_uncorrVarDown
void callEvents(columnar::EventContextRange events) const override
CP::SystematicSet m_affectedSys
Affected systematic, should be done only once.
std::unordered_map< CP::SystematicSet, CP::SystematicSet > m_systFilter
Systematics filter map.
std::vector< CP::SystematicVariation > m_corrVarDown
std::vector< CP::SystematicVariation > m_corrVarUp
std::unique_ptr< Root::TElectronEfficiencyCorrectionTool > m_rootTool
Pointer to the underlying ROOT based tool.
int m_dataTypeOverwrite
Force the data type to a given value.
virtual CP::CorrectionCode getEfficiencyScaleFactor(const xAOD::Electron &inputObject, double &efficiencyScaleFactor) const override final
virtual CP::SystematicSet affectingSystematics() const override final
returns: the list of all systematics this tool can be affected by
std::string m_resultName
The string for the result.
virtual StatusCode beginEvent() override final
Function called when a new events is loaded.
virtual const CP::SystematicSet & appliedSystematics() const override final
returns: the currently applied systematics
std::string m_resultPrefix
The prefix string for the result.
bool m_metadata_retrieved
To check if the metadata can be retrieved.
virtual StatusCode initialize() override final
Gaudi Service Interface method implementations.
virtual CP::SystematicSet recommendedSystematics() const override final
returns: the list of all systematics this tool recommends to use
virtual StatusCode getFile(const std::string &recokey, const std::string &idkey, const std::string &isokey, const std::string &trigkey)
Gets the correction filename from map.
virtual ASG_TOOL_CLASS(AsgElectronEfficiencyCorrectionTool, IAsgElectronEfficiencyCorrectionTool) public ~AsgElectronEfficiencyCorrectionTool() override final
Standard destructor.
std::vector< std::pair< float, std::vector< float > > > m_pteta_bins
virtual bool isAffectedBySystematic(const CP::SystematicVariation &systematic) const override final
returns: whether this tool is affected by the given systematis
CP::SystematicSet * m_appliedSystematics
Currently applied systematics.
virtual int systUncorrVariationIndex(const xAOD::Electron &inputObject) const override final
StatusCode get_simType_from_metadata(PATCore::ParticleDataType::DataType &result) const
std::vector< CP::SystematicVariation > m_uncorrVarUp
int currentUncorrSystRegion(const double cluster_eta, const double et) const
static std::string retrieveMetadata(const std::string &folder, const std::string &key, const ServiceHandle< StoreGateSvc > &inputMetaStore)
method that always returns as a string you can use from, e.g, pyROOT with evt = ROOT....
ServiceHandle< StoreGateSvc > & evtStore()
Return value from object correction CP tools.
@ Error
Some error happened during the object correction.
@ OutOfValidityRange
Input object is out of validity range.
@ Ok
The correction was done successfully.
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
std::pair< unsigned, float > getToyVariationByBaseName(const std::string &basename) const
the toy variation for the given basename
const_iterator begin() const
description: const iterator to the beginning of the set
size_t size() const
returns: size of the set
static StatusCode filterForAffectingSystematics(const SystematicSet &systConfig, const SystematicSet &affectingSystematics, SystematicSet &filteredSystematics)
description: filter the systematics for the affected systematics returns: success guarantee: strong f...
bool empty() const
returns: whether this is an empty systematic, i.e.
static SystematicVariation makeToyEnsemble(const std::string &basename)
constructor for toy systematics ensemble
SG::Decorator< T, ALLOC > Decorator
Definition AuxElement.h:575
MetaStorePtr_t inputMetaStore() const
Accessor for the input metadata store.
@ simFlavour
Fast or Full sim [string].
bool value(MetaDataType type, std::string &val) const
Get a pre-defined string value out of the object.
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:114
std::string getValueByKey(const std::string &mapFile, const std::string &key)
std::string convertToOneKey(const std::string &recokey, const std::string &idkey, const std::string &isokey, const std::string &trigkey)
Information about type of data used to fill particle.
Information about type of data used to fill particle.
ObjectId< ContainerId::electron > ElectronId
Definition EgammaDef.h:38
ObjectRange< ContainerId::eventContext > EventContextRange
ObjectId< ContainerId::eventContext > EventContextId
ObjectRange< ContainerId::electron > ElectronRange
Definition EgammaDef.h:37
ObjectId< ContainerId::eventInfo > EventInfoId
STL namespace.
const uint16_t AuthorFwdElectron
Electron reconstructed by the Forward cluster-based algorithm.
Definition EgammaDefs.h:30
EventInfo_v1 EventInfo
Definition of the latest event info version.
FileMetaData_v1 FileMetaData
Declare the latest version of the class.
Electron_v1 Electron
Definition of the current "egamma version".
Extra patterns decribing particle interation process.
MsgStream & msg
Definition testRead.cxx:32