ATLAS Offline Software
Loading...
Searching...
No Matches
EtaJESCorrection.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
8#include <TAxis.h>
9#include <TEnv.h>
10#include <utility>
11
19
20EtaJESCorrection::EtaJESCorrection(const std::string& name, TEnv* config, TString jetAlgo, TString calibAreaTag, bool mass, bool dev)
22 m_config(config), m_jetAlgo(std::move(jetAlgo)), m_calibAreaTag(std::move(calibAreaTag)), m_mass(mass), m_dev(dev),
24 m_lowPtExtrap(0), m_lowPtMinR(0.25),
25 m_etaBinAxis(nullptr)
26{ }
27
33
35
36 ATH_MSG_INFO("Initializing JES correction.");
37
38 if(!m_config){
39 ATH_MSG_ERROR("EtaJES tool received a null config pointer.");
40 return StatusCode::FAILURE;
41 }
42
43 m_jetStartScale = m_config->GetValue("EtaJESStartingScale","JetPileupScaleMomentum");
44
45 TString absoluteJESCalibFile = m_config->GetValue("AbsoluteJES.CalibFile","");
46 if(m_dev){
47 absoluteJESCalibFile.Remove(0,33);
48 absoluteJESCalibFile.Insert(0,"JetCalibTools/");
49 }
50 else{absoluteJESCalibFile.Insert(14,m_calibAreaTag);}
51 TString calibFile = PathResolverFindCalibFile(absoluteJESCalibFile.Data());
52 m_config->ReadFile(calibFile, kEnvLocal);
53 ATH_MSG_INFO("Reading absolute calibration factors from: " << calibFile);
54 m_jesDesc = m_config->GetValue("AbsoluteJES.Description","");
55 ATH_MSG_INFO("Description: " << m_jesDesc);
56
57 // minPt_JES (always in GeV) determines at which point we stop using the correction curve and switch to an extrapolated value
58 m_minPt_JES = m_config->GetValue(m_jetAlgo+".MinPtForETAJES",10);
59 //Which extrapolation method to use at low Et (Et < _minPt_JES)
60 m_lowPtExtrap = m_config->GetValue("LowPtJESExtrapolationMethod",0);
61 //For order 2 extrapolation only, set the minimum value of the response for Et = 0
62 m_lowPtMinR = m_config->GetValue("LowPtJESExtrapolationMinimumResponse",0.25);
63 //Allowing to use different minPt_JES depending on eta (only for extrapolation methon 1)
64 m_useSecondaryminPt_JES = m_config->GetValue(m_jetAlgo+".UseSecondaryMinPtForETAJES", false);
65 //Starting eta for secondary minPt_JES (Default |eta|>=1.9) (Used only if UseSecondaryMinPtForETAJES is true)
66 m_etaSecondaryminPt_JES = m_config->GetValue(m_jetAlgo+".EtaSecondaryMinPtForETAJES", 1.9);
67 //SecondaryminPt_JES (Default 7 GeV) (Used only if UseSecondaryMinPtForETAJES is true)
68 m_secondaryminPt_JES = m_config->GetValue(m_jetAlgo+".SecondaryMinPtForETAJES",7);
69 // Freeze JES correction at maximum values of energy for each eta bin
70 m_freezeJESatHighE = m_config->GetValue(m_jetAlgo+".FreezeJEScorrectionatHighE", false);
71 m_isSpline = m_config->GetValue(m_jetAlgo+".isSpline", false);
72
73 // From mswiatlo, help from dag: variable eta binning
74 std::vector<double> etaBins = JetCalibUtils::VectorizeD(m_config->GetValue("JES.EtaBins",""));
75 if (etaBins.empty()){ // default binning
76 for (int i=0;i<=90; i++)
77 etaBins.push_back(0.1*i-4.5);
78 }
79 else if (etaBins.empty()) { ATH_MSG_FATAL("JES.EtaBins incorrectly specified"); return StatusCode::FAILURE; }
80 else if (etaBins.size()>s_nEtaBins+1) {
81 ATH_MSG_FATAL( "JES.EtaBins has " << etaBins.size()-1 << " bins, can be maximally 90!" );
82 return StatusCode::FAILURE;
83 }
84 m_etaBinAxis = new TAxis(etaBins.size()-1,&etaBins[0]);
85
86 m_applyMassCorrection = m_config->GetValue("ApplyMassCorrection",false);
87
88 if(m_mass){ // Only for the calibration sequence: EtaMassJES
89 if(m_applyMassCorrection) ATH_MSG_INFO("Jet mass correction will be applied.");
90 else { ATH_MSG_FATAL( "You can't apply the mass correction unless you specify ApplyMassCorrection: true in the configuration file!"); return StatusCode::FAILURE; }
91 }
92
93 for (uint ieta=0;ieta<etaBins.size()-1;++ieta) {
94 if(!m_isSpline){
95 // Read in absolute JES calibration factors
96 TString key=Form("JES.%s_Bin%d",m_jetAlgo.Data(),ieta);
97 std::vector<double> params = JetCalibUtils::VectorizeD(m_config->GetValue(key,""));
98 m_nPar = params.size();
99 if (m_nPar<s_nParMin || m_nPar>s_nParMax) { ATH_MSG_FATAL( "Cannot read JES calib constants " << key ); return StatusCode::FAILURE; }
100 for (uint ipar=0;ipar<m_nPar;++ipar) m_JESFactors[ieta][ipar] = params[ipar];
101
102 //Protections for high order extrapolation methods at low Et (Et < _minPt_JES)
103 if(m_lowPtExtrap > 0) {
104 //Calculate the slope of the response curve at the minPt for each eta bin
105 //Used in the GetLowPtJES method when Pt < minPt
106 const double *factors = m_JESFactors[ieta];
107 double Ecutoff;
108 if(!m_useSecondaryminPt_JES) Ecutoff = m_minPt_JES*cosh(etaBins[ieta]);
109 else {
110 if(fabs(etaBins[ieta]) < m_etaSecondaryminPt_JES) Ecutoff = m_minPt_JES*cosh(etaBins[ieta]);
111 else{ Ecutoff = m_secondaryminPt_JES*cosh(etaBins[ieta]);}
112 }
113 const double Rcutoff = getLogPolN(factors,Ecutoff);
114 const double Slope = getLogPolNSlope(factors,Ecutoff);
115 if(Slope > Rcutoff/Ecutoff) ATH_MSG_FATAL("Slope of calibration curve at minimum ET is too steep for the JES factors of etabin " << ieta << ", eta = " << etaBins[ieta] );
116
117 m_JES_MinPt_E[ieta] = Ecutoff;
118 m_JES_MinPt_R[ieta] = Rcutoff;
119 m_JES_MinPt_Slopes[ieta] = Slope;
120
121 //Calculate the parameters for a 2nd order polynomial extension to the calibration curve below minimum ET
122 //Used in the GetLowPtJES method when Pt < minPt
123 if(m_lowPtExtrap == 2) {
124 const double h = m_lowPtMinR;
125 const double Param1 = (2/Ecutoff)*(Rcutoff-h)-Slope;
126 const double Param2 = (0.5/Ecutoff)*(Slope-Param1);
127 //Slope of the calibration curve should always be positive
128 if( Param1 < 0 || Param1 + 2*Param2*Ecutoff < 0) ATH_MSG_FATAL("Polynomial extension to calibration curve below minimum ET is not monotonically increasing for etabin " << ieta << ", eta = " << etaBins[ieta] );
129 m_JES_MinPt_Param1[ieta] = Param1;
130 m_JES_MinPt_Param2[ieta] = Param2;
131 }
132 }
133 }
134
135 // Read in jet eta calibration factors
136 TString key=Form("EtaCorr.%s_Bin%d",m_jetAlgo.Data(),ieta);
137 std::vector<double> params = JetCalibUtils::VectorizeD(m_config->GetValue(key,""));
138 m_nPar = params.size();
139
140 if (params.size()!=m_nPar) { ATH_MSG_FATAL( "Cannot read jet eta calib constants " << key ); return StatusCode::FAILURE; }
141 for (uint ipar=0;ipar<m_nPar;++ipar) m_etaCorrFactors[ieta][ipar] = params[ipar];
142
143 if(m_freezeJESatHighE){ // Read starting energy values to freeze JES correction
144 key=Form("EmaxJES.%s_Bin%d",m_jetAlgo.Data(),ieta);
145 params = JetCalibUtils::VectorizeD(m_config->GetValue(key,""));
146 if (params.size()!=1) { ATH_MSG_FATAL( "Cannot read starting energy for the freezing of JES correction " << key ); return StatusCode::FAILURE; }
147 for (uint ipar=0;ipar<1;++ipar) m_energyFreezeJES[ieta] = params[ipar];
148 }
149
151 // Read in absolute JMS calibration factors
152 key=Form("MassCorr.%s_Bin%d",m_jetAlgo.Data(),ieta);
153 params = JetCalibUtils::VectorizeD(m_config->GetValue(key,""));
154 if (params.size()!=m_nPar) {ATH_MSG_FATAL( "Cannot read JMS calib constants " << key ); return StatusCode::FAILURE;}
155 for (uint ipar=0;ipar<m_nPar;++ipar) m_JMSFactors[ieta][ipar] = params[ipar];
156 }
157
158 }
159 if(m_isSpline){
160 TString absoluteJESCalibHists = m_config->GetValue("AbsoluteJES.CalibHists","");
161 if(m_dev){
162 absoluteJESCalibHists.Remove(0,33);
163 absoluteJESCalibHists.Insert(0,"JetCalibTools/");
164 }
165 else{
166 absoluteJESCalibHists.Insert(14,m_calibAreaTag);
167 }
168 TString calibHistFile = PathResolverFindCalibFile(absoluteJESCalibHists.Data());
169 loadSplineHists(calibHistFile, "etaJes");
170
171 //Protections for high order extrapolation methods at low Et (Et < _minPt_JES)
172 if(m_lowPtExtrap != 1) {
173 ATH_MSG_ERROR("Only linear extrapolations are supported for p-splines currently. Please change the config file to reflect this");
174 return StatusCode::FAILURE;
175 }
176
177 if(m_lowPtExtrap > 0) {
178 for (uint ieta=0;ieta<etaBins.size()-1;++ieta) {
179 //Calculate the slope of the response curve at the minPt for each eta bin
180 //Used in the GetLowPtJES method when Pt < minPt
181 double Ecutoff;
182 if(!m_useSecondaryminPt_JES) Ecutoff = m_minPt_JES*cosh(etaBins[ieta]);
183 else {
184 if(std::abs(etaBins[ieta]) < m_etaSecondaryminPt_JES) Ecutoff = m_minPt_JES*cosh(etaBins[ieta]);
185 else{ Ecutoff = m_secondaryminPt_JES*cosh(etaBins[ieta]);}
186 }
187 const double Rcutoff = getSplineCorr(ieta, Ecutoff);
188 const double Slope = getSplineSlope(ieta, Ecutoff);
189 if(Slope > Rcutoff/Ecutoff) ATH_MSG_WARNING("Slope of calibration curve at minimum ET is too steep for the JES factors of etabin " << ieta << ", eta = " << etaBins[ieta] );
190
191 m_JES_MinPt_E[ieta] = Ecutoff;
192 m_JES_MinPt_R[ieta] = Rcutoff;
193 m_JES_MinPt_Slopes[ieta] = Slope;
194 }
195 }
196 }
197
198
199 return StatusCode::SUCCESS;
200}
201
202
204void EtaJESCorrection::loadSplineHists(const TString & fileName, const std::string &etajes_name)
205{
206 std::unique_ptr<TFile> tmpF(TFile::Open( fileName ));
207 TList *etajes_l = static_cast<TList*>( tmpF->Get(etajes_name.c_str()));
208
209 m_etajesFactors.resize( etajes_l->GetSize() );
210 if(etajes_l->GetSize() != m_etaBinAxis->GetNbins()+1){
211 ATH_MSG_WARNING("Do not have the correct number of eta bins for " << fileName << "\t" << etajes_name << "\t" << etajes_l->GetSize() );
212 }
213
214 for(int i=0 ; i<m_etaBinAxis->GetNbins(); i++){
215 auto *pTH1 = dynamic_cast<TH1*>(etajes_l->At(i));
216 if (not pTH1) continue;
217 m_etajesFactors[i].reset(pTH1);
218 m_etajesFactors[i]->SetDirectory(nullptr);
219 }
220 tmpF->Close();
221}
222
223
225
226 xAOD::JetFourMom_t jetStartP4;
228 jetStartP4 = jet.jetP4();
229
230 //Apply the JES calibration scale factor
231 //Takes the uncorrected jet eta (in case the origin and/or 4vector jet area corrections were applied
232 float detectorEta = jet.getAttribute<float>("DetectorEta");
233
234 xAOD::JetFourMom_t calibP4 = jetStartP4*getJES( jetStartP4.e(), detectorEta );
235
236 const double etaCorr = calibP4.eta() + getEtaCorr( calibP4.e(), detectorEta );
237 double massCorr;
238 if(!m_applyMassCorrection) massCorr = calibP4.mass();
239 else{ massCorr = jetStartP4.mass()*getMassCorr(calibP4.e(), detectorEta); }
240 TLorentzVector TLVjet;
241 TLVjet.SetPtEtaPhiM( calibP4.P()/cosh(etaCorr),etaCorr,calibP4.phi(),massCorr );
242 calibP4.SetPxPyPzE( TLVjet.Px(), TLVjet.Py(), TLVjet.Pz(), TLVjet.E() );
243
244 if(m_dev){
245 float JESFactor = calibP4.e()/jetStartP4.e();
246 jet.setAttribute<float>("JetJESCalibFactor",JESFactor);
247 }
248
249 //Transfer calibrated jet properties to the Jet object
250 jet.setAttribute<xAOD::JetFourMom_t>("JetEtaJESScaleMomentum",calibP4);
251 jet.setJetP4( calibP4 );
252
253 return StatusCode::SUCCESS;
254}
255
256// E_uncorr is the EM-scale, or LC-scale jet energy
257// eta_det is the eta of the raw, constituent-scale jet (constscale_eta)
258double EtaJESCorrection::getJES(double E_uncorr, double eta_det) const {
259
260 double E = E_uncorr/m_GeV; // E in GeV
261 //Check if the Pt goes below the minimum value, if so use the special GetLowPtJES method
263 if(fabs(eta_det) < m_etaSecondaryminPt_JES && E/cosh(eta_det) < m_minPt_JES){
264 double R = getLowPtJES(E,eta_det);
265 return 1.0/R;
266 }
267 if(fabs(eta_det) >= m_etaSecondaryminPt_JES && E/cosh(eta_det) < m_secondaryminPt_JES){
268 double R = getLowPtJES(E,eta_det);
269 return 1.0/R;
270 }
271 }else{
272 if ( E/cosh(eta_det) < m_minPt_JES ) {
273 double R = getLowPtJES(E,eta_det);
274 return 1.0/R;
275 }
276 }
277
278 // Get the factors
279 int ieta = getEtaBin(eta_det);
280
281 // Freeze correction
282 if(m_freezeJESatHighE && E>m_energyFreezeJES[ieta] && m_energyFreezeJES[ieta]!=-1) E = m_energyFreezeJES[ieta];
283
284
285 // The low pT extrapolation doesn't work for the spline yet, so putting this code here.
286 if(m_isSpline){
287 double R = getSplineCorr(ieta, E);
288 return 1.0/R;
289 }
290 const double *factors = m_JESFactors[ieta];
291
292
293 // Calculate the jet response and then the JES as 1/R
294 double R = getLogPolN(factors,E);
295 return 1.0/R;
296}
297
298double EtaJESCorrection::getLowPtJES(double E_uncorr, double eta_det) const {
299 int ieta = getEtaBin(eta_det);
300 if (m_lowPtExtrap == 0) {
301 const double *factors = m_JESFactors[ieta];
302 double E = m_minPt_JES*cosh(eta_det);
303 double R = getLogPolN(factors,E);
304 return R;
305 }
306 else if (m_lowPtExtrap == 1) {
307 double Ecutoff = m_JES_MinPt_E[ieta];
308 double Rcutoff = m_JES_MinPt_R[ieta];
309 double slope = m_JES_MinPt_Slopes[ieta];
310 double R = slope*(E_uncorr-Ecutoff)+Rcutoff;
311 return R;
312 }
313 else if(m_lowPtExtrap == 2) {
314 double minR = m_lowPtMinR;
315 double R = minR + m_JES_MinPt_Param1[ieta]*E_uncorr + m_JES_MinPt_Param2[ieta]*E_uncorr*E_uncorr;
316 return R;
317 }
318 else ATH_MSG_WARNING("Incorrect specification of low Pt JES extrapolation, please check the value of the LowPtJESExtrapolationMethod config flag.");
319 return 1;
320}
321
322double EtaJESCorrection::getSplineSlope(const int ieta, const double minE) const {
323 // Don't want to use interpolation here, so instead just use the values at the bin centers near the cutoff
324 int minBin = m_etajesFactors[ieta]->FindBin(minE);
325
326 double rFirst = m_etajesFactors[ ieta ]->GetBinContent(minBin);
327 double rSecond = m_etajesFactors[ ieta ]->GetBinContent(minBin+1);
328 double binWidth = m_etajesFactors[ ieta ]->GetBinCenter(minBin+1) - m_etajesFactors[ ieta ]->GetBinCenter(minBin);
329 double slope = (rSecond - rFirst) / binWidth;
330
331 return slope;
332}
333
334
335double EtaJESCorrection::getSplineCorr(const int etaBin, double E) const {
336 double R = m_etajesFactors[ etaBin ]->Interpolate(E);
337 return R;
338}
339
340
341
342double EtaJESCorrection::getEtaCorr(double E_corr, double eta_det) const {
343 int ieta = getEtaBin(eta_det);
344 const double *factors = m_etaCorrFactors[ieta];
345
346 double E = E_corr/m_GeV;
347 if ( E < m_minPt_EtaCorr*cosh(eta_det) )
348 E = m_minPt_EtaCorr*cosh(eta_det);
350
351 double etaCorr = getLogPolN(factors,E);
352
353 // This is ( reco_eta - truth_eta )
354 // to make it an additive correction return the negative value
355 return -etaCorr;
356}
357
358double EtaJESCorrection::getMassCorr(double E_corr, double eta_det) const {
359
360 if (!m_applyMassCorrection) { ATH_MSG_FATAL( "You can't apply the mass correction unless you specify ApplyMassCorrection: true in the configuration file!" ); return 0; }
361
362 int ieta = getEtaBin(eta_det);
363 const double *factors = m_JMSFactors[ieta];
364 double E = ( E_corr/cosh(eta_det)<5.0*m_GeV ? 5.0*cosh(eta_det) : E_corr/m_GeV ); // E in GeV
365
366 double massR = getLogPolN(factors,E);
367 return 1.0/massR;
368}
369
370double EtaJESCorrection::getLogPolN(const double *factors, double x) const {
371 double y=0;
372 for ( uint i=0; i<m_nPar; ++i )
373 y += factors[i]*TMath::Power(log(x),Int_t(i));
374 return y;
375}
376
377double EtaJESCorrection::getLogPolNSlope(const double *factors, double x) const {
378 double y=0;
379 const double inv_x = 1. / x;
380 for ( uint i=0; i<m_nPar; ++i )
381 y += i*factors[i]*TMath::Power(log(x),Int_t(i-1))*inv_x;
382 return y;
383}
384
385int EtaJESCorrection::getEtaBin(double eta_det) const {
386 int bin = std::as_const(m_etaBinAxis)->FindBin(eta_det);
387 if (bin<=0) return 0;
388 if (bin>m_etaBinAxis->GetNbins()) return bin-2; // overflow
389 return bin-1;
390}
391
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
unsigned int uint
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
#define y
#define x
Header file for AthHistogramAlgorithm.
double m_JESFactors[s_nEtaBins][s_nParMax]
virtual StatusCode calibrate(xAOD::Jet &jet, JetEventInfo &) const override
unsigned int m_lowPtExtrap
virtual StatusCode initialize() override
double getSplineSlope(const int ieta, const double minE) const
static const unsigned int s_nEtaBins
double m_JES_MinPt_Slopes[s_nEtaBins]
double m_JES_MinPt_R[s_nEtaBins]
double m_JMSFactors[s_nEtaBins][s_nParMax]
double getLogPolNSlope(const double *factors, double x) const
double getJES(double E_uncorr, double eta_det) const
static const unsigned int s_nParMax
double m_energyFreezeJES[s_nEtaBins]
double getEtaCorr(double E_corr, double eta_det) const
double getLowPtJES(double E_uncorr, double eta_det) const
double m_JES_MinPt_Param1[s_nEtaBins]
void loadSplineHists(const TString &fileName, const std::string &etajes_name="etaJes")
Loads the calib constants from histograms in TFile named fileName.
double getSplineCorr(const int etaBin, double E) const
double getMassCorr(double E_corr, double eta_det) const
std::vector< std::unique_ptr< TH1 > > m_etajesFactors
double m_etaCorrFactors[s_nEtaBins][s_nParMax]
double m_JES_MinPt_Param2[s_nEtaBins]
unsigned int m_nPar
int getEtaBin(double eta_det) const
double m_JES_MinPt_E[s_nEtaBins]
double getLogPolN(const double *factors, double x) const
virtual StatusCode setStartP4(xAOD::Jet &jet) const
JetCalibrationStep(const char *name="JetCalibrationStep")
void binWidth(TH1 *h)
Definition listroot.cxx:80
VecD VectorizeD(const TString &str, const TString &sep=" ")
STL namespace.
Jet_v1 Jet
Definition of the current "jet version".
ROOT::Math::LorentzVector< ROOT::Math::PtEtaPhiM4D< double > > JetFourMom_t
Base 4 Momentum type for Jet.
Definition JetTypes.h:17