ATLAS Offline Software
Loading...
Searching...
No Matches
ElectronPhotonVariableCorrectionBase.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
12
16
17// EDM includes
19#include "TEnv.h"
20
21//Root includes
22#include "TObject.h"
23#include "TFormula.h"
24
25#include "TFile.h"
26#include "TRandom3.h"
27
28//allow advanced math for the TF1
29#include "TMath.h"
30
32
33// ===========================================================================
34// Standard Constructor
35// ===========================================================================
37 AsgTool(myname)
38{
39 //declare the needed properties
40 declareProperty("ConfigFile",m_configFile="","The configuration file to use");
41}
42
43// ===========================================================================
44// Initialize
45// ===========================================================================
47{
48 // Locate configuration file, abort if not found
49 std::string configFile;
50 if (!m_configFile.empty())
51 {
53 if (configFile.empty())
54 {
55 ATH_MSG_ERROR("Could not locate configuration file " << m_configFile);
56 return StatusCode::FAILURE;
57 }
58 ATH_MSG_DEBUG("Use configuration file " << m_configFile << " " << configFile);
59 }
60 else
61 {
62 ATH_MSG_ERROR("Config file string is empty. Please provide a config file to the tool.");
63 return StatusCode::FAILURE;
64 }
65
66 // retrieve properties from configuration file, using TEnv class
67 TEnv env;
68 env.ReadFile(configFile.c_str(), kEnvLocal);
69 // Send warning if duplicates found in conf file
70 env.IgnoreDuplicates(false);
71
72 //retrieve variable to correct
73 if (env.Lookup("Variable"))
74 {
75 m_correctionVariable = env.GetValue("Variable","");
76 }
77 else
78 {
79 ATH_MSG_ERROR("Correction variable is empty or not in configuration file.");
80 return StatusCode::FAILURE;
81 }
82
83 // initialize the variable aux element accessors
84 // variable to be corrected
85 m_variableToCorrect = std::make_unique<SG::Accessor<float>>(m_correctionVariable);
86 // save original value under different name
87 m_originalVariable = std::make_unique<SG::Accessor<float>>(m_correctionVariable + "_original");
88
89 // Get whether to apply a pure correction or to smear the variable (shift by a random amount,
90 // determined using function as probability density function)
91 if (env.Lookup("doGaussianSmearing"))
92 {
93 m_doGaussianSmearing = env.GetValue("doGaussianSmearing", false); // Default is to not do smearing - keeps previous configs valid
94 }
95 // Get the function used to correct the variable
96 if (env.Lookup("Function"))
97 {
98 m_correctionFunctionString = env.GetValue("Function","failure");
99 // initialize the actual correction function TFormula
100 m_correctionFunctionTFormula = std::make_unique<TFormula>("m_correctionFunctionTF1",m_correctionFunctionString.c_str(), false);
101 }
102 else
103 {
104 ATH_MSG_ERROR("Correction function is empty or not in configuration file.");
105 return StatusCode::FAILURE;
106 }
107
108 // Get the number of parameters used in the correction function
109 if (env.Lookup("nFunctionParameters"))
110 {
111 m_numberOfFunctionParameters = env.GetValue("nFunctionParameters",-1);
112
113 // If doing the Gaussian smearing, there can only be two parameters
114 // so fail if there is more or less than this
116 {
117 ATH_MSG_ERROR("When using Gaussian smearing, there can only be two " <<
118 "function parameters, the Gaussian mean and the Gaussian width");
119 return StatusCode::FAILURE;
120 }
121
122 }
123 else
124 {
125 ATH_MSG_ERROR("You did not specify the number of parameters in the correction function.");
126 return StatusCode::FAILURE;
127 }
128
129 // resize all vectors used for getting parameters to m_numberOfFunctionParameters
136
137 // Save the type of all parameters in the correction function (assuming m_numberOfFunctionParameters parameters)
138 for (int parameter_itr = 0; parameter_itr < m_numberOfFunctionParameters; parameter_itr++)
139 {
140 // if the parameter #parameter_itr is in the conf file, save its type
141 TString parameterType = TString::Format("Parameter%dType",parameter_itr);
142 if (env.Lookup(parameterType))
143 {
144 // convert string to ParameterType, fail if non-existing type
147 {
148 ATH_MSG_ERROR("Parameter " << parameter_itr << " read-in failed, not an allowed parameter type.");
149 return StatusCode::FAILURE;
150 }
151 // save type, get according type information and save it
152 m_ParameterTypeVector.at(parameter_itr) = type;
153 ATH_CHECK(getParameterInformationFromConf(env, parameter_itr, type));
154 }
155 // else fail
156 else
157 {
158 ATH_MSG_ERROR("Did not find Parameter" << parameter_itr << ", although you specified there were " << m_numberOfFunctionParameters << " parameters for the correction function.");
159 return StatusCode::FAILURE;
160 }
161 } // end loop over all function parameters
162
163 // check to which EGamma object the conf file should be applied to, if flag is set
164 if (env.Lookup("ApplyTo"))
165 {
166 std::string applyToObjectsFlag = env.GetValue("ApplyTo","Failure");
167 m_applyToObjects = stringToEGammaObject(applyToObjectsFlag);
168 // fail if not passed a proper type
170 {
171 ATH_MSG_ERROR("You did not correctly specify the object type in the ApplyTo flag.");
172 return StatusCode::FAILURE;
173 }
174 }
175 // else fail
176 else
177 {
178 ATH_MSG_ERROR("You did not specify to which objects this conf file should be applied to (ApplyTo).");
179 return StatusCode::FAILURE;
180 }
181
182 // check if there are any (discrete) values which should be left uncorrected
183 if (env.Lookup("UncorrectedDiscontinuities"))
184 {
185 m_uncorrectedDiscontinuities = AsgConfigHelper::HelperFloat("UncorrectedDiscontinuities", env);
186 // if flag is given, but no values, fail
188 {
189 ATH_MSG_ERROR("Did not find any discontinuities to not correct, despite finding the flag UncorrectedDiscontinuities.");
190 return StatusCode::FAILURE;
191 }
192 }
193
194 //everything worked out, so
195 return StatusCode::SUCCESS;
196}
197
198// ===========================================================================
199// Application of correction
200// ===========================================================================
202{
203 // check if we should only deal with converted / unconverted photons
204 if (!passedCorrectPhotonType(photon))
205 {
206 ATH_MSG_ERROR("You specified in the conf file that the tool should only be used for (un-)converted photons, but passed the other conversion type.");
208 }
209
210 // From the object, get the variable value according to the variable from the conf file
211 // if variable not found, fail
212 float original_variable = 0.;
213 if( m_variableToCorrect->isAvailable(photon) )
214 {
215 original_variable = (*m_variableToCorrect)(photon);
216 //Save the original value to the photon under different name
217 (*m_originalVariable)(photon) = original_variable;
218 // check if tool should skip correcting this variable, as it's from some discontinuity
219 if (isEqualToUncorrectedDiscontinuity(original_variable))
220 {
222 }
223 }
224 else
225 {
226 ATH_MSG_ERROR("The correction variable \"" << m_correctionVariable << "\" provided in the conf file is not available.");
228 }
229
230 float eta; //safe value of eta of event
231 float pt; //safe pt of event
232 float phi; //safe phi of event
233
234 //Get all the properties from the photon and fill them to properties, eta, pt, phi
235 if (getKinematicProperties(photon, pt, eta, phi) != StatusCode::SUCCESS)
236 {
237 ATH_MSG_ERROR("Could not retrieve kinematic properties of this photon object.");
239 }
240 ATH_MSG_VERBOSE("Got the photon kinematics , pT = " << pt << " eta = " << eta << "phi = " << phi);
241 std::vector<float> properties;
242 if (getCorrectionParameters(pt, eta, phi, properties) != StatusCode::SUCCESS)
243 {
244 ATH_MSG_ERROR("Could not get the correction parameters for this photon object.");
246 }
247
248 // Apply the correction, write to the corrected AuxElement
249 correct((*m_variableToCorrect)(photon),original_variable, properties);
250
251 // everything worked out, so
253}
254
256{
257 if (!applyToElectrons())
258 {
259 ATH_MSG_ERROR("You want to correct electrons, but passed a conf file with ApplyTo flag not set for electrons. Are you using the correct conf file?");
261 }
262
263 // From the object, get the variable value according to the variable from the conf file
264 // if variable not found, fail
265 float original_variable = 0.;
266
267 if (m_correctionVariable == "transformed_e_probability_ht") {
268 // this is a special case, since what we want to fudge is not the variable
269 // usually stoared in (D)xAOD, but a transformed version
270 // here we compute the transormed version
271 // this is code duplication from AsgElectronLikelihoodTool.cxx
272
273 const xAOD::TrackParticle* track = electron.trackParticle();
274 if (!track) {
275 ATH_MSG_ERROR("you are trying to fudge transformed_e_probability_ht but the electron has no track!");
277 }
278 float TRT_PID = 0.;
279 if (!track->summaryValue(TRT_PID, xAOD::eProbabilityHT)) {
280 ATH_MSG_ERROR("you are trying to fudge transformed_e_probability_ht but eProbabilityHT is not present");
282 }
283
284 const double tau = 15.0;
285 const double fEpsilon = 1.0e-30; // to avoid zero division
286 double pid_tmp = TRT_PID;
287 if (pid_tmp >= 1.0)
288 pid_tmp = 1.0 - 1.0e-15; // this number comes from TMVA
289 else if (pid_tmp <= fEpsilon)
290 pid_tmp = fEpsilon;
291 double trans_TRT_PID = -std::log(1.0 / pid_tmp - 1.0) * (1. / double(tau));
292
293 (*m_variableToCorrect)(electron) = (float)trans_TRT_PID;
294 }
295
296 if (m_variableToCorrect->isAvailable(electron))
297 {
298 original_variable = (*m_variableToCorrect)(electron);
299 //Save the original value to the photon under different name
300 (*m_originalVariable)(electron) = original_variable;
301 // check if tool should skip correcting this variable, as it's from some discontinuity
302 if (isEqualToUncorrectedDiscontinuity(original_variable))
303 {
305 }
306 }
307 else
308 {
309 ATH_MSG_ERROR("The correction variable \"" << m_correctionVariable << "\" provided in the conf file is not available.");
311 }
312
313 float eta; //safe value of eta of event
314 float pt; //safe pt of event
315 float phi; //safe phi of event
316
317 //Get all the properties from the electron and fill them to properties, eta, pt, phi
318 if (getKinematicProperties(electron, pt, eta, phi) != StatusCode::SUCCESS)
319 {
320 ATH_MSG_ERROR("Could not retrieve kinematic properties of this electron object.");
322 }
323 ATH_MSG_VERBOSE("Got the electron kinematics , pT = " << pt << " eta = " << eta << "phi = " << phi);
324 std::vector<float> properties;
325 if (getCorrectionParameters(pt, eta, phi, properties) != StatusCode::SUCCESS)
326 {
327 ATH_MSG_ERROR("Could not get the correction parameters for this electron object.");
329 }
330
331 // If applying a Gaussian smearing correction, set the seed based on the
332 // electron properties
333 unsigned int rndSeed(0);
335 {
336 rndSeed = 1 + static_cast<unsigned int>(pt + std::abs(eta) * 1E3 + std::abs(phi) * 1E6);
337 }
338
339 // Apply the correction, write to the corrected AuxElement
340 correct((*m_variableToCorrect)(electron),original_variable, properties, rndSeed);
341
342 // everything worked out, so
344}
345
346void ElectronPhotonVariableCorrectionBase::correct(float& return_corrected_variable, const float original_variable,
347 const std::vector<float>& properties,
348 unsigned int rndSeed) const
349{
350 ATH_MSG_VERBOSE("original var " << original_variable);
351
352 // If not smearing, apply correction in normal way
354 {
355 double x = original_variable;
356 std::vector<double> dpars (properties.begin(), properties.end());
357 return_corrected_variable = m_correctionFunctionTFormula->EvalPar(&x,
358 dpars.data());
359 }
360 else
361 {
362 // Get Gaussian mean and width from the parameters, to be used with
363 // TRandom::Gaus (assumes function given is a gaussian)
364 const double gaussMean = properties.at(0);
365 const double gaussAbsWidth = std::abs(properties.at(1));
366
367 // If the Gaussian width is 0, can't use TRandom::Gaus - just apply shift
368 if (gaussAbsWidth == 0.0)
369 {
370 return_corrected_variable = original_variable + gaussMean;
371 }
372 // Otherwise, can apply smear using TRandom::Gaus
373 else
374 {
375 return_corrected_variable = original_variable +
376 getTLSRandomGen(rndSeed)->Gaus(gaussMean, gaussAbsWidth);
377 }
378 }
379
380 ATH_MSG_VERBOSE("corrected var " << return_corrected_variable);
381}
382
383// ===========================================================================
384// Corrected Copies
385// ===========================================================================
387{
388 out_photon = new xAOD::Photon(in_photon);
389 return applyCorrection(*out_photon);
390}
391
393{
394 out_electron = new xAOD::Electron(in_electron);
395 return applyCorrection(*out_electron);
396}
397
398// ===========================================================================
399// Helper Functions
400// ===========================================================================
401
403{
404 // if no values set, return false as there is nothing to check
406 {
407 return false;
408 }
409
410 // check all discontinuities which where passed
411 for (unsigned int value_itr = 0; value_itr < m_uncorrectedDiscontinuities.size(); value_itr++)
412 {
413 if (value == m_uncorrectedDiscontinuities.at(value_itr))
414 {
415 // if the value is equal to one of the discontinuities, no need to check further
416 return true;
417 }
418 }
419 // if we eer get here, the value was never equal to a discontinuity
420 return false;
421}
422
423const StatusCode ElectronPhotonVariableCorrectionBase::getKinematicProperties(const xAOD::Egamma& egamma_object, float& pt, float& eta, float& phi) const
424{
425 // just retrieving eta and pt is probably less expensive then checking if I need it and
426 // then retrieve it only if I actually need it
427
428 // protection against bad clusters
429 const xAOD::CaloCluster* cluster = egamma_object.caloCluster();
430 if ( cluster == nullptr )
431 {
432 ATH_MSG_ERROR("EGamma object calorimeter cluster is NULL: Cluster " << cluster);
433 return StatusCode::FAILURE;
434 }
435
436 // Fill variables
437 // eta position in second sampling
438 eta = cluster->etaBE(2);
439 // transverse energy in calorimeter (using eta position in second sampling)
440 const double energy = cluster->e();
441 double et = 0.;
442 if (eta<999.) {
443 const double cosheta = cosh(eta);
444 et = (cosheta != 0.) ? energy/cosheta : 0.;
445 }
446 pt = et;
447 // issue a warning if pT is unphysical - i.e. < 0
448 if (pt < 0)
449 {
450 ATH_MSG_WARNING("Encountered EGamma object with strange pT: " << pt << " MeV. Correcting as if it has a pT of 0.");
451 }
452 // phi
453 phi = cluster->phiBE(2);
454
455 // everything went fine, so
456 return StatusCode::SUCCESS;
457}
458
460{
461 // don't want to write the same code multiple times, so set flags when to retrieve eta/pt bins
462 bool getEtaBins = false;
463 bool getPtBins = false;
464 // form strings according to which parameter to retrieve
465 TString filePathKey = TString::Format("Parameter%dFile",parameter_number);
466 TString graphNameKey = TString::Format("Parameter%dGraphName",parameter_number);
467 TString histNameKey = TString::Format("Parameter%dTH2Name",parameter_number);
468 TString binValues = TString::Format("Parameter%dValues",parameter_number);
469 TString interpolate = TString::Format("Parameter%dInterpolate",parameter_number);
470
471 // according to the parameter type, retrieve the information from conf
472 switch (type)
473 {
475 // this fallthrough is intentional!
477 {
478 auto object = getObjectFromRootFile(env, parameter_number, filePathKey, graphNameKey);
479 if (!object) {
480 return StatusCode::FAILURE;
481 }
482 auto* graph = dynamic_cast<TGraph*>(object.get());
483 if (!graph) {
484 ATH_MSG_ERROR("Object for parameter " << parameter_number << " is not a TGraph.");
485 return StatusCode::FAILURE;
486 }
487 m_graphCopies.at(parameter_number) = std::unique_ptr<TGraph>( static_cast<TGraph*>(object.release()));
488 }
489 break;
491 //get eta binning later
492 getEtaBins = true;
493 break;
495 //get pt binning later
496 getPtBins = true;
497 break;
499 //get eta and pt binning later
500 getEtaBins = true;
501 getPtBins = true;
502 break;
504 {
505 auto object = getObjectFromRootFile(env, parameter_number, filePathKey, histNameKey);
506 if (!object) [[unlikely]] {
507 ATH_MSG_ERROR("TH2 object is null.");
508 return StatusCode::FAILURE;
509 }
510 auto* th2 = dynamic_cast<TH2*>(object.get());
511 if (!th2) [[unlikely]] {
512 ATH_MSG_ERROR("Object for parameter " << parameter_number << " is not a TH2.");
513 return StatusCode::FAILURE;
514 }
515 // Bin 0 is the underflow bin, so use bin 1.
516 auto* axis = th2->GetXaxis();
517 if (!axis) [[unlikely]] {
518 ATH_MSG_ERROR("TH2 X axis is null.");
519 return StatusCode::FAILURE;
520 }
521 const float lowest_bin_boundary = axis->GetBinLowEdge(1);
522 if (lowest_bin_boundary > 0) {
524 "Lowest bin edge in TH2 for parameter "
525 << parameter_number
526 << " is > 0. Please provide the TH2 including corrections either "
527 "for the positive eta range (starting at 0), or the whole eta "
528 "range (starting with a negative dummy value which is treated "
529 "as -infinity.");
530 return StatusCode::FAILURE;
531 }
532 m_useAbsEtaTH2.at(parameter_number) = lowest_bin_boundary;
533 m_TH2Copies.at(parameter_number) =
534 std::unique_ptr<TH2>( static_cast<TH2*>(object.release()));
535 }
536 break;
538 // nothing has to be retrieved, no additional parameters for EventDensity currently
539 return StatusCode::SUCCESS;
540 default:
541 {}//only adding default to omit compile time warnings for not including parameterType::Failure
542 // this case will never occur, since returning this case fails earlier
543 }
544
545 //get the pt and eta binning from the conf file, if necessary
546 if (getEtaBins || getPtBins)
547 { ATH_CHECK(getEtaPtBinningsFromConf(getEtaBins, getPtBins, binValues, interpolate, env, parameter_number)); }
548
549 //everything went fine, so
550 return StatusCode::SUCCESS;
551}
552
553const StatusCode ElectronPhotonVariableCorrectionBase::getEtaPtBinningsFromConf(const bool getEtaBins, const bool getPtBins, const TString& binValues, const TString& interpolate, TEnv& env, const int parameter_number)
554{
555 // if needed and not already retrieved, get eta binning
556 if (getEtaBins && !m_retrievedEtaBinning)
557 {
558 // check if necessary information is in conf, else fail
559 if (env.Lookup("EtaBins"))
560 {
561 //get the eta binning (global!)
563 //force that the low bin edges are given by the conf file, starting with 0 or a negative value
564 if (m_etaBins.at(0) > 0.)
565 {
566 ATH_MSG_ERROR("Lowest bin edge given for parameter " << parameter_number << " is > 0. Please provide the lower bin edges of your correction binning in the conf file, starting with either 0 (for corrections symmetric in eta) or a negative number (being treated as -infinity).");
567 return StatusCode::FAILURE;
568 }
569 else
570 {
571 m_useAbsEtaBinned = m_etaBins.at(0) >= 0;
572 }
573 // don't want to retrieve the same thing twice from conf
575 }
576 else
577 {
578 ATH_MSG_ERROR("Could not retrieve eta binning.");
579 return StatusCode::FAILURE;
580 }
581 }
582 // if needed and not already retrieved, get pt binning
583 if (getPtBins && !m_retrievedPtBinning)
584 {
585 // check if necessary information is in conf, else fail
586 if (env.Lookup("PtBins"))
587 {
588 //get the pt binning (global!)
590 //force that the low bin edges are given by the conf file, starting with 0
591 if (m_ptBins.at(0) != 0.)
592 {
593 ATH_MSG_ERROR("Lowest bin edge given for parameter " << parameter_number << " is not 0. Please provide the lower bin edges of your correction binning in the conf file, starting with 0.");
594 return StatusCode::FAILURE;
595 }
596 // don't want to retrieve the same thing twice from conf
598 }
599 else
600 {
601 ATH_MSG_ERROR("Could not retrieve pt binning.");
602 return StatusCode::FAILURE;
603 }
604 }
605 //check if interpolation should be done
606 if (getPtBins)
607 {
608 // default is false
609 m_interpolatePtFlags.at(parameter_number) = env.GetValue(interpolate.Data(),false);
610 }
611 if ( getEtaBins || getPtBins)
612 {
613 // check if necessary information is in conf, else fail
614 if (env.Lookup(binValues))
615 {
616 //get the binned values of the eta/pt dependent parameter
617 m_binValues.at(parameter_number) = AsgConfigHelper::HelperFloat(binValues.Data(),env);
618 }
619 else
620 {
621 ATH_MSG_ERROR("Could not retrieve binned values.");
622 return StatusCode::FAILURE;
623 }
624 }
625
626 // everything went fine, so
627 return StatusCode::SUCCESS;
628}
629
630std::unique_ptr<TObject>
631ElectronPhotonVariableCorrectionBase::getObjectFromRootFile(TEnv& env, const int parameter_number, const TString& filePathKey, const TString& nameKey)
632{
633 // helpers
634 TString filePath = "";
635 TString objectName = "";
636 // check if necessary information is in conf, else fail
637 if (env.Lookup(filePathKey))
638 {
639 //get the path to the root file where the graph is saved
640 filePath = PathResolverFindCalibFile(env.GetValue(filePathKey.Data(),""));
641 // fail if file not found
642 if (filePath == "")
643 {
644 ATH_MSG_ERROR("Could not locate Parameter" << parameter_number << " TObject file.");
645 return nullptr;
646 }
647 }
648 else
649 {
650 ATH_MSG_ERROR("Could not retrieve Parameter" << parameter_number << " file path.");
651 return nullptr;
652 }
653 // check if necessary information is in conf, else fail
654 if (env.Lookup(nameKey))
655 {
656 //get the name of the TGraph
657 objectName = env.GetValue(nameKey.Data(),"");
658 }
659 else
660 {
661 ATH_MSG_ERROR("Could not retrieve Parameter" << parameter_number << " object name.");
662 return nullptr;
663 }
664 // open file, if it works, try to find object, get object, store a copy, else warning + fail
665 auto file = std::make_unique<TFile>(filePath.Data(),"READ");
666 // check if file is open - if open, get graph, if not, fail
667 if (file->IsOpen())
668 {
669 TObject* object = file->Get(objectName.Data());
670 if (!object){
671 ATH_MSG_ERROR("Could not find TObject " << objectName << " in file " << filePath);
672 return nullptr;
673 }
674 //clone would not be required for THx objects, but we want this to work for TGraph also
675 auto returnObj = std::unique_ptr<TObject> (object->Clone());
676 // need to un-associate THx type objects from file directory, so they remain accessible
677 if (auto pHist = dynamic_cast<TH1*>(returnObj.get());pHist != nullptr)
678 {
679 pHist->SetDirectory(nullptr);
680 }
681 file->Close();
682 return returnObj;
683 }
684 ATH_MSG_ERROR("Could not open Parameter" << parameter_number << " TObject file " << filePath.Data());
685 return nullptr;
686}
687
688
689const StatusCode ElectronPhotonVariableCorrectionBase::getCorrectionParameters(const float pt, const float eta, const float phi,
690 std::vector<float>& properties) const
691{
692 properties.resize(m_numberOfFunctionParameters);
693
694 // check if eta or abs(eta) is used for the binned variables
695 float etaForBinned = eta;
697 { etaForBinned = std::abs(eta); }
698 // if use eta, correct for cases where eta is smaller than lowest bin boundary
699 // i.e. treat lowest bin boundary as -inf!
700 else if (etaForBinned < m_etaBins.at(0))
701 {
702 // set eta to midpoint of lowest bin
703 etaForBinned = 0.5*(m_etaBins.at(0) + m_etaBins.at(1));
704 }
705
706 // according to the parameter type, get the actual parameter going to the correction function
707 // for this, loop over the parameter type vector
708 const std::string shapeStr{"TopoClusterIsoCentralEventShape"};
709 for (unsigned int parameter_itr = 0; parameter_itr < m_ParameterTypeVector.size(); parameter_itr++)
710 {
711 switch (m_ParameterTypeVector.at(parameter_itr))
712 {
714 // evaluate TGraph at eta
715 properties.at(parameter_itr) = m_graphCopies.at(parameter_itr)->Eval(etaForBinned);
716 break;
718 // evaluate TGraph at pt
719 properties.at(parameter_itr) = m_graphCopies.at(parameter_itr)->Eval(pt);
720 break;
722 // get value of correct eta bin
723 ATH_CHECK(get1DBinnedParameter(properties.at(parameter_itr),etaForBinned,m_etaBins,parameter_itr));
724 break;
726 // get value of correct pt bin
727 ATH_CHECK(get1DBinnedParameter(properties.at(parameter_itr),pt,m_ptBins,parameter_itr));
728 break;
730 // get value of correct eta x pt bin
731 ATH_CHECK(get2DBinnedParameter(properties.at(parameter_itr),etaForBinned,pt,parameter_itr));
732 break;
734 { // need curly brackets here to mark scope - since etaForThisTH2 is initialized (and only needed) here
735 // check if need to use eta or abseta for this parameter (depends on the respective TH2)
736 float etaForThisTH2 = eta;
737 if (m_useAbsEtaTH2.at(parameter_itr) == 0.)
738 { etaForThisTH2 = std::abs(eta); }
739 // get value of correct eta x phi bin
740 ATH_CHECK(get2DHistParameter(properties.at(parameter_itr),etaForThisTH2,phi,parameter_itr));
741 }
742 break;
744 // get event density
745 ATH_CHECK(getDensity(properties.at(parameter_itr), shapeStr));
746 break;
747 default:
748 {}//only adding default to omit compile time warnings for not including parameterType::Failure
749 // this case will never occur, since returning this case fails earlier
750 }
751 }
752
753 for (auto p : properties)
754 ATH_MSG_VERBOSE("prop " << p);
755
756 // everything went fine, so
757 return StatusCode::SUCCESS;
758}
759
760const StatusCode ElectronPhotonVariableCorrectionBase::get1DBinnedParameter(float& return_parameter_value, const float evalPoint, const std::vector<float>& binning, const int parameter_number) const
761{
762 ANA_MSG_VERBOSE("EvalPoint: " << evalPoint);
763 // need to find the bin in which the evalPoint is
764 int bin = -1;
765 ATH_CHECK(findBin(bin, evalPoint, binning));
766
767 // calculate return value
768 // if interpolation flag is true, interpolate
769 if (getInterpolationFlag(parameter_number))
770 {
771 ATH_CHECK(interpolate(return_parameter_value, evalPoint, bin, binning, m_binValues.at(parameter_number)));
772 }
773 else
774 {
775 return_parameter_value = m_binValues.at(parameter_number).at(bin);
776 }
777
778 // everything went fine, so
779 return StatusCode::SUCCESS;
780}
781
782const StatusCode ElectronPhotonVariableCorrectionBase::get2DBinnedParameter(float& return_parameter_value, const float etaEvalPoint, const float ptEvalPoint, const int parameter_number) const
783{
784 //need to find eta bin, and need to find pt bin
785 //from this, calculate which parameter of the list is needed to be returned.
786 int etaBin = -1;
787 int ptBin = -1;
788
789 ATH_MSG_VERBOSE("eta = " << etaEvalPoint << " pt = " << ptEvalPoint);
790
791 ATH_CHECK(findBin(etaBin, etaEvalPoint, m_etaBins));
792 ATH_CHECK(findBin(ptBin, ptEvalPoint, m_ptBins));
793
794 // get the corresponding pt x eta bin found
795 /* Note: Assuming that the values are binned in pt x eta in the conf file:
796 * eta bin 0 | eta bin 1 | eta bin 2 | eta bin 3 | eta bin 4 | etc.
797 * pt bin 0 0 1 2 3 4
798 * pt bin 1 5 6 7 8 9
799 * pt bin 2 10 11 12 13 14
800 * pt bin 3 15 16 17 18 19
801 * pt bin 4 20 21 22 23 24
802 * etc.
803 * the correct parameter is saved in the vector at (number of eta bins) * ptBinNumber + etaBinNumber
804 * */
805
806 ATH_MSG_VERBOSE(" eta bin " << etaBin << " pT bin " << ptBin);
807
808 int bin_number_in_bin_values = m_etaBins.size() * ptBin + etaBin;
809
810 // calculate return value
811 // if interpolation flag is true, interpolate
812 if (getInterpolationFlag(parameter_number))
813 {
814 // create the vector of correction values binned in pT at the found eta bin
815 std::vector<float> tmp_binValuesAtEtaSlice;
816 // from the full binning vector, need to cut one of the columns
817 for (unsigned int binValue_itr = etaBin; binValue_itr < m_binValues.at(parameter_number).size(); binValue_itr += m_etaBins.size())
818 {
819 tmp_binValuesAtEtaSlice.push_back(m_binValues.at(parameter_number).at(binValue_itr));
820 }
821 // interpolate using the above slice of the correction values
822 ATH_CHECK(interpolate(return_parameter_value, ptEvalPoint, ptBin, m_ptBins, tmp_binValuesAtEtaSlice));
823 }
824 else
825 {
826 return_parameter_value = m_binValues.at(parameter_number).at(bin_number_in_bin_values);
827 }
828
829 // everything went fine, so
830 return StatusCode::SUCCESS;
831}
832
833const StatusCode ElectronPhotonVariableCorrectionBase::get2DHistParameter(float& return_parameter_value, const float etaEvalPoint, const float phiEvalPoint, const int parameter_number) const
834{
835 // might need to update eta evaluation point and can't update const float
836 float this_etaEvalPoint = etaEvalPoint;
837 ATH_MSG_VERBOSE("eta = " << this_etaEvalPoint << " phi = " << phiEvalPoint);
838 // make sure the eta eval point is inside the bounds of the histogram (i.e. pretend the lowest bin boundary is -infinity)
839 if (this_etaEvalPoint < m_useAbsEtaTH2.at(parameter_number))
840 {
841 this_etaEvalPoint = m_TH2Copies.at(parameter_number)->GetXaxis()->GetBinCenter(1);
842 ATH_MSG_VERBOSE("eta was out of bounds of TH2, corrected to eta = " << this_etaEvalPoint);
843 }
844 // get the value of the TH2 at the corresponding eta x phi pair
845 const int bin_number = m_TH2Copies.at(parameter_number)->FindBin(this_etaEvalPoint, phiEvalPoint);
846 return_parameter_value = m_TH2Copies.at(parameter_number)->GetBinContent(bin_number);
847 ATH_MSG_VERBOSE("Correction factor:" << return_parameter_value);
848
849 // everything went fine, so
850 return StatusCode::SUCCESS;
851}
852
853
854const StatusCode ElectronPhotonVariableCorrectionBase::findBin(int& return_bin, const float evalPoint, const std::vector<float>& binning)
855{
856 // need to find the bin in which the evalPoint is
857 return_bin = -1;
858 // if the evalPoint is < lowest bin edge, interpolate to -inf and return leftmost value
859 if (evalPoint < binning.at(0))
860 {
861 return_bin = 0;
862 // found bin, no need to continue here
863 return StatusCode::SUCCESS;
864 }
865 // loop over bin boundaries
866 //run only up to binning.size()-1, as running to binning.size() will get a seg fault for the boundary check
867 for (unsigned int bin_itr = 0; bin_itr < binning.size()-1; bin_itr++)
868 {
869 // if the evaluation point is within the checked bins boundaries, this is the value we want
870 if (evalPoint > binning.at(bin_itr) && evalPoint < binning.at(bin_itr + 1))
871 {
872 // we found the according bin, so return the according value
873 return_bin = bin_itr;
874 // we can stop now
875 break;
876 }
877 }
878 //if this point is ever reached and bin == -1, the evaluation point is larger then the largest lowest bin edge
879 //if that's the case, return the value for the last bin
880 //the -1 is because the parameter numbering in a vector starts at 0
881 if (return_bin == -1)
882 {
883 return_bin = binning.size()-1;
884 }
885
886 // everythin went fine, so
887 return StatusCode::SUCCESS;
888}
889
891{
892 bool do_interpolation = false;
893 // get parameter number type
895 // check if parameter has a type for which we need to check if interpolation is wanted
897 {
898 // get the flag
899 do_interpolation = m_interpolatePtFlags.at(parameter_number);
900 }
901 return do_interpolation;
902}
903
904const StatusCode ElectronPhotonVariableCorrectionBase::interpolate(float& return_parameter_value, const float evalPoint, const int bin, const std::vector<float>& binning, const std::vector<float>& binValues) const
905{
906 // check if passed binning is consistent
907 if (binning.size() != binValues.size())
908 {
909 ATH_MSG_ERROR("Binning and bin values have different sizes.");
910 return StatusCode::FAILURE;
911 }
912
913 // if evalPoint is left to the leftmost bin center, return the leftmost bin center without interpolation
914 float leftmost_bin_center = 0;
915 ANA_CHECK(getBinCenter(leftmost_bin_center, binning, 0));
916 if (evalPoint <= leftmost_bin_center)
917 {
918 return_parameter_value = binValues.at(0);
919 return StatusCode::SUCCESS;
920 }
921
922 // if evalPoint is right to the rightmost bin center, return the rightmost bin center without interpolation
923 float rightmost_bin_center = 0;
924 ANA_CHECK(getBinCenter(rightmost_bin_center, binning, binning.size()-1));
925 if (evalPoint >= rightmost_bin_center)
926 {
927 return_parameter_value = binValues.at(binValues.size()-1);
928 return StatusCode::SUCCESS;
929 }
930
931 float left_bin_center = 0;
932 float right_bin_center = 0;
933 float left_bin_value = 0;
934 float right_bin_value = 0;
935 float current_bin_center = 0;
936 ANA_CHECK(getBinCenter(current_bin_center, binning, bin));
937
938 // else interpolate using next left or next right bin
939 if (evalPoint <= current_bin_center)
940 {
941 //interpolate left
942 ANA_CHECK(getBinCenter(left_bin_center, binning, bin-1));
943 ANA_CHECK(getBinCenter(right_bin_center, binning, bin));
944 left_bin_value = binValues.at(bin-1);
945 right_bin_value = binValues.at(bin);
946 }
947 else // evalPoint is right from bin center
948 {
949 //interpolate right
950 ANA_CHECK(getBinCenter(left_bin_center, binning, bin));
951 ANA_CHECK(getBinCenter(right_bin_center, binning, bin+1));
952 left_bin_value = binValues.at(bin);
953 right_bin_value = binValues.at(bin+1);
954 }
955 ATH_MSG_VERBOSE("bin centers : " << left_bin_center << " " << right_bin_center << " current : " << current_bin_center << " values : " << left_bin_value << " " << right_bin_value);
956
957 // calculate return value
958 return_parameter_value = interpolate_function(evalPoint, left_bin_center, left_bin_value, right_bin_center, right_bin_value);
959
960 // everything went fine, so
961 return StatusCode::SUCCESS;
962}
963
964const StatusCode ElectronPhotonVariableCorrectionBase::getBinCenter(float& return_bin_center, const std::vector<float>& binning, const int bin_int) const
965{
966 if (bin_int < 0)
967 {
968 ATH_MSG_ERROR("Bin number must be a non-negative integer.");
969 return StatusCode::FAILURE;
970 }
971
972 // implicitly convert to loong unsigend int for comparisons, to get rid of compiler warnings resulting from comparisons of int and unsigned int
973 long unsigned int bin = bin_int;
974
975 if (bin >= binning.size())
976 {
977 ATH_MSG_ERROR("The requested bin is out of range of the passed binning.");
978 return StatusCode::FAILURE;
979 }
980
981 // need special treatment for rightmost bin center:
982 // it goes up to infinity...assume it's as broad as the
983 // next to the rightmost bin for the interpolation
984 if (bin == binning.size()-1)
985 {
986 //calculate the width of the next to rightmost bin
987 float bin_width = binning.at(bin) - binning.at(bin-1);
988 return_bin_center = binning.at(bin) + 0.5 * bin_width;
989 }
990 // normal calculation
991 else
992 {
993 return_bin_center = 0.5 * (binning.at(bin) + binning.at(bin+1));
994 }
995
996 //everything went fine, so
997 return StatusCode::SUCCESS;
998}
999
1000float ElectronPhotonVariableCorrectionBase::interpolate_function(const float value, const float left_bin_center, const float left_bin_value, const float right_bin_center, const float right_bin_value)
1001{
1002 return left_bin_value + (value - left_bin_center) * (right_bin_value - left_bin_value) / (right_bin_center - left_bin_center);
1003}
1004
1005const StatusCode ElectronPhotonVariableCorrectionBase::getDensity(float& value, const std::string& eventShapeContainer) const
1006{
1007 // retrieve the event shape container
1008 const xAOD::EventShape* evtShape = nullptr;
1009 if(evtStore()->retrieve(evtShape, eventShapeContainer).isFailure()){
1010 ATH_MSG_ERROR("Cannot retrieve density container " << eventShapeContainer);
1011 return StatusCode::FAILURE;
1012 }
1013 // get the density from the container
1014 value = evtShape->getDensity(xAOD::EventShape::Density);
1015 return StatusCode::SUCCESS;
1016}
1017
1019{
1020 // return parameter type according to string given in conf file
1021 if( input == "EtaDependentTGraph")
1023 else if( input == "PtDependentTGraph")
1025 else if( input == "EtaBinned")
1027 else if( input == "PtBinned")
1029 else if( input == "EtaTimesPtBinned")
1031 else if( input == "EtaTimesPhiTH2")
1033 else if( input == "EventDensity")
1035 else
1036 {
1037 // if not a proper type, return failure type - check and fail on this!
1038 ATH_MSG_ERROR(input.c_str() << " is not an allowed parameter type.");
1040 }
1041}
1042
1044{
1045 // return object type which correction should be applied to
1046 if( input == "unconvertedPhotons" )
1048 else if( input == "convertedPhotons" )
1050 else if( input == "allPhotons" )
1052 else if( input == "allElectrons" )
1054 else if( input == "allEGammaObjects" )
1056 else
1057 {
1058 // if not a proper object type, return failure type - check and fail on this!
1059 ATH_MSG_ERROR(input.c_str() << " is not an allowed EGamma object type to apply corrections to.");
1061 }
1062}
1063
1065{
1066 // retrieve if photon is converted or unconverted
1067 bool isConvertedPhoton = xAOD::EgammaHelpers::isConvertedPhoton(&photon);
1068 bool isUnconvertedPhoton = !isConvertedPhoton;
1069
1070 // check if conf file ApplyTo flag matches photon conversion type
1071 return ((applyToConvertedPhotons() && isConvertedPhoton) || (applyToUnconvertedPhotons() && isUnconvertedPhoton));
1072}
1073
1081
1089
1091{
1094 return (applyToAllEGamma || applyToAllElectrons);
1095}
1096
1097
1099{
1100 TRandom3* random = m_TRandom_tls.get();
1101 if (!random) {
1102 random = new TRandom3();
1103 m_TRandom_tls.reset(random);
1104 }
1105 random->SetSeed(seed);
1106 return random;
1107}
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#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,...)
#define ATH_MSG_VERBOSE(x,...)
#define ANA_MSG_VERBOSE(xmsg,...)
Macro printing verbose messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
size_t size() const
Number of registered mappings.
#define x
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
ServiceHandle< StoreGateSvc > & evtStore()
Return value from object correction CP tools.
@ Error
Some error happened during the object correction.
@ Ok
The correction was done successfully.
std::unique_ptr< TFormula > m_correctionFunctionTFormula
The actual TFormula correction function.
std::vector< std::vector< float > > m_binValues
List of eta/pt dependent values, stored if needed by the respective correction function parameter.
boost::thread_specific_ptr< TRandom3 > m_TRandom_tls
thread-safe TRandom3 for setting seed of random smearing correction
const StatusCode getBinCenter(float &return_bin_center, const std::vector< float > &binning, const int bin_int) const
Get the bin center of a bin bin_int using the binning binning.
bool m_retrievedPtBinning
Store if already retrieved pt binning.
bool m_doGaussianSmearing
Whether to apply normal correction or smearing correction.
bool applyToConvertedPhotons() const
Check if the ApplyTo flag passed in the conf file is compatible with converted photons.
const StatusCode getDensity(float &value, const std::string &eventShapeContainer) const
Get the events energy density from the eventShape.
std::vector< float > m_useAbsEtaTH2
Store the lowest eta bin boundary: used for checking if the respective TH2 needs the eta or abs(eta) ...
const StatusCode get2DHistParameter(float &return_parameter_value, const float etaEvalPoint, const float phiEvalPoint, const int parameter_number) const
Get the correction function parameter value if its type is eta- and pT-binned.
bool applyToUnconvertedPhotons() const
Check if the ApplyTo flag passed in the conf file is compatible with uconverted photons.
std::vector< float > m_ptBins
List of bin boundaries in pT, stored if needed by any correction function parameter.
bool m_retrievedEtaBinning
Store if already retrieved eta binning.
bool isEqualToUncorrectedDiscontinuity(const float value) const
Check if the value passed is equal to one of the values passed via the UncorrectedDiscontinuites flag...
parameterType
Use enum and not string for type of function parameter in order to do faster comparisons.
std::unique_ptr< SG::Accessor< float > > m_originalVariable
Accessor to store the original value of the corrected variable.
const StatusCode getEtaPtBinningsFromConf(const bool getEtaBins, const bool getPtBins, const TString &binValues, const TString &interpolate, TEnv &env, const int parameter_number)
Get the eta and pt binning as well as the respective correction values from the given conf file.
std::string m_correctionFunctionString
Function to use for the variable correction, TFormula style.
static const StatusCode findBin(int &return_bin, const float evalPoint, const std::vector< float > &binning)
Find the bin number in which the evalPoint is located in the binning binning.
std::vector< std::unique_ptr< TH2 > > m_TH2Copies
Copy of the TH2 from the root file, stored if needed by the respective correction function parameter.
std::vector< parameterType > m_ParameterTypeVector
Map of the correction function parameter number to the parameter type.
const StatusCode getCorrectionParameters(const float pt, const float eta, const float ph, std::vector< float > &properties) const
Get the actual parameters of the TF1 function used for the current e/y object to be corrected.
std::string m_configFile
The name of the configuration file.
TRandom3 * getTLSRandomGen(unsigned int seed) const
Getting thread safe random number generator (and resetting its seed).
const StatusCode get1DBinnedParameter(float &return_parameter_value, const float evalPoint, const std::vector< float > &binning, const int parameter_number) const
Get the correction function parameter value if its type is eta- or pT-binned.
const CP::CorrectionCode applyCorrection(xAOD::Photon &photon) const
Apply the correction given in the conf file to the passed photon.
std::vector< float > m_uncorrectedDiscontinuities
Values of discontinuities in the variable which should not be corrected.
virtual StatusCode initialize() override
Initialize the class instance.
std::unique_ptr< TObject > getObjectFromRootFile(TEnv &env, const int parameter_number, const TString &filePathKey, const TString &nameKey)
Get a TObject storing corrections (i.e.
const StatusCode getParameterInformationFromConf(TEnv &env, const int parameter_number, const ElectronPhotonVariableCorrectionBase::parameterType type)
Get the relevant information for a correction function parameter from the given conf file.
std::vector< bool > m_interpolatePtFlags
List of bools whether a parameter should use linear interpolation in pT if it's some kind of pT binne...
std::vector< float > m_etaBins
List of bin boundaries in eta, stored if needed by any correction function parameter.
ElectronPhotonVariableCorrectionBase::parameterType stringToParameterType(const std::string &input) const
Convert input string to a parameter function type.
bool getInterpolationFlag(const int parameter_number) const
Return the interpolation flag of parameter parameter_number as a boolean.
const CP::CorrectionCode correctedCopy(const xAOD::Photon &in_photon, xAOD::Photon *&out_photon) const
Make a corrected copy of the passed photon according to the given conf file.
ElectronPhotonVariableCorrectionBase::EGammaObjects stringToEGammaObject(const std::string &input) const
Convert input string to egamma object type.
int m_numberOfFunctionParameters
Number of parameters of the variable correction function.
bool applyToElectrons() const
Check if the ApplyTo flag passed in the conf file is compatible with electrons.
const StatusCode get2DBinnedParameter(float &return_parameter_value, const float etaEvalPoint, const float ptEvalPoint, const int parameter_number) const
Get the correction function parameter value if its type is eta- and pT-binned.
std::string m_correctionVariable
The name of the variable to correct.
ElectronPhotonVariableCorrectionBase(const std::string &myname)
Standard constructor.
static float interpolate_function(const float value, const float left_bin_center, const float left_bin_value, const float right_bin_center, const float right_bin_value)
Returns the linearly intrpolated value of value given the bin centers and bin values.
const StatusCode interpolate(float &return_parameter_value, const float evalPoint, const int bin, const std::vector< float > &binning, const std::vector< float > &binValues) const
Given a point x, approximates the value via linear interpolation based on the two nearest bin centers...
const StatusCode getKinematicProperties(const xAOD::Egamma &egamma_object, float &pt, float &eta, float &phi) const
Get the e/y kinematic properties.
EGammaObjects
Define the categories of EGamma objects tool can be applied to.
std::unique_ptr< SG::Accessor< float > > m_variableToCorrect
Accessor for the variable to be corrected.
bool passedCorrectPhotonType(const xAOD::Photon &photon) const
Check if the photon which was passed to the tool has the correct type, if only (un)converted photons ...
bool m_useAbsEtaBinned
Store if the eta binned parameters need the eta or abs(eta) value for evaluation.
std::vector< std::unique_ptr< TGraph > > m_graphCopies
Copy of the TGraph from the root file, stored if needed by the respective correction function paramet...
ElectronPhotonVariableCorrectionBase::EGammaObjects m_applyToObjects
The type of objects to which the specific conf file settings are allowed to be applied to.
void correct(float &return_corrected_variable, const float original_variable, const std::vector< float > &properties, unsigned int rndSeed=0) const
Actual application of the correction to the variable.
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
float phiBE(const unsigned layer) const
Get the phi in one layer of the EM Calo.
virtual double e() const
The total energy of the particle.
float etaBE(const unsigned layer) const
Get the eta in one layer of the EM Calo.
const xAOD::CaloCluster * caloCluster(size_t index=0) const
Pointer to the xAOD::CaloCluster/s that define the electron candidate.
bool getDensity(EventDensityID id, double &v) const
Get a density variable from the object.
static std::string release
Definition computils.h:54
std::vector< float > HelperFloat(const std::string &input, TEnv &env)
bool isConvertedPhoton(const xAOD::Egamma *eg, bool excludeTRT=false)
is the object a converted photon
CaloCluster_v1 CaloCluster
Define the latest version of the calorimeter cluster class.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Egamma_v1 Egamma
Definition of the current "egamma version".
Definition Egamma.h:17
Photon_v1 Photon
Definition of the current "egamma version".
Definition Photon.h:17
EventShape_v1 EventShape
Definition of the current event format version.
Definition EventShape.h:16
@ eProbabilityHT
Electron probability from High Threshold (HT) information [float].
Electron_v1 Electron
Definition of the current "egamma version".
Definition Electron.h:17
#define unlikely(x)
Extra patterns decribing particle interation process.
TFile * file