ATLAS Offline Software
egammaMVACalibTool.cxx
Go to the documentation of this file.
1  /*
2  Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 
7 #include "xAODEgamma/Egamma.h"
9 
12 
13 #include "TFile.h"
14 #include "TMath.h"
15 #include "TObjString.h"
16 #include "TTree.h"
17 #include "TClass.h"
18 
19 #include <cmath>
20 
21 #ifndef XAOD_ANALYSIS
22 #include "GaudiKernel/SystemOfUnits.h"
23 using Gaudi::Units::GeV;
24 #else
25 #define GeV 1000
26 #endif
27 
29  asg::AsgTool(name)
30 {
31 }
32 
34 {
36  ATH_MSG_FATAL("Particle type not set: you have to set property ParticleType to a valid value");
37  return StatusCode::FAILURE;
38  }
39  ATH_MSG_DEBUG("Initializing with particle " << m_particleType);
40 
41  if (m_shiftType == MEAN10TOTRUE) {
42  ATH_MSG_DEBUG("Using Mean10 shift");
43  } else if (m_shiftType == NOSHIFT) {
44  ATH_MSG_DEBUG("Not using a shift");
45  } else {
46  ATH_MSG_FATAL("Unsupported shift: " << m_shiftType);
47  return StatusCode::FAILURE;
48  }
49 
50  // get the BDTs and initialize functions
51  ATH_MSG_DEBUG("get BDTs in folder: " << m_folder);
52  switch (m_particleType) {
54  {
55  std::unique_ptr<egammaMVAFunctions::funcMap_t> funcLibraryPtr =
57  ATH_CHECK(setupBDT(*funcLibraryPtr,
58  PathResolverFindCalibFile(m_folder + "/MVACalib_electron.weights.root")));
59  }
60  break;
62  {
63  std::unique_ptr<egammaMVAFunctions::funcMap_t> funcLibraryPtr =
65  ATH_CHECK(setupBDT(*funcLibraryPtr,
66  PathResolverFindCalibFile(m_folder + "/MVACalib_unconvertedPhoton.weights.root")));
67  }
68  break;
70  {
71  std::unique_ptr<egammaMVAFunctions::funcMap_t> funcLibraryPtr =
73  ATH_CHECK(setupBDT(*funcLibraryPtr,
74  PathResolverFindCalibFile(m_folder + "/MVACalib_convertedPhoton.weights.root")));
75  }
76  break;
77  default:
78  ATH_MSG_FATAL("Particle type not set properly: " << m_particleType);
79  return StatusCode::FAILURE;
80  }
81 
82  // Load these dictionaries now, so we don't need to try to do so
83  // while multiple threads are running.
84  TClass::GetClass ("TH2Poly");
85  TClass::GetClass ("TMultiGraph");
86 
87  return StatusCode::SUCCESS;
88 }
89 
91  const std::string& fileName)
92 {
93  ATH_MSG_DEBUG("Trying to open " << fileName);
94 
95  std::unique_ptr<TFile> f(TFile::Open(fileName.c_str()));
96  if (!f || f->IsZombie()) {
97  ATH_MSG_FATAL("Could not open file: " << fileName);
98  return StatusCode::FAILURE;
99  }
100 
101  // Load hPoly
102  TH2Poly *hPoly = nullptr;
103  f->GetObject("hPoly", hPoly);
104  if (!hPoly) {
105  ATH_MSG_FATAL("Could not find hPoly");
106  return StatusCode::FAILURE;
107  }
108  //pass ownership to class variable
109  m_hPoly.reset(static_cast<TH2Poly*>(hPoly));
110  m_hPoly->SetDirectory(nullptr);
111 
112  // Load variables
113  TObjArray *variablesTmp = nullptr;
114  f->GetObject("variables", variablesTmp);
115  if (!variablesTmp) {
116  ATH_MSG_FATAL("Could not find variables");
117  return StatusCode::FAILURE;
118  }
119  auto variables = std::unique_ptr<TObjArray>(variablesTmp);
120  variables->SetOwner(); // to delete the objects when d-tor is called
121 
122  // Load shifts
123  TObjArray *shiftsTmp = nullptr;
124  f->GetObject("shifts", shiftsTmp);
125  if (!shiftsTmp) {
126  ATH_MSG_FATAL("Could not find shifts");
127  return StatusCode::FAILURE;
128  }
129  auto shifts = std::unique_ptr<TObjArray>(shiftsTmp);
130  shifts->SetOwner(); // to delete the objects when d-tor is called
131 
132  // Load trees
133  TObjArray *treesTmp = nullptr;
134  std::unique_ptr<TObjArray> trees;
135  f->GetObject("trees", treesTmp);
136  if (treesTmp) {
137  trees = std::unique_ptr<TObjArray>(treesTmp);
138  trees->SetOwner(); // to delete the objects when d-tor is called
139  ATH_MSG_DEBUG("setupBDT " << "BDTs read from TObjArray");
140  } else {
141  ATH_MSG_DEBUG("setupBDT " << "Reading trees individually");
142  trees = std::make_unique<TObjArray>();
143  trees->SetOwner(); // to delete the objects when d-tor is called
144  for (int i = 0; i < variables->GetEntries(); ++i)
145  {
146  TTree *tree = nullptr;
147  f->GetObject(Form("BDT%d", i), tree);
148  if (tree) tree->SetCacheSize(0);
149  trees->AddAtAndExpand(tree, i);
150  }
151  }
152 
153  // Ensure the objects have (the same number of) entries
154  if (!trees->GetEntries() || !(trees->GetEntries() == variables->GetEntries())) {
155  ATH_MSG_FATAL("Tree has size " << trees->GetEntries()
156  << " while variables has size " << variables->GetEntries());
157  return StatusCode::FAILURE;
158  }
159 
160  // Loop simultaneously over trees, variables and shifts
161  // Define the BDTs, the list of variables and the shift for each BDT
162  TObjString *str2;
163  TObjString *shift;
164  TTree *tree;
165  TIter nextTree(trees.get());
166  TIter nextVariables(variables.get());
167  TIter nextShift(shifts.get());
168  for (int i=0; (tree = (TTree*) nextTree()) && ((TObjString*) nextVariables()); ++i)
169  {
170  m_BDTs.emplace_back(tree);
171 
172  std::vector<std::function<float(const xAOD::Egamma*, const xAOD::CaloCluster*)> > funcs;
173  // Loop over variables, which are separated by comma
174  char separator_var = ';';
175  if (getString(variables->At(i)).Index(";") < 1) separator_var = ','; // old versions
176  std::unique_ptr<TObjArray> tokens(getString(variables->At(i)).Tokenize(separator_var));
177  TIter nextVar(tokens.get());
178  while ((str2 = (TObjString*) nextVar()))
179  {
180  const TString& varName = getString(str2);
181  if (!varName.Length()) {
182  ATH_MSG_FATAL("There was an empty variable name!");
183  return StatusCode::FAILURE;
184  }
185  try {
186  funcs.push_back(funcLibrary.at(varName.Data()));
187  } catch(const std::out_of_range& e) {
188  ATH_MSG_FATAL("Could not find formula for variable " << varName << ", error: " << e.what());
189  return StatusCode::FAILURE;
190  }
191  }
192  m_funcs.push_back(std::move(funcs));
193 
194  if (m_shiftType == MEAN10TOTRUE) {
195  shift = (TObjString*) nextShift();
196  const TString& shiftFormula = getString(shift);
197  m_shifts.emplace_back("", shiftFormula);
198  }
199  }
200  return StatusCode::SUCCESS;
201 
202 }
203 
204 const TString& egammaMVACalibTool::getString(TObject* obj)
205 {
206  TObjString *objS = dynamic_cast<TObjString*>(obj);
207  if (!objS) {
208  throw std::runtime_error("egammaMVACalibTool::getString was passed something that was not a string object");
209  }
210  return objS->GetString();
211 }
212 
214  const xAOD::Egamma* eg) const
215 {
216 
217  ATH_MSG_DEBUG("calling getEnergy with cluster index (" << clus.index());
218 
219  // find the bin of BDT and the shift
220  const auto initEnergy = (m_useLayerCorrected ?
223 
224  const auto etVarGeV = (initEnergy / std::cosh(clus.eta())) / GeV;
225  const auto etaVar = std::abs(clus.eta());
226 
227  ATH_MSG_DEBUG("Looking at object with initEnergy = " << initEnergy
228  << ", etVarGeV = " << etVarGeV
229  << ", etaVar = " << etaVar
230  << ", clus->e() = " << clus.e());
231 
232  // Normally, we'd just use FindFixBin here. But TH2Poly overrides FindBin
233  // to handle its special bin definitions, but it doesn't also override
234  // FindFixBin. But TH2Poly::FindBin (unlike TH1::FindBin) doesn't actually
235  // do anything non-const, so just suppress the warning here.
236  TH2Poly* hPoly ATLAS_THREAD_SAFE = m_hPoly.get();
237  const int bin = hPoly->FindBin(etaVar, etVarGeV) - 1; // poly bins are shifted by one
238 
239  ATH_MSG_DEBUG("Using bin: " << bin);
240 
241  if (bin < 0) {
242  ATH_MSG_DEBUG("The bin is under/overflow; just return the energy");
243  return clus.e();
244  }
245 
246  if (bin >= static_cast<int>(m_BDTs.size())) {
247  ATH_MSG_WARNING("The bin is outside the range, so just return the energy");
248  return clus.e();
249  }
250 
251  // select the bdt and functions. (shifts are done later if needed)
252  // if there is only one BDT just use that
253  const int bin_BDT = m_BDTs.size() != 1 ? bin : 0;
254  const auto& bdt = m_BDTs[bin_BDT];
255  const auto& funcs = m_funcs[bin_BDT];
256 
257  const size_t sz = funcs.size();
258 
259  // could consider adding std::array support to the BDTs
260  std::vector<float> vars(sz);
261 
262  for (size_t i = 0; i < sz; ++i) {
263  vars[i] = funcs[i](eg, &clus);
264  }
265 
266  // evaluate the BDT response
267  const float mvaOutput = bdt.GetResponse(vars);
268 
269  // what to do if the MVA response is 0;
270  if (mvaOutput == 0.) {
271  if (m_clusterEif0) {
272  return clus.e();
273  }
274  return 0.;
275  }
276 
277  // calculate the unshifted energy
278  const auto energy = (m_calibrationType == fullCalibration) ?
279  mvaOutput : (initEnergy * mvaOutput);
280 
281  ATH_MSG_DEBUG("energy after MVA = " << energy);
282 
283  if (m_shiftType == NOSHIFT) {
284  // if no shift, just return the unshifted energy
285  return energy;
286  }
287 
288  // have to do a shift if here. It's based on the corrected Et in GeV
289  const auto etGeV = (energy / std::cosh(clus.eta())) / GeV;
290 
291  // evaluate the TFormula associated with the bin
292  const auto shift = m_shifts[bin].Eval(etGeV);
293  ATH_MSG_DEBUG("shift = " << shift);
294  if (shift > 0.5) {
295  return energy / shift;
296  }
297  ATH_MSG_WARNING("Shift value too small: " << shift << "; not applying shift");
298  return energy;
299 
300 }
egammaMVACalibTool::m_calibrationType
Gaudi::Property< int > m_calibrationType
Definition: egammaMVACalibTool.h:98
egammaMVAFunctions::compute_rawcl_Eacc
float compute_rawcl_Eacc(const xAOD::CaloCluster &cl)
Definition: egammaMVAFunctions.h:94
egammaMVACalibTool::m_particleType
Gaudi::Property< int > m_particleType
Definition: egammaMVACalibTool.h:90
python.CaloRecoConfig.f
f
Definition: CaloRecoConfig.py:127
egammaMVAFunctions::funcMap_t
std::unordered_map< std::string, std::function< float(const xAOD::Egamma *, const xAOD::CaloCluster *)> > funcMap_t
Define the map type since it's long.
Definition: egammaMVAFunctions.h:243
ATH_MSG_FATAL
#define ATH_MSG_FATAL(x)
Definition: AthMsgStreamMacros.h:34
egammaMVACalibTool::MEAN10TOTRUE
@ MEAN10TOTRUE
Definition: egammaMVACalibTool.h:83
xAOD::EgammaParameters::convertedPhoton
@ convertedPhoton
Definition: EgammaEnums.h:20
fitman.sz
sz
Definition: fitman.py:527
checkCoolLatestUpdate.variables
variables
Definition: checkCoolLatestUpdate.py:13
ParticleTest.eg
eg
Definition: ParticleTest.py:29
egammaMVACalibTool::setupBDT
StatusCode setupBDT(const egammaMVAFunctions::funcMap_t &funcLibrary, const std::string &fileName)
a function called by initialize to setup the BDT, funcs, and shifts.
Definition: egammaMVACalibTool.cxx:90
egammaMVACalibTool::m_folder
Gaudi::Property< std::string > m_folder
string with folder for weight files
Definition: egammaMVACalibTool.h:107
RTTAlgmain.trees
list trees
Definition: RTTAlgmain.py:40
tree
TChain * tree
Definition: tile_monitor.h:30
asg
Definition: DataHandleTestTool.h:28
bin
Definition: BinsDiffFromStripMedian.h:43
xAOD::Egamma_v1
Definition: Egamma_v1.h:56
beamspotman.tokens
tokens
Definition: beamspotman.py:1284
egammaMVACalibTool::NOSHIFT
@ NOSHIFT
Definition: egammaMVACalibTool.h:83
xAOD::EgammaParameters::NumberOfEgammaTypes
@ NumberOfEgammaTypes
Definition: EgammaEnums.h:21
Egamma.h
xAOD::CaloCluster_v1
Description of a calorimeter cluster.
Definition: CaloCluster_v1.h:59
egammaMVAFunctions::initializeConvertedPhotonFuncs
std::unique_ptr< funcMap_t > initializeConvertedPhotonFuncs(bool useLayerCorrected)
A function to build the map for converted photons.
Definition: egammaMVAFunctions.cxx:72
FortranAlgorithmOptions.fileName
fileName
Definition: FortranAlgorithmOptions.py:13
egammaMVACalibTool::getString
static const TString & getString(TObject *obj)
a utility to get a TString out of an TObjString pointer
Definition: egammaMVACalibTool.cxx:204
ParticleGun_FastCalo_ChargeFlip_Config.energy
energy
Definition: ParticleGun_FastCalo_ChargeFlip_Config.py:78
egammaMVACalibTool::m_useLayerCorrected
Gaudi::Property< bool > m_useLayerCorrected
Definition: egammaMVACalibTool.h:111
xAOD::CaloCluster_v1::eta
virtual double eta() const
The pseudorapidity ( ) of the particle.
Definition: CaloCluster_v1.cxx:251
lumiFormat.i
int i
Definition: lumiFormat.py:92
CaloCluster.h
PixelAthClusterMonAlgCfg.varName
string varName
end cluster ToT and charge
Definition: PixelAthClusterMonAlgCfg.py:117
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
ATH_MSG_DEBUG
#define ATH_MSG_DEBUG(x)
Definition: AthMsgStreamMacros.h:29
egammaMVAFunctions::initializeUnconvertedPhotonFuncs
std::unique_ptr< funcMap_t > initializeUnconvertedPhotonFuncs(bool useLayerCorrected)
A function to build the map for uncoverted photons.
Definition: egammaMVAFunctions.cxx:59
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
egammaMVACalibTool::m_clusterEif0
Gaudi::Property< bool > m_clusterEif0
Definition: egammaMVACalibTool.h:102
egammaMVACalibTool.h
SG::AuxElement::index
size_t index() const
Return the index of this element within its container.
egammaMVACalibTool::m_shifts
std::vector< TFormula > m_shifts
shifts formulas
Definition: egammaMVACalibTool.h:125
egammaMVAFunctions::compute_correctedcl_Eacc
float compute_correctedcl_Eacc(const xAOD::CaloCluster &cl)
Definition: egammaMVAFunctions.h:97
PathResolver.h
egammaMVACalibTool::m_funcs
std::vector< std::vector< std::function< float(const xAOD::Egamma *, const xAOD::CaloCluster *)> > > m_funcs
where the pointers to the funcs to calculate the vars per BDT
Definition: egammaMVACalibTool.h:122
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:192
egammaMVACalibTool::initialize
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
Definition: egammaMVACalibTool.cxx:33
plotBeamSpotVxVal.bin
int bin
Definition: plotBeamSpotVxVal.py:83
egammaMVAFunctions::initializeElectronFuncs
std::unique_ptr< funcMap_t > initializeElectronFuncs(bool useLayerCorrected)
A function to build the map for electrons.
Definition: egammaMVAFunctions.cxx:34
egammaMVACalibTool::getEnergy
float getEnergy(const xAOD::CaloCluster &clus, const xAOD::Egamma *eg) const override final
returns the calibrated energy
Definition: egammaMVACalibTool.cxx:213
PathResolverFindCalibFile
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
Definition: PathResolver.cxx:431
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
xAOD::EgammaParameters::electron
@ electron
Definition: EgammaEnums.h:18
egammaMVACalibTool::m_shiftType
Gaudi::Property< int > m_shiftType
Definition: egammaMVACalibTool.h:94
egammaMVACalibTool::fullCalibration
@ fullCalibration
Definition: egammaMVACalibTool.h:78
ATLAS_THREAD_SAFE
#define ATLAS_THREAD_SAFE
Definition: checker_macros.h:211
egammaMVACalibTool::m_hPoly
std::unique_ptr< TH2Poly > m_hPoly
A TH2Poly used to extract bin numbers. Note there is an offset of 1.
Definition: egammaMVACalibTool.h:116
checker_macros.h
Define macros for attributes used to control the static checker.
python.PyAthena.obj
obj
Definition: PyAthena.py:135
GeV
#define GeV
Definition: CaloTransverseBalanceVecMon.cxx:30
xAOD::CaloCluster_v1::e
virtual double e() const
The total energy of the particle.
Definition: CaloCluster_v1.cxx:265
readCCLHist.float
float
Definition: readCCLHist.py:83
egammaMVACalibTool::m_BDTs
std::vector< MVAUtils::BDT > m_BDTs
Where the BDTs are stored.
Definition: egammaMVACalibTool.h:119
egammaMVACalibTool::egammaMVACalibTool
egammaMVACalibTool(const std::string &type)
Definition: egammaMVACalibTool.cxx:28
xAOD::EgammaParameters::unconvertedPhoton
@ unconvertedPhoton
Definition: EgammaEnums.h:19