ATLAS Offline Software
Loading...
Searching...
No Matches
TauCombinedTES.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include "TFile.h"
8
9#include <cmath>
10
11
12
13TauCombinedTES::TauCombinedTES(const std::string& name) :
14 TauRecToolBase(name) {
15}
16
17
18
20
21 std::string calFilePath = find_file(m_calFileName);
22 std::unique_ptr<TFile> calFile(TFile::Open(calFilePath.c_str(), "READ"));
23 ATH_MSG_INFO("Using calibration file: " << calFilePath);
24
25 // 1D array with decay mode as index
26 TH1F* hist = nullptr;
27 TF1* tf1 = nullptr;
28 std::string histName = "";
29 for (size_t decayModeIndex = 0; decayModeIndex < DecayModeBinning; ++ decayModeIndex) {
30 histName = "CorrelationCoeff_tauRec_" + m_decayModeNames[decayModeIndex];
31 hist = dynamic_cast<TH1F*> (calFile->Get(histName.c_str()));
32 if(hist) {
33 hist->SetDirectory(nullptr);
34 m_correlationHists[decayModeIndex] = std::unique_ptr<TH1F>(hist);
35 ATH_MSG_DEBUG("Adding corr hist: " << histName);
36 }
37 else {
38 ATH_MSG_FATAL("Failed to get an object with name " << histName);
39 return StatusCode::FAILURE;
40 }
41
42 histName = "nSigmaCompatibility_" + m_decayModeNames[decayModeIndex];
43 tf1 = dynamic_cast<TF1*> (calFile->Get(histName.c_str()));
44 if(tf1) {
45 m_nSigmaCompatibility[decayModeIndex] = std::unique_ptr<TF1>(tf1);
46 ATH_MSG_DEBUG("Adding compatibility TF1: " << histName);
47 }
48 else {
49 ATH_MSG_FATAL("Failed to get an object with name " << histName);
50 return StatusCode::FAILURE;
51 }
52 }
53
54 // 2D array with (eta, decay mode) as index
55 TGraph* graph = nullptr;
56 std::string graphName="";
57 for (size_t decayModeIndex = 0; decayModeIndex < DecayModeBinning; ++decayModeIndex) {
58 for (size_t etaIndex = 0; etaIndex < EtaBinning; ++etaIndex) {
59 // Calo TES: relative bias
60 graphName = "tauRec/Graph_from_MeanEt_tauRec_" + m_decayModeNames[decayModeIndex] + "_" + m_etaBinNames[etaIndex];
61 graph = dynamic_cast<TGraph*> (calFile->Get(graphName.c_str()));
62 if(graph) {
63 m_caloRelBiasMaxEt[decayModeIndex][etaIndex] = TMath::MaxElement(graph->GetN(), graph->GetX());
64 m_caloRelBias[decayModeIndex][etaIndex] = std::unique_ptr<TGraph>(graph);
65 ATH_MSG_DEBUG("Adding graph: " << graphName);
66 }
67 else {
68 ATH_MSG_FATAL("Failed to get an object with name " << graphName);
69 return StatusCode::FAILURE;
70 }
71
72 // Calo TES: resolution
73 graphName = "tauRec/Graph_from_ResolutionEt_tauRec_" + m_decayModeNames[decayModeIndex] + "_" + m_etaBinNames[etaIndex];
74 graph = dynamic_cast<TGraph*> (calFile->Get(graphName.c_str()));
75 if(graph){
76 m_caloResMaxEt[decayModeIndex][etaIndex] = TMath::MaxElement(graph->GetN(), graph->GetX());
77 m_caloRes[decayModeIndex][etaIndex] = std::unique_ptr<TGraph>(graph);
78 ATH_MSG_DEBUG("Adding graph: " << graphName);
79 }
80 else {
81 ATH_MSG_FATAL("Failed to get an object with name " << graphName);
82 return StatusCode::FAILURE;
83 }
84
85 // PanTau: relative bias
86 graphName = "ConstituentEt/Graph_from_MeanEt_ConstituentEt_" + m_decayModeNames[decayModeIndex] + "_" + m_etaBinNames[etaIndex];
87 graph = dynamic_cast<TGraph*> (calFile->Get(graphName.c_str()));
88 if(graph){
89 m_panTauRelBiasMaxEt[decayModeIndex][etaIndex] = TMath::MaxElement(graph->GetN(), graph->GetX());
90 m_panTauRelBias[decayModeIndex][etaIndex] = std::unique_ptr<TGraph>(graph);
91 ATH_MSG_DEBUG("Adding graph: " << graphName);
92 }
93 else {
94 ATH_MSG_FATAL("Failed to get an object with name " << graphName);
95 return StatusCode::FAILURE;
96 }
97
98 // PanTau: resolution
99 graphName = "ConstituentEt/Graph_from_ResolutionEt_ConstituentEt_" + m_decayModeNames[decayModeIndex] + "_" + m_etaBinNames[etaIndex];
100 graph = dynamic_cast<TGraph*> (calFile->Get(graphName.c_str()));
101 if(graph){
102 m_panTauResMaxEt[decayModeIndex][etaIndex] = TMath::MaxElement(graph->GetN(), graph->GetX());
103 m_panTauRes[decayModeIndex][etaIndex] = std::unique_ptr<TGraph>(graph);
104 ATH_MSG_DEBUG("Adding graph: " << graphName);
105 }
106 else {
107 ATH_MSG_FATAL("Failed to get an object with name " << graphName);
108 return StatusCode::FAILURE;
109 }
110
111 // MVA resolution, optional
113 graphName = "FinalCalib/Graph_from_ResolutionEt_FinalCalib_" + m_decayModeNames[decayModeIndex] + "_" + m_etaBinNames[etaIndex];
114 graph = dynamic_cast<TGraph*> (calFile->Get(graphName.c_str()));
115 if(graph){
116 m_mvaResMaxEt[decayModeIndex][etaIndex] = TMath::MaxElement(graph->GetN(), graph->GetX());
117 m_mvaRes[decayModeIndex][etaIndex] = std::unique_ptr<TGraph>(graph);
118 ATH_MSG_DEBUG("Adding graph: " << graphName);
119 }
120 else {
121 ATH_MSG_FATAL("Failed to get an object with name " << graphName);
122 return StatusCode::FAILURE;
123 }
124 }
125 }
126 }
127 calFile->Close();
128
129 return StatusCode::SUCCESS;
130}
131
132
133
134StatusCode TauCombinedTES::execute(xAOD::TauJet& tau) const {
135 TLorentzVector combinedP4(tau.p4(xAOD::TauJetParameters::TauEnergyScale));
136
137 // used to store immediate results
138 Variables variables;
139
140 // Parameterization is only valid for |eta| < 2.5, and decay modes of 1p0n, 1p1n, 1pXn, 3p0n, 3pXn
141 // If these variables of the given tau candidate are outside the range, we just use calo TES
142 if(isValid(tau)) {
143 combinedP4 = getCombinedP4(tau, variables);
144 }
145
146 static const SG::Accessor<float> decPtCombined("ptCombined");
147 static const SG::Accessor<float> decEtaCombined("etaCombined");
148 static const SG::Accessor<float> decPhiCombined("phiCombined");
149 static const SG::Accessor<float> decMCombined("mCombined");
150
151 decPtCombined(tau) = combinedP4.Pt();
152 decEtaCombined(tau) = combinedP4.Eta();
153 decPhiCombined(tau) = combinedP4.Phi();
154 decMCombined(tau) = combinedP4.M();
155
157 static const SG::Accessor<float> decPtConstituent("pt_constituent");
158 static const SG::Accessor<float> decPtTauRecCalibrated("pt_tauRecCalibrated");
159 static const SG::Accessor<float> decPtWeighted("pt_weighted");
160 static const SG::Accessor<float> decWeightWeighted("weight_weighted");
161 static const SG::Accessor<float> decSigmaCompatibility("sigma_compatibility");
162 static const SG::Accessor<float> decSigmaTaurec("sigma_tauRec");
163 static const SG::Accessor<float> decSigmaConstituent("sigma_constituent");
164 static const SG::Accessor<float> decCorrelationCoefficient("correlation_coefficient");
165
166 decPtConstituent(tau) = variables.pt_constituent;
167 decPtTauRecCalibrated(tau) = variables.pt_tauRecCalibrated;
168 decPtWeighted(tau) = variables.pt_weighted;
169 decWeightWeighted(tau) = variables.weight;
170 decSigmaCompatibility(tau) = variables.sigma_compatibility;
171 decSigmaTaurec(tau) = variables.sigma_tauRec;
172 decSigmaConstituent(tau) = variables.sigma_constituent;
173 decCorrelationCoefficient(tau) = variables.corrcoeff;
174 }
175
176 return StatusCode::SUCCESS;
177}
178
179
180
182 if (! isValid(tau)) return false;
183
185 int decayModeIndex = getDecayModeIndex(decayMode);
186
187 int etaIndex = getEtaIndex(tau.etaTauEnergyScale());
188
189 double caloSigma = tau.ptTauEnergyScale() * getCaloResolution(tau.ptTauEnergyScale(), decayModeIndex, etaIndex);
190 double deltaEt = tau.ptFinalCalib() - tau.ptTauEnergyScale();
191
192 bool compatibility = true;
193
194 // FIXME: should we use combinedSigma here ??
195 if (std::abs(deltaEt) > 5 * caloSigma) {
196 compatibility = false;
197 }
198
199 return compatibility;
200}
201
202
203
205 // It would be better to retrieve eta bins from the calibration file, e.g. for upgrade studies!
206 float abseta = std::abs(eta);
207
208 if (abseta < 0.3) {
209 return 0;
210 }
211 if (abseta < 0.8) {
212 return 1;
213 }
214 if (abseta < 1.3) {
215 return 2;
216 }
217 if (abseta < 1.6) {
218 return 3;
219 }
220 // slightly extend the tau eta range, as |eta|<2.5 applies to the seed jet
221 if (abseta < 2.6) {
222 return 4;
223 }
224
225 return 99;
226}
227
228
229
236
237
238
240 return static_cast<int>(decayMode);
241}
242
243
244
245bool TauCombinedTES::isValid(const xAOD::TauJet& tau) const {
247 if (decayMode < xAOD::TauJetParameters::Mode_1p0n || decayMode > xAOD::TauJetParameters::Mode_3pXn) {
248 ATH_MSG_DEBUG("Decay mode is not supported !");
249 return false;
250 }
251
252 int etaIndex = getEtaIndex(tau.etaTauEnergyScale());
253 if (etaIndex > 4) {
254 ATH_MSG_DEBUG("Eta is out of the supported range !");
255 return false;
256 }
257
258 return true;
259}
260
261
262
263double TauCombinedTES::getCorrelation(int decayModeIndex, int etaIndex) const {
264 return m_correlationHists[decayModeIndex]->GetBinContent(etaIndex);
265}
266
267
268
269double TauCombinedTES::getCaloCalEt(double caloEt,
270 int decayModeIndex,
271 int etaIndex) const {
272 // ratio stored in the calibration graph equals (caloEt-truthEt)/caloEt
273 double ratio = 0.0;
274
275 // FIXME: If caloEt is larger than max et, could we use the ratio at
276 // max et, instead of setting it to zero
277 if (caloEt <= m_caloRelBiasMaxEt[decayModeIndex][etaIndex]) {
278 ratio = m_caloRelBias[decayModeIndex][etaIndex]->Eval(caloEt);
279 }
280
281 double caloCalEt = caloEt - ratio * caloEt;
282
283 return caloCalEt;
284}
285
286
287
288double TauCombinedTES::getPanTauCalEt(double panTauEt,
289 int decayModeIndex,
290 int etaIndex) const {
291 // ratio stored in the calibration graph equals (panTauEt-truthEt)/panTauEt
292 double ratio = 0.0;
293
294 // Substructure is badly determined at high pt, as track momentum is pooryly measured
295 if (panTauEt <= m_panTauRelBiasMaxEt[decayModeIndex][etaIndex]) {
296 ratio = m_panTauRelBias[decayModeIndex][etaIndex]->Eval(panTauEt);
297 }
298
299 double panTauCalEt = panTauEt - ratio * panTauEt;
300
301 return panTauCalEt;
302}
303
304
305
307 // Assume the resolution to be 100% when no parametrisation is available
308 // "validity" criteria might have to be revised if such "invalid taus" end up in analyses
309 if (!isValid(tau) || !m_useMvaResolution) return 1.0;
310
312 int decayModeIndex = getDecayModeIndex(decayMode);
313
314 int etaIndex = getEtaIndex(tau.etaFinalCalib());
315
316 double pt = std::min(tau.ptFinalCalib(), m_mvaResMaxEt[decayModeIndex][etaIndex]);
317 double resolution = m_mvaRes[decayModeIndex][etaIndex]->Eval(pt);
318
319 return resolution;
320}
321
322
323
324double TauCombinedTES::getCaloResolution(double et, int decayModeIndex, int etaIndex) const {
325 double x = std::min(et, m_caloResMaxEt[decayModeIndex][etaIndex]);
326 double resolution = m_caloRes[decayModeIndex][etaIndex]->Eval(x);
327
328 return resolution;
329}
330
331
332
333double TauCombinedTES::getPanTauResolution(double et, int decayModeIndex, int etaIndex) const {
334 double x = std::min(et, m_panTauResMaxEt[decayModeIndex][etaIndex]);
335 double resolution = m_panTauRes[decayModeIndex][etaIndex]->Eval(x);
336
337 return resolution;
338}
339
340
341
342double TauCombinedTES::getWeight(double caloSigma,
343 double panTauSigma,
344 double correlation) const {
345 double cov = correlation * caloSigma * panTauSigma;
346 double caloWeight = std::pow(panTauSigma, 2) - cov;
347 double panTauWeight = std::pow(caloSigma, 2) - cov;
348
349 double weight = (caloWeight + panTauWeight !=0.) ? caloWeight/(caloWeight + panTauWeight) : 0.;
350 // enforce that the weight is within [0,1]
351 return std::clamp(weight, 0., 1.);
352}
353
355 double panTauSigma,
356 double correlation) const {
357 double compatibilitySigma2 = std::pow(caloSigma, 2) + std::pow(panTauSigma, 2) - 2 * correlation * caloSigma * panTauSigma;
358
359 return std::sqrt(compatibilitySigma2);
360}
361
362
363
364double TauCombinedTES::getNsigmaCompatibility(double et, int decayModeIndex) const {
365 double nsigma = m_nSigmaCompatibility.at(decayModeIndex)->Eval(et);
366
367 if (nsigma < 0.) return 0.;
368
369 return nsigma;
370}
371
372
373
374double TauCombinedTES::getCombinedEt(double caloEt,
375 double panTauEt,
377 float eta,
378 Variables& variables) const {
379 // Obtain the index of calibration graph
380 int decayModeIndex = getDecayModeIndex(decayMode);
381 int etaIndex = getEtaIndex(eta);
382
383 // Obtain the calibration parameter based on the index
384 // -- Correlation between calo TES and PanTau
385 double correlation = getCorrelation(decayModeIndex, etaIndex);
386
387 // -- Sigma of the difference between reconstruted et and truth et at calo TES
388 double caloSigma = caloEt * getCaloResolution(caloEt, decayModeIndex, etaIndex);
389 if (0. == caloSigma) {
390 ATH_MSG_WARNING("Calo TES: Et resolution at " << caloEt << " is 0");
391 m_caloRes[decayModeIndex][etaIndex]->Print("all");
392 return 0.;
393 }
394
395 // -- Sigma of the difference between reconstruted et and truth et at PanTau
396 double panTauSigma = panTauEt * getPanTauResolution(panTauEt, decayModeIndex, etaIndex);
397 if (0. == panTauSigma) {
398 ATH_MSG_WARNING("PanTau: Et resolution at " << panTauEt << " is 0");
399 m_panTauRes[decayModeIndex][etaIndex]->Print("all");
400 return 0.;
401 }
402
403 // -- Et at calo TES with bias corrected
404 double caloCalEt = getCaloCalEt(caloEt, decayModeIndex, etaIndex);
405
406 // -- Et at PanTau with bias corrected
407 double panTauCalEt = getPanTauCalEt(panTauEt, decayModeIndex, etaIndex);
408
409 // Combination of calo TES and PanTau
410 // FIXME: A more consistent way would be calculating the weight use bias corrected Et as input
411 double weight = getWeight(caloSigma, panTauSigma, correlation);
412 double weightedEt = weight * caloCalEt + (1 - weight) * panTauCalEt;
413 double compatibilitySigma = getCompatibilitySigma(caloSigma, panTauSigma, correlation);
414
415 // If the difference of calo TES and PanTau is too large, the combined result
416 // may not be reliable
417 // FIXME: A more consistent way would be calculating the NsigmaCompatibility use caloCalEt
418 double deltaEt = caloCalEt - panTauCalEt;
419 if (std::abs(deltaEt) > getNsigmaCompatibility(caloEt, decayModeIndex) * compatibilitySigma) {
420 // FIXME: Why not use caloCalEt here ?
421 weightedEt = caloEt;
422 }
423
424 // Store the results
425 variables.corrcoeff = correlation;
426 variables.sigma_tauRec = caloSigma;
427 variables.sigma_constituent = panTauSigma;
428 variables.pt_tauRecCalibrated = caloCalEt;
429 variables.pt_constituent = panTauCalEt;
430 variables.pt_weighted = weightedEt;
431 variables.weight = weight;
432 variables.sigma_compatibility = compatibilitySigma;
433
434 ATH_MSG_DEBUG("Intermediate results\n" <<
435 "coff: " << correlation << " sigma(calo): " << caloSigma << " sigma(constituent): " << panTauSigma <<
436 "\ncalibrated et(calo): " << caloCalEt << " calibrated et(constituent): " << panTauCalEt <<
437 "\nweight:" << weight << " combined et: " << weightedEt << " compatibility sigma: " << compatibilitySigma);
438
439 return weightedEt;
440}
441
442
443
444TLorentzVector TauCombinedTES::getCombinedP4(const xAOD::TauJet& tau, Variables& variables) const {
445 TLorentzVector caloP4 = tau.p4(xAOD::TauJetParameters::TauEnergyScale);
446 TLorentzVector panTauP4 = tau.p4(xAOD::TauJetParameters::PanTauCellBased);
447
448 ATH_MSG_DEBUG("Four momentum at calo TES, pt: " << caloP4.Pt() << " eta: " << caloP4.Eta() <<
449 " phi: " << caloP4.Phi() << " mass: " << caloP4.M());
450 ATH_MSG_DEBUG("Four momentum at PanTau, pt: " << panTauP4.Pt() << " eta: " << panTauP4.Eta() <<
451 " phi: " << panTauP4.Phi() << " mass: " << panTauP4.M());
452
454
455 double combinedEt = getCombinedEt(caloP4.Et(), panTauP4.Et(), decayMode, caloP4.Eta(), variables);
456
457 // Et is the combination of calo TES and PanTau, but eta and phi is from PanTau
458 TLorentzVector combinedP4;
459 combinedP4.SetPtEtaPhiM(combinedEt, panTauP4.Eta(), panTauP4.Phi(), 0.);
460
461 ATH_MSG_DEBUG("Combined four momentum, pt: " << combinedP4.Pt() << " eta: " << combinedP4.Eta() <<
462 " phi: " << combinedP4.Phi() << " mass: " << combinedP4.M());
463
464 return combinedP4;
465}
Scalar eta() const
pseudorapidity method
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define x
Helper class to provide type-safe access to aux data.
const std::array< std::string, DecayModeBinning > m_decayModeNames
Decay mode binning in the calibration graph/hist.
const std::array< std::string, EtaBinning > m_etaBinNames
Eta binning in the calibration graph.
double getWeight(double caloSigma, double panTauSigma, double correlatioon) const
Get the weight of calo TES.
Gaudi::Property< std::string > m_calFileName
std::array< std::array< std::unique_ptr< TGraph >, EtaBinning >, DecayModeBinning > m_caloRelBias
Calibration graph: mean of bias/caloEt as a function of caloEt.
int getEtaIndex(float eta) const
Get the index of eta in the calibration histogram.
xAOD::TauJetParameters::DecayMode getDecayMode(const xAOD::TauJet &tau) const
Get the decay mode of the tau candidate.
Gaudi::Property< bool > m_addCalibrationResultVariables
double getCaloResolution(double et, int decayModeIndex, int etaIndex) const
Get the resolution of Et at the calo TES.
std::array< std::unique_ptr< TH1F >, DecayModeBinning > m_correlationHists
Calibration histogram: correlation coefficient of calo TES and PanTau.
std::array< std::array< double, EtaBinning >, DecayModeBinning > m_caloRelBiasMaxEt
Maximum Et of m_caloRelBias.
std::array< std::array< double, EtaBinning >, DecayModeBinning > m_panTauRelBiasMaxEt
Maximum Et of m_panTauRelBias.
double getMvaEnergyResolution(const xAOD::TauJet &tau) const
Get MVA Et resolution, invoked by METSignificance.
bool isValid(const xAOD::TauJet &tau) const
Whether the tau candidate is valid for the calculation.
bool getTESCompatibility(const xAOD::TauJet &tau) const
Check if MVA TES and CaloTES are compatible, invoked by TauSmearing tool.
std::array< std::array< double, EtaBinning >, DecayModeBinning > m_mvaResMaxEt
Maximum Et of m_mvaRes.
virtual StatusCode initialize() override
Tool initializer.
std::array< std::array< std::unique_ptr< TGraph >, EtaBinning >, DecayModeBinning > m_mvaRes
Calibration graph: MVA TES resolution as a function of MVA pt.
double getPanTauResolution(double et, int decayModeIndex, int etaIndex) const
Get the resolution of Et at PanTau.
double getCompatibilitySigma(double caloSigma, double panTauSigma, double correlation) const
Get the compatibility sigma of calo TES and PanTau.
std::array< std::array< std::unique_ptr< TGraph >, EtaBinning >, DecayModeBinning > m_panTauRes
Calibration graph: resolution at PanTau as a function of panTauEt.
std::array< std::array< std::unique_ptr< TGraph >, EtaBinning >, DecayModeBinning > m_panTauRelBias
Calibration graph: mean of bias/panTauEt as a funtion of panTauEt.
std::array< std::array< double, EtaBinning >, DecayModeBinning > m_caloResMaxEt
Maximum Et of m_caloRes.
std::array< std::array< double, EtaBinning >, DecayModeBinning > m_panTauResMaxEt
Maximum Et of m_panTauRes.
Gaudi::Property< bool > m_useMvaResolution
TLorentzVector getCombinedP4(const xAOD::TauJet &tau, Variables &variables) const
Get the weighted four momentum of calo TES and PanTau.
double getCaloCalEt(double et, int decayModeIndex, int etaIndex) const
Get the Et at the calo TES after calibration correction.
std::array< std::array< std::unique_ptr< TGraph >, EtaBinning >, DecayModeBinning > m_caloRes
Calibration graph: resolution at Calo TES as a function of caloEt.
int getDecayModeIndex(xAOD::TauJetParameters::DecayMode decayMode) const
Get the index of decay mode in the calibration histogram.
double getCorrelation(int decayModeIndex, int etaIndex) const
Get correlation coefficient between the calo TES and PanTau.
virtual StatusCode execute(xAOD::TauJet &xTau) const override
Execute - called for each tau candidate.
double getNsigmaCompatibility(double caloEt, int decayModeIndex) const
Get the allowed difference between calo TES and PanTau.
double getPanTauCalEt(double panTauEt, int decayModeIndex, int etaIndex) const
Get the Et at PanTau after calibration correction.
TauCombinedTES(const std::string &name="TauCombinedTES")
std::array< std::unique_ptr< TF1 >, DecayModeBinning > m_nSigmaCompatibility
Maximum tolerence in unit of combined sigma, as a function of calo Et.
double getCombinedEt(double caloEt, double et_substructure, xAOD::TauJetParameters::DecayMode decayMode, float eta, Variables &variables) const
Get the combined Et of calo TES and PanTau.
TauRecToolBase(const std::string &name)
std::string find_file(const std::string &fname) const
double etaFinalCalib() const
double ptTauEnergyScale() const
double etaTauEnergyScale() const
virtual FourMom_t p4() const
The full 4-momentum of the particle.
Definition TauJet_v3.cxx:96
double ptFinalCalib() const
bool panTauDetail(TauJetParameters::PanTauDetails panTauDetail, int &value) const
Get and set values of pantau details variables via enum.
TauJet_v3 TauJet
Definition of the current "tau version".
Extra patterns decribing particle interation process.