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