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