ATLAS Offline Software
Loading...
Searching...
No Matches
TauCombinedTES.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 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.at(etaIndex);
114 graph = dynamic_cast<TGraph*> (calFile->Get(graphName.c_str()));
115 if(graph){
116 m_mvaResMaxEt.at(decayModeIndex).at(etaIndex) = TMath::MaxElement(graph->GetN(), graph->GetX());
117 m_mvaRes.at(decayModeIndex).at(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
134 const EventContext& /*ctx*/) const {
135
136 TLorentzVector combinedP4(tau.p4(xAOD::TauJetParameters::TauEnergyScale));
137
138 // Parameterization is only valid for |eta| < 2.5, and decay modes of 1p0n, 1p1n, 1pXn, 3p0n, 3pXn
139 // If these variables of the given tau candidate are outside the range, we just use calo TES
140 if(isValid(tau)) {
141 combinedP4 = getCombinedP4(tau);
142 }
143
144 static const SG::Accessor<float> decPtCombined("ptCombined");
145 static const SG::Accessor<float> decEtaCombined("etaCombined");
146 static const SG::Accessor<float> decPhiCombined("phiCombined");
147 static const SG::Accessor<float> decMCombined("mCombined");
148
149 decPtCombined(tau) = combinedP4.Pt();
150 decEtaCombined(tau) = combinedP4.Eta();
151 decPhiCombined(tau) = combinedP4.Phi();
152 decMCombined(tau) = combinedP4.M();
153
154 return StatusCode::SUCCESS;
155}
156
157
158
160 if (! isValid(tau)) return false;
161
162 xAOD::TauJetParameters::DecayMode decayMode = getDecayMode(tau); //can return 7
163 int decayModeIndex = getDecayModeIndex(decayMode);
164
165 int etaIndex = getEtaIndex(tau.etaTauEnergyScale());
166
167 double caloSigma = tau.ptTauEnergyScale() * getCaloResolution(tau.ptTauEnergyScale(), decayModeIndex, etaIndex);
168 double deltaEt = tau.ptFinalCalib() - tau.ptTauEnergyScale();
169
170 bool compatibility = true;
171
172 // FIXME: should we use combinedSigma here ??
173 if (std::abs(deltaEt) > 5 * caloSigma) {
174 compatibility = false;
175 }
176
177 return compatibility;
178}
179
180
181
183 // It would be better to retrieve eta bins from the calibration file, e.g. for upgrade studies!
184 float abseta = std::abs(eta);
185
186 if (abseta < 0.3) {
187 return 0;
188 }
189 if (abseta < 0.8) {
190 return 1;
191 }
192 if (abseta < 1.3) {
193 return 2;
194 }
195 if (abseta < 1.6) {
196 return 3;
197 }
198 // slightly extend the tau eta range, as |eta|<2.5 applies to the seed jet
199 if (abseta < 2.6) {
200 return 4;
201 }
202
203 return 99;
204}
205
206
207
214
215
216
218 return static_cast<int>(decayMode);
219}
220
221
222
223bool TauCombinedTES::isValid(const xAOD::TauJet& tau) const {
225 if (decayMode < xAOD::TauJetParameters::Mode_1p0n || decayMode > xAOD::TauJetParameters::Mode_3pXn) {
226 ATH_MSG_DEBUG("Decay mode is not supported !");
227 return false;
228 }
229
230 int etaIndex = getEtaIndex(tau.etaTauEnergyScale());
231 if (etaIndex > 4) {
232 ATH_MSG_DEBUG("Eta is out of the supported range !");
233 return false;
234 }
235
236 return true;
237}
238
239
240
241double TauCombinedTES::getCorrelation(int decayModeIndex, int etaIndex) const {
242 return m_correlationHists.at(decayModeIndex)->GetBinContent(etaIndex);
243}
244
245
246
247double TauCombinedTES::getCaloCalEt(double caloEt,
248 int decayModeIndex,
249 int etaIndex) const {
250 // ratio stored in the calibration graph equals (caloEt-truthEt)/caloEt
251 double ratio = 0.0;
252
253 // FIXME: If caloEt is larger than max et, could we use the ratio at
254 // max et, instead of setting it to zero
255 if (caloEt <= m_caloRelBiasMaxEt.at(decayModeIndex).at(etaIndex)) {
256 ratio = m_caloRelBias.at(decayModeIndex).at(etaIndex)->Eval(caloEt);
257 }
258
259 double caloCalEt = caloEt - ratio * caloEt;
260
261 return caloCalEt;
262}
263
264
265
266double TauCombinedTES::getPanTauCalEt(double panTauEt,
267 int decayModeIndex,
268 int etaIndex) const {
269 // ratio stored in the calibration graph equals (panTauEt-truthEt)/panTauEt
270 double ratio = 0.0;
271
272 // Substructure is badly determined at high pt, as track momentum is pooryly measured
273 if (panTauEt <= m_panTauRelBiasMaxEt.at(decayModeIndex).at(etaIndex)) {
274 ratio = m_panTauRelBias.at(decayModeIndex).at(etaIndex)->Eval(panTauEt);
275 }
276
277 double panTauCalEt = panTauEt - ratio * panTauEt;
278
279 return panTauCalEt;
280}
281
282
283
285 // Assume the resolution to be 100% when no parametrisation is available
286 // "validity" criteria might have to be revised if such "invalid taus" end up in analyses
287 if (!isValid(tau) || !m_useMvaResolution) return 1.0;
288
290 int decayModeIndex = getDecayModeIndex(decayMode);
291
292 int etaIndex = getEtaIndex(tau.etaFinalCalib());
293
294 double pt = std::min(tau.ptFinalCalib(), m_mvaResMaxEt.at(decayModeIndex).at(etaIndex));
295 double resolution = m_mvaRes.at(decayModeIndex).at(etaIndex)->Eval(pt);
296
297 return resolution;
298}
299
300
301
302double TauCombinedTES::getCaloResolution(double et, int decayModeIndex, int etaIndex) const {
303 double x = std::min(et, m_caloResMaxEt.at(decayModeIndex).at(etaIndex));
304 double resolution = m_caloRes.at(decayModeIndex).at(etaIndex)->Eval(x);
305
306 return resolution;
307}
308
309
310
311double TauCombinedTES::getPanTauResolution(double et, int decayModeIndex, int etaIndex) const {
312 double x = std::min(et, m_panTauResMaxEt.at(decayModeIndex).at(etaIndex));
313 double resolution = m_panTauRes.at(decayModeIndex).at(etaIndex)->Eval(x);
314
315 return resolution;
316}
317
318
319
320double TauCombinedTES::getWeight(double caloSigma,
321 double panTauSigma,
322 double correlation) const {
323 double cov = correlation * caloSigma * panTauSigma;
324 double caloWeight = std::pow(panTauSigma, 2) - cov;
325 double panTauWeight = std::pow(caloSigma, 2) - cov;
326
327 double weight = (caloWeight + panTauWeight !=0.) ? caloWeight/(caloWeight + panTauWeight) : 0.;
328 // enforce that the weight is within [0,1]
329 return std::clamp(weight, 0., 1.);
330}
331
333 double panTauSigma,
334 double correlation) const {
335 double compatibilitySigma2 = std::pow(caloSigma, 2) + std::pow(panTauSigma, 2) - 2 * correlation * caloSigma * panTauSigma;
336
337 return std::sqrt(compatibilitySigma2);
338}
339
340
341
342double TauCombinedTES::getNsigmaCompatibility(double et, int decayModeIndex) const {
343 double nsigma = m_nSigmaCompatibility.at(decayModeIndex)->Eval(et);
344
345 if (nsigma < 0.) return 0.;
346
347 return nsigma;
348}
349
350
351
352double TauCombinedTES::getCombinedEt(double caloEt,
353 double panTauEt,
355 float eta) const {
356 // Obtain the index of calibration graph
357 int decayModeIndex = getDecayModeIndex(decayMode);
358 int etaIndex = getEtaIndex(eta);
359
360 // Obtain the calibration parameter based on the index
361 // -- Correlation between calo TES and PanTau
362 double correlation = getCorrelation(decayModeIndex, etaIndex);
363
364 // -- Sigma of the difference between reconstruted et and truth et at calo TES
365 double caloSigma = caloEt * getCaloResolution(caloEt, decayModeIndex, etaIndex);
366 if (0. == caloSigma) {
367 ATH_MSG_WARNING("Calo TES: Et resolution at " << caloEt << " is 0");
368 m_caloRes.at(decayModeIndex)[etaIndex]->Print("all");
369 return 0.;
370 }
371
372 // -- Sigma of the difference between reconstruted et and truth et at PanTau
373 double panTauSigma = panTauEt * getPanTauResolution(panTauEt, decayModeIndex, etaIndex);
374 if (0. == panTauSigma) {
375 ATH_MSG_WARNING("PanTau: Et resolution at " << panTauEt << " is 0");
376 m_panTauRes.at(decayModeIndex).at(etaIndex)->Print("all");
377 return 0.;
378 }
379
380 // -- Et at calo TES with bias corrected
381 double caloCalEt = getCaloCalEt(caloEt, decayModeIndex, etaIndex);
382
383 // -- Et at PanTau with bias corrected
384 double panTauCalEt = getPanTauCalEt(panTauEt, decayModeIndex, etaIndex);
385
386 // Combination of calo TES and PanTau
387 // FIXME: A more consistent way would be calculating the weight use bias corrected Et as input
388 double weight = getWeight(caloSigma, panTauSigma, correlation);
389 double weightedEt = weight * caloCalEt + (1 - weight) * panTauCalEt;
390 double compatibilitySigma = getCompatibilitySigma(caloSigma, panTauSigma, correlation);
391
392 // If the difference of calo TES and PanTau is too large, the combined result
393 // may not be reliable
394 // FIXME: A more consistent way would be calculating the NsigmaCompatibility use caloCalEt
395 double deltaEt = caloCalEt - panTauCalEt;
396 if (std::abs(deltaEt) > getNsigmaCompatibility(caloEt, decayModeIndex) * compatibilitySigma) {
397 // FIXME: Why not use caloCalEt here ?
398 weightedEt = caloEt;
399 }
400
401 ATH_MSG_DEBUG("Intermediate results\n" <<
402 "coff: " << correlation << " sigma(calo): " << caloSigma << " sigma(constituent): " << panTauSigma <<
403 "\ncalibrated et(calo): " << caloCalEt << " calibrated et(constituent): " << panTauCalEt <<
404 "\nweight:" << weight << " combined et: " << weightedEt << " compatibility sigma: " << compatibilitySigma);
405
406 return weightedEt;
407}
408
409
410
411TLorentzVector TauCombinedTES::getCombinedP4(const xAOD::TauJet& tau) const {
412 TLorentzVector caloP4 = tau.p4(xAOD::TauJetParameters::TauEnergyScale);
413 TLorentzVector panTauP4 = tau.p4(xAOD::TauJetParameters::PanTauCellBased);
414
415 ATH_MSG_DEBUG("Four momentum at calo TES, pt: " << caloP4.Pt() << " eta: " << caloP4.Eta() <<
416 " phi: " << caloP4.Phi() << " mass: " << caloP4.M());
417 ATH_MSG_DEBUG("Four momentum at PanTau, pt: " << panTauP4.Pt() << " eta: " << panTauP4.Eta() <<
418 " phi: " << panTauP4.Phi() << " mass: " << panTauP4.M());
419
421
422 double combinedEt = getCombinedEt(caloP4.Et(), panTauP4.Et(), decayMode, caloP4.Eta());
423
424 // Et is the combination of calo TES and PanTau, but eta and phi is from PanTau
425 TLorentzVector combinedP4;
426 combinedP4.SetPtEtaPhiM(combinedEt, panTauP4.Eta(), panTauP4.Phi(), 0.);
427
428 ATH_MSG_DEBUG("Combined four momentum, pt: " << combinedP4.Pt() << " eta: " << combinedP4.Eta() <<
429 " phi: " << combinedP4.Phi() << " mass: " << combinedP4.M());
430
431 return combinedP4;
432}
Scalar eta() const
pseudorapidity method
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_WARNING(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(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.
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 getCombinedEt(double caloEt, double et_substructure, xAOD::TauJetParameters::DecayMode decayMode, float eta) const
Get the combined Et of calo TES and 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.
virtual StatusCode executeTool(xAOD::TauJet &xTau, const EventContext &ctx) const override
Execute - called for each tau candidate.
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
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.
TLorentzVector getCombinedP4(const xAOD::TauJet &tau) const
Get the weighted four momentum of calo TES and PanTau.
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.
TauRecToolBase(const std::string &name)
std::string find_file(const std::string &fname) const
TauJet_v3 TauJet
Definition of the current "tau version".
Definition TauJet.h:17
Extra patterns decribing particle interation process.