ATLAS Offline Software
Loading...
Searching...
No Matches
GlobalSequentialCorrection.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5/*
6 * Calculates global sequential jet calibration factors
7 * -Requires jet branches trackWIDTH, nTrk, Tile0, EM3
8 * -Apply using
9 * 1. No jet area correction: JetCalibrationTool::ApplyOffsetEtaJESGSC
10 * 2. With jet area correction (not yet supported): JetCalibrationTool::ApplyJetAreaOffsetEtaJESGSC
11 * -GSC correction factor is returned by JetCalibrationTool::GetGSC
12 * TFile* inputFile = NULL;
13 inputFile = openInputFile(m_fileName);
14 *
15 * Extension of the ApplyJetCalibrationTool
16 *
17 * Authors: Joe Taenzer (joseph.taenzer@cern.ch), Reina Camacho, Jonathan Bossio (jbossios@cern.ch)
18 *
19 */
20
21#include <TKey.h>
22
23#include <utility>
24
26
29
31#include "xAODTracking/Vertex.h"
33
42
43GlobalSequentialCorrection::GlobalSequentialCorrection(const std::string& name, TEnv* config, TString jetAlgo, const std::string& depth, TString calibAreaTag, bool useOriginVertex, bool dev)
45 m_config(config), m_jetAlgo(std::move(jetAlgo)), m_depthString(depth), m_calibAreaTag(std::move(calibAreaTag)), m_dev(dev),
46 m_binSize(0.1), m_depth(0),
49
50{ }
51
52
54
55 ATH_MSG_INFO("Initializing the Global Sequential Calibration tool");
56
57 if(!m_config){
58 ATH_MSG_ERROR("GSC tool received a null config pointer.");
59 return StatusCode::FAILURE;
60 }
61
62 // Set m_PFlow
63 m_PFlow = m_jetAlgo == "AntiKt4EMPFlow";
64
65 // Set m_caloBased
66 if( m_jetAlgo == "AntiKt4EMTopoTrig" && !m_PFlow ) {
67 m_caloBased = true;
68 ATH_MSG_INFO("Using calo based GSC");
69 } else{
70 // better to read from config which type of GSC: caloBased for trigger jets.
71 m_caloBased = m_config->GetValue("caloBasedGSC",false);
72 }
73
74 m_jetStartScale = m_config->GetValue("GSCStartingScale","JetEtaJESScaleMomentum");
75 m_turnOffTrackCorrections = m_config->GetValue("TurnOffTrackCorrections", false);
76 m_turnOffStartingpT = m_config->GetValue("TurnOffStartingpT", 1200);
77 m_turnOffEndpT = m_config->GetValue("TurnOffEndpT", 2000);
78 m_pTResponseRequirementOff = m_config->GetValue("PTResponseRequirementOff", false);
79
80 // In release 21, the nTrk and trackWIDTH corrections are also included for PFlow jets
81 // The default is set to false to maintain the backwards compatibility
82 m_nTrkwTrk_4PFlow = m_config->GetValue("nTrkwTrk4PFlow", false);
83
84 // For AFII calibrations, EM3 correction should be applied up to |eta|=3.2
85 m_EM3MaxEtaBin = m_config->GetValue("EM3MaxEtaBin", 35);
86
87 if ( m_jetAlgo.EqualTo("") ) { ATH_MSG_FATAL("No jet algorithm specified. Aborting."); return StatusCode::FAILURE; }
88
89 //find the ROOT file containing response histograms, path comes from the config file.
90 TString GSCFile = m_config->GetValue("GSCFactorsFile","empty");
91 if ( GSCFile.EqualTo("empty") ) {
92 ATH_MSG_FATAL("NO GSCFactorsFile specified. Aborting.");
93 return StatusCode::FAILURE;
94 }
95 if(m_dev){
96 GSCFile.Remove(0,33);
97 GSCFile.Insert(0,"JetCalibTools/");
98 }
99 else{GSCFile.Insert(14,m_calibAreaTag);}
100 TString fileName = PathResolverFindCalibFile(GSCFile.Data());
101 std::unique_ptr<TFile> inputFile(TFile::Open(fileName));
102 if (!inputFile){
103 ATH_MSG_FATAL("Cannot open GSC factors file" << fileName);
104 return StatusCode::FAILURE;
105 }
106
107 TString depthString = "";
108 if ( m_depthString != "auto" ) depthString = m_depthString;
109 else depthString = m_config->GetValue("GSCDepth","Full");
110 if ( !depthString.Contains("ChargedFraction") && !depthString.Contains("Tile0") && !depthString.Contains("EM3") && !depthString.Contains("nTrk") && !depthString.Contains("trackWIDTH") && !depthString.Contains("PunchThrough") && !depthString.Contains("N90Constituents") && !depthString.Contains("TileGap3") && !depthString.Contains("caloWIDTH") && !depthString.Contains("Full") ) {
111 ATH_MSG_FATAL("depthString flag not properly set, please check your config file.");
112 return StatusCode::FAILURE;
113 }
114
115 // Protection against requesting nTrk or trackWIDTH corrections for PFlow jets when m_nTrkwTrk_4PFlow is false
116 if ( !m_nTrkwTrk_4PFlow && (depthString.Contains("nTrk")||depthString.Contains("trackWIDTH")) && m_PFlow ){
117 ATH_MSG_FATAL("depthString flag not properly set, please check your config file. nTrkwTrk4PFlow should be set to true to apply nTrk or trackWIDTH corrections to PFlow jets");
118 return StatusCode::FAILURE;
119 }
120
121 // Protection against requesting nTrk/trackWIDTH/ChargedFraction/PunchThrough corrections for HLT trigger jets when m_caloBased is true
122 if ( m_caloBased && (depthString.Contains("nTrk")||depthString.Contains("trackWIDTH")||depthString.Contains("ChargedFraction")||depthString.Contains("PunchThrough"))){
123 ATH_MSG_FATAL("depthString flag not properly set, please check your config file. nTrk, trackWIDTH, PunchThrough and ChargedFraction corrections not available for trigger jets");
124 return StatusCode::FAILURE;
125 }
126
127
128 //ATH_MSG_INFO(" for " << m_jetAlgo << " jets\n\n");
129
130 if ( depthString.Contains("PunchThrough") || depthString.Contains("Full") ) {
131 setPunchThroughEtaBins( JetCalibUtils::VectorizeD( m_config->GetValue("PunchThroughEtaBins","") ) );
132 setPunchThroughMinPt( m_config->GetValue("PunchThroughMinPt",50) );
133 }
134
135 //set the depth private variable, used to determine which parts of the GS calibration are applied
136 if( !m_PFlow && !m_caloBased ){
137 if ( depthString.Contains("PunchThrough") || depthString.Contains("Full") ) m_depth = ApplyTile0 | ApplyEM3 | ApplynTrk | ApplytrackWIDTH | ApplyPunchThrough;
138 else if ( depthString.Contains("trackWIDTH") ) m_depth = ApplyTile0 | ApplyEM3 | ApplynTrk | ApplytrackWIDTH;
139 else if ( depthString.Contains("nTrk") ) m_depth = ApplyTile0 | ApplyEM3 | ApplynTrk;
140 else if ( depthString.Contains("EM3") ) m_depth = ApplyTile0 | ApplyEM3;
141 else if ( depthString.Contains("Tile0") ) m_depth = ApplyTile0;
142 else { ATH_MSG_FATAL("depthString flag not properly set, please check your config file."); return StatusCode::FAILURE; }
143 }
144 else if (m_caloBased){
145 if ( depthString.Contains("caloWIDTH") || depthString.Contains("Full") ) m_depth = ApplyTile0 | ApplyEM3 | ApplyN90Constituents | ApplycaloWIDTH;
146 else if ( depthString.Contains("TileGap3") ) m_depth = ApplyTile0 | ApplyEM3 | ApplyN90Constituents | ApplyTileGap3;
147 else if ( depthString.Contains("N90Constituents") ) m_depth = ApplyTile0 | ApplyEM3 | ApplyN90Constituents;
148 else if ( depthString.Contains("EM3") ) m_depth = ApplyTile0 | ApplyEM3;
149 else if ( depthString.Contains("Tile0") ) m_depth = ApplyTile0;
150 else { ATH_MSG_FATAL("depthString flag for calo based GSC not properly set, please check your config file."); return StatusCode::FAILURE; }
151 }
152 else { // PFlow
154 if ( depthString.Contains("PunchThrough") || depthString.Contains("Full") ) m_depth = ApplyChargedFraction | ApplyTile0 | ApplyEM3 | ApplyPunchThrough;
155 else if ( depthString.Contains("EM3") ) m_depth = ApplyChargedFraction | ApplyTile0 | ApplyEM3;
156 else if ( depthString.Contains("Tile0") ) m_depth = ApplyChargedFraction | ApplyTile0;
157 else if ( depthString.Contains("ChargedFraction") ) m_depth = ApplyChargedFraction;
158 else { ATH_MSG_FATAL("depthString flag not properly set, please check your config file."); return StatusCode::FAILURE; }
159 } else {
160 if ( depthString.Contains("PunchThrough") || depthString.Contains("Full") ) m_depth = ApplyChargedFraction | ApplyTile0 | ApplyEM3 | ApplynTrk | ApplytrackWIDTH | ApplyPunchThrough;
161 else if ( depthString.Contains("trackWIDTH") ) m_depth = ApplyChargedFraction | ApplyTile0 | ApplyEM3 | ApplynTrk | ApplytrackWIDTH;
162 else if ( depthString.Contains("nTrk") ) m_depth = ApplyChargedFraction | ApplyTile0 | ApplyEM3 | ApplynTrk;
163 else if ( depthString.Contains("EM3") ) m_depth = ApplyChargedFraction | ApplyTile0 | ApplyEM3;
164 else if ( depthString.Contains("Tile0") ) m_depth = ApplyChargedFraction | ApplyTile0;
165 else if ( depthString.Contains("ChargedFraction") ) m_depth = ApplyChargedFraction;
166 else { ATH_MSG_FATAL("depthString flag not properly set, please check your config file."); return StatusCode::FAILURE; }
167 }
168 }
169
170 //Get a TList of TKeys pointing to the histograms contained in the ROOT file
171 inputFile->cd();
172 TList *keys = inputFile->GetListOfKeys();
173 std::vector<TString> histoNames;
174 //fill the names of the TKeys into a vector of TStrings
175 TIter ikeys(keys);
176 while ( TKey *iterobj = (TKey*)ikeys() ) { histoNames.emplace_back(iterobj->GetName() ); }
177
178 //Grab the TH2Fs from the ROOT file and put them into a vectors of TH2Fs
179 for (uint ihisto=0; ihisto<histoNames.size(); ++ihisto) {
180 if ( !histoNames[ihisto].Contains( m_jetAlgo.Data() ) ) continue;
181 else if ( ihisto>0 && histoNames[ihisto].Contains( histoNames[ihisto-1].Data() ) ) continue;
182 else if ( histoNames[ihisto].Contains("EM3") && m_respFactorsEM3.size() < m_EM3MaxEtaBin)
183 m_respFactorsEM3.push_back( JetCalibUtils::GetHisto2(*inputFile,histoNames[ihisto]) );
184 else if ( histoNames[ihisto].Contains("nTrk") && m_respFactorsnTrk.size() < m_nTrkMaxEtaBin)
185 m_respFactorsnTrk.push_back( JetCalibUtils::GetHisto2(*inputFile,histoNames[ihisto]) );
186 else if ( histoNames[ihisto].Contains("Tile0") && m_respFactorsTile0.size() < m_Tile0MaxEtaBin)
187 m_respFactorsTile0.push_back( JetCalibUtils::GetHisto2(*inputFile,histoNames[ihisto]) );
188 else if ( histoNames[ihisto].Contains("chargedFraction") && m_respFactorsChargedFraction.size() < m_chargedFractionMaxEtaBin)
189 m_respFactorsChargedFraction.push_back( JetCalibUtils::GetHisto2(*inputFile,histoNames[ihisto]) );
190 else if ( histoNames[ihisto].Contains("trackWIDTH") && m_respFactorstrackWIDTH.size() < m_trackWIDTHMaxEtaBin)
191 m_respFactorstrackWIDTH.push_back( JetCalibUtils::GetHisto2(*inputFile,histoNames[ihisto]) );
192 else if ( histoNames[ihisto].Contains("PunchThrough") )
193 m_respFactorsPunchThrough.push_back( JetCalibUtils::GetHisto2(*inputFile,histoNames[ihisto]) );
194 else if ( histoNames[ihisto].Contains("N90Constituents") && m_respFactorsN90Constituents.size() < m_N90ConstituentsMaxEtaBin)
195 m_respFactorsN90Constituents.push_back( JetCalibUtils::GetHisto2(*inputFile,histoNames[ihisto]) );
196 else if ( histoNames[ihisto].Contains("caloWIDTH") && m_respFactorscaloWIDTH.size() < m_caloWIDTHMaxEtaBin)
197 m_respFactorscaloWIDTH.push_back( JetCalibUtils::GetHisto2(*inputFile,histoNames[ihisto]) );
198 else if ( histoNames[ihisto].Contains("TileGap3") && m_respFactorsTileGap3.size() < m_TileGap3MaxEtaBin )
199 m_respFactorsTileGap3.push_back( JetCalibUtils::GetHisto2(*inputFile,histoNames[ihisto]) );
200 }
201
202 //Make sure we put something in the vectors of TH2Fs
203 if( !m_PFlow && !m_caloBased ){
204 if ( (m_depth & ApplyEM3) && m_respFactorsEM3.size() < 3 ) {
205 ATH_MSG_FATAL("Vector of EM3 histograms may be empty. Please check your GSCFactors file: " << GSCFile);
206 return StatusCode::FAILURE;
207 }
208 else if ( (m_depth & ApplynTrk) && m_respFactorsnTrk.size() < 3 ) {
209 ATH_MSG_FATAL("Vector of nTrk histograms may be empty. Please check your GSCFactors file: " << GSCFile);
210 return StatusCode::FAILURE;
211 }
212 else if ( (m_depth & ApplyTile0) && m_respFactorsTile0.size() < 3 ) {
213 ATH_MSG_FATAL("Vector of Tile0 histograms may be empty. Please check your GSCFactors file: " << GSCFile);
214 return StatusCode::FAILURE;
215 }
216 else if ( (m_depth & ApplytrackWIDTH) && m_respFactorstrackWIDTH.size() < 3 ) {
217 ATH_MSG_FATAL("Vector of trackWIDTH histograms may be empty. Please check your GSCFactors file: " << GSCFile);
218 return StatusCode::FAILURE;
219 }
220 else if ( (m_depth & ApplyPunchThrough) && m_respFactorsPunchThrough.size() < 2 ) {
221 ATH_MSG_FATAL("Vector of PunchThrough histograms may be empty. Please check your GSCFactors file: " << GSCFile);
222 return StatusCode::FAILURE;
223 }
224 else ATH_MSG_INFO("GSC Tool has been initialized with binning and eta fit factors from: " << fileName);
225 }
226 else if (m_caloBased) {
227 if ( (m_depth & ApplyEM3) && m_respFactorsEM3.size() < 3 ) {
228 ATH_MSG_FATAL("Vector of EM3 histograms may be empty. Please check your GSCFactors file: " << GSCFile);
229 return StatusCode::FAILURE;
230 }
231 else if ( (m_depth & ApplyN90Constituents) && m_respFactorsN90Constituents.size() < 3 ) {
232 ATH_MSG_FATAL("Vector of N90Constituents histograms may be empty. Please check your GSCFactors file: " << GSCFile);
233 return StatusCode::FAILURE;
234 }
235 else if ( (m_depth & ApplyTile0) && m_respFactorsTile0.size() < 3 ) {
236 ATH_MSG_FATAL("Vector of Tile0 histograms may be empty. Please check your GSCFactors file: " << GSCFile);
237 return StatusCode::FAILURE;
238 }
239 else if ( (m_depth & ApplycaloWIDTH) && m_respFactorscaloWIDTH.size() < 3 ) {
240 ATH_MSG_FATAL("Vector of caloWIDTH histograms may be empty. Please check your GSCFactors file: " << GSCFile);
241 return StatusCode::FAILURE;
242 }
243 else if ( (m_depth & ApplyTileGap3) && m_respFactorsTileGap3.size() < 3 ) {
244 ATH_MSG_FATAL("Vector of TileGap3 histograms may be empty. Please check your GSCFactors file: " << GSCFile);
245 return StatusCode::FAILURE;
246 }
247
248 else ATH_MSG_INFO("GSC Tool has been initialized with binning and eta fit factors from: " << fileName << "\n");
249 }
250 else{
252 ATH_MSG_FATAL("Vector of ChargedFraction histograms may be empty. Please check your GSCFactors file: " << GSCFile);
253 return StatusCode::FAILURE;
254 }
255 else if ( (m_depth & ApplyEM3) && m_respFactorsEM3.size() < 3 ) {
256 ATH_MSG_FATAL("Vector of EM3 histograms may be empty. Please check your GSCFactors file: " << GSCFile);
257 return StatusCode::FAILURE;
258 }
259 else if ( (m_depth & ApplyTile0) && m_respFactorsTile0.size() < 3 ) {
260 ATH_MSG_FATAL("Vector of Tile0 histograms may be empty. Please check your GSCFactors file: " << GSCFile);
261 return StatusCode::FAILURE;
262 }
263 else if ( m_nTrkwTrk_4PFlow && (m_depth & ApplynTrk) && m_respFactorsnTrk.size() < 3 ) {
264 ATH_MSG_FATAL("Vector of nTrk histograms may be empty. Please check your GSCFactors file: " << GSCFile);
265 return StatusCode::FAILURE;
266 }
267 else if ( m_nTrkwTrk_4PFlow && (m_depth & ApplytrackWIDTH) && m_respFactorstrackWIDTH.size() < 3 ) {
268 ATH_MSG_FATAL("Vector of trackWIDTH histograms may be empty. Please check your GSCFactors file: " << GSCFile);
269 return StatusCode::FAILURE;
270 }
271 else if ( (m_depth & ApplyPunchThrough) && m_respFactorsPunchThrough.size() < 2 ) {
272 ATH_MSG_FATAL("Vector of PunchThrough histograms may be empty. Please check your GSCFactors file: " << GSCFile);
273 return StatusCode::FAILURE;
274 }
275 else ATH_MSG_INFO("GSC Tool has been initialized with binning and eta fit factors from: " << fileName);
276 }
277 return StatusCode::SUCCESS;
278
279}
280
281double GlobalSequentialCorrection::readPtJetPropertyHisto(double pT, double jetProperty, const TH2& respFactors) const {
282 int pTbin = respFactors.GetXaxis()->FindBin(pT);
283 int pTMinbin = respFactors.GetXaxis()->GetFirst();
284 int pTMaxbin = respFactors.GetXaxis()->GetLast();
285 int jetPropbin = respFactors.GetYaxis()->FindBin(jetProperty);
286 int jetPropMinbin = respFactors.GetYaxis()->GetFirst();
287 int jetPropMaxbin = respFactors.GetYaxis()->GetLast();
288 //Protection against input values that are outside the histogram range, which would cause TH2::Interpolate to throw an error
289 if (pTbin < pTMinbin) pT = respFactors.GetXaxis()->GetBinLowEdge(pTMinbin)+1e-6;
290 else if (pTbin > pTMaxbin) pT = respFactors.GetXaxis()->GetBinUpEdge(pTMaxbin)-1e-6;
291 if (jetPropbin < jetPropMinbin) jetProperty = respFactors.GetYaxis()->GetBinLowEdge(jetPropMinbin)+1e-6;
292 else if (jetPropbin > jetPropMaxbin) jetProperty = respFactors.GetYaxis()->GetBinUpEdge(jetPropMaxbin)-1e-6;
293 //TH2::Interpolate is a bilinear interpolation from the bin centers.
294 return respFactors.Interpolate(pT, jetProperty);
295}
296
297double GlobalSequentialCorrection::getTrackWIDTHResponse(double pT, uint etabin, double trackWIDTH) const {
298 if (trackWIDTH<=0) return 1;
299 if ( etabin >= m_respFactorstrackWIDTH.size() ) return 1.;
300 //jets with no tracks are assigned a trackWIDTH of -1, we use the trackWIDTH=0 correction in those cases
301 double trackWIDTHResponse;
303 if(pT>=m_turnOffStartingpT && pT<=m_turnOffEndpT){
304 double responseatStartingpT = readPtJetPropertyHisto(m_turnOffStartingpT, trackWIDTH, *m_respFactorstrackWIDTH[etabin]);
305 trackWIDTHResponse = (1-responseatStartingpT)/(m_turnOffEndpT-m_turnOffStartingpT);
306 trackWIDTHResponse *= pT;
307 trackWIDTHResponse += 1 - (m_turnOffEndpT*(1-responseatStartingpT)/(m_turnOffEndpT-m_turnOffStartingpT));
308 return trackWIDTHResponse;
309 }
310 else if(pT>m_turnOffEndpT) return 1;
311 }
312 trackWIDTHResponse = readPtJetPropertyHisto(pT, trackWIDTH, *m_respFactorstrackWIDTH[etabin]);
313 return trackWIDTHResponse;
314}
315
316double GlobalSequentialCorrection::getNTrkResponse(double pT, uint etabin, double nTrk) const {
317 if (nTrk<=0) return 1; //nTrk < 0 is unphysical, nTrk = 0 is a special case, so return 1 for nTrk <= 0
318 if ( etabin >= m_respFactorsnTrk.size() ) return 1.;
319 double nTrkResponse;
321 if(pT>=m_turnOffStartingpT && pT<=m_turnOffEndpT){
322 double responseatStartingpT = readPtJetPropertyHisto(m_turnOffStartingpT, nTrk, *m_respFactorsnTrk[etabin]);
323 nTrkResponse = (1-responseatStartingpT)/(m_turnOffEndpT-m_turnOffStartingpT);
324 nTrkResponse *= pT;
325 nTrkResponse += 1 - (m_turnOffEndpT*(1-responseatStartingpT)/(m_turnOffEndpT-m_turnOffStartingpT));
326 return nTrkResponse;
327 }
328 else if(pT>m_turnOffEndpT) return 1;
329 }
330 nTrkResponse = readPtJetPropertyHisto(pT, nTrk, *m_respFactorsnTrk[etabin]);
331 return nTrkResponse;
332}
333
334double GlobalSequentialCorrection::getTile0Response(double pT, uint etabin, double Tile0) const {
335 if (Tile0<0) return 1; //Tile0 < 0 is unphysical, so we return 1
336 if ( etabin >= m_respFactorsTile0.size() ) return 1.;
337 double Tile0Response = readPtJetPropertyHisto(pT, Tile0, *m_respFactorsTile0[etabin]);
338 return Tile0Response;
339}
340
341double GlobalSequentialCorrection::getEM3Response(double pT, uint etabin, double EM3) const {
342 if (EM3<=0) return 1; //EM3 < 0 is unphysical, EM3 = 0 is a special case, so we return 1 for EM3 <= 0
343 if ( etabin >= m_respFactorsEM3.size() ) return 1.;
344 double EM3Response = readPtJetPropertyHisto(pT, EM3, *m_respFactorsEM3[etabin]);
345 return EM3Response;
346}
347
348double GlobalSequentialCorrection::getChargedFractionResponse(double pT, uint etabin, double ChargedFraction) const {
349 if (ChargedFraction<=0) return 1; //ChargedFraction < 0 is unphysical, ChargedFraction = 0 is a special case, so we return 1 for ChargedFraction <= 0
350 if ( etabin >= m_respFactorsChargedFraction.size() ) return 1.;
351 double ChargedFractionResponse = readPtJetPropertyHisto(pT, ChargedFraction, *m_respFactorsChargedFraction[etabin]);
352 return ChargedFractionResponse;
353}
354
355double GlobalSequentialCorrection::getPunchThroughResponse(double E, double eta_det, int Nsegments) const {
356 int etabin=-99;
357 //Check that the punch through eta binning defined in the config appears reasonable, otherwise throw an error.
359 ATH_MSG_WARNING("Please check that the punch through eta binning is properly set in your config file");
360 if ( eta_det >= m_punchThroughEtaBins.back() || Nsegments < 20 ) return 1;
361 for (uint i=0; i<m_punchThroughEtaBins.size()-1; ++i) {
362 if(eta_det >= m_punchThroughEtaBins[i] && eta_det < m_punchThroughEtaBins[i+1]) etabin = i;
363 }
364 if(etabin<0) {
365 ATH_MSG_WARNING("There was a problem determining the eta bin to use for the punch through correction.");
366 //this could probably be improved, but to avoid a seg fault...
367 return 1;
368 }
369 double PunchThroughResponse = readPtJetPropertyHisto(E,Nsegments,*m_respFactorsPunchThrough[etabin]);
370 if(!m_pTResponseRequirementOff && PunchThroughResponse>1) return 1;
371 return PunchThroughResponse;
372}
373
374double GlobalSequentialCorrection::getCaloWIDTHResponse(double pT, uint etabin, double caloWIDTH) const {
375 if (caloWIDTH<=0) return 1;
376 if ( etabin >= m_respFactorscaloWIDTH.size() ) return 1.;
377 double caloWIDTHResponse = readPtJetPropertyHisto(pT, caloWIDTH, *m_respFactorscaloWIDTH[etabin]);
378 return caloWIDTHResponse;
379}
380
381double GlobalSequentialCorrection::getN90ConstituentsResponse(double pT, uint etabin, double N90Constituents) const {
382 if (N90Constituents<=0) return 1; // N90Constituents < 0 is unphysical, N90Constituents = 0 is a special case, so return 1 for N90Constituents <= 0
383 if ( etabin >= m_respFactorsN90Constituents.size() ) return 1.;
384 double N90ConstituentsResponse = readPtJetPropertyHisto(pT, N90Constituents, *m_respFactorsN90Constituents[etabin]);
385 return N90ConstituentsResponse;
386}
387
388double GlobalSequentialCorrection::getTileGap3Response(double pT, uint etabin, double TileGap3 ) const {
389 if (TileGap3<0) return 1; //TileGap3 < 0 is unphysical, so we return 1
390 if ( etabin >= m_respFactorsTileGap3.size() ) return 1.;
391 double TileGap3Response = readPtJetPropertyHisto(pT, TileGap3, *m_respFactorsTileGap3[etabin]);
392 return TileGap3Response;
393}
394
396 double trackWIDTH, double nTrk, double Tile0, double EM3, int Nsegments, double ChargedFraction, double caloWIDTH, double N90Constituents, double TileGap3) const {
397 //eta bins have size m_binSize=0.1 and are numbered sequentially from 0, so |eta|=2.4 is in eta bin #24
398 int etabin = eta/m_binSize;
399 double Corr=1;
400 //Using bit sequence check to determine which GS corrections to apply.
401 if( !m_PFlow && !m_caloBased ){
402 if (m_depth & ApplyTile0) Corr*=1./getTile0Response(jetP4.pt()/m_GeV, etabin, Tile0);
403 if (m_depth & ApplyEM3) Corr*=1./getEM3Response(jetP4.pt()/m_GeV*Corr, etabin, EM3);
404 if (m_depth & ApplynTrk) Corr*=1./getNTrkResponse(jetP4.pt()/m_GeV*Corr, etabin, nTrk);
405 if (m_depth & ApplytrackWIDTH) Corr*=1./getTrackWIDTHResponse(jetP4.pt()/m_GeV*Corr,etabin,trackWIDTH);
406 if ( jetP4.pt() < m_punchThroughMinPt ) return Corr; //Applying punch through correction to low pT jets introduces a bias, default threshold is 50 GeV
407 //eta binning for the punch through correction differs from the rest of the GSC, so the eta bin is determined in the GetPunchThroughResponse method
408 else if (m_depth & ApplyPunchThrough) {
409 jetP4*=Corr; //The punch through correction is binned in E instead of pT, so we determine E from the corrected jet here
410 Corr*=1/getPunchThroughResponse(jetP4.e()/m_GeV,eta,Nsegments);
411 }
412 }
413 else if (m_caloBased){
414 if (m_depth & ApplyTile0) Corr*=1./getTile0Response(jetP4.pt()/m_GeV*Corr, etabin, Tile0);
415 if (m_depth & ApplyEM3) Corr*=1./getEM3Response(jetP4.pt()/m_GeV*Corr, etabin, EM3);
416 if (m_depth & ApplyN90Constituents) Corr*=1/getN90ConstituentsResponse(jetP4.pt()/m_GeV*Corr, etabin, N90Constituents);
417 if (m_depth & ApplyTileGap3) Corr*=1/getTileGap3Response(jetP4.pt()/m_GeV*Corr,etabin, TileGap3);
418 if (m_depth & ApplycaloWIDTH) Corr*=1/getCaloWIDTHResponse(jetP4.pt()/m_GeV*Corr,etabin,caloWIDTH);
419 }
420 else{ // PFlow
421 if (m_depth & ApplyChargedFraction) Corr*=1./getChargedFractionResponse(jetP4.pt()/m_GeV, etabin, ChargedFraction);
422 if (m_depth & ApplyTile0) Corr*=1./getTile0Response(jetP4.pt()/m_GeV*Corr, etabin, Tile0);
423 if (m_depth & ApplyEM3) Corr*=1./getEM3Response(jetP4.pt()/m_GeV*Corr, etabin, EM3);
424 if ( m_nTrkwTrk_4PFlow && (m_depth & ApplynTrk) ) Corr*=1./getNTrkResponse(jetP4.pt()/m_GeV*Corr, etabin, nTrk);
425 if ( m_nTrkwTrk_4PFlow && (m_depth & ApplytrackWIDTH) ) Corr*=1./getTrackWIDTHResponse(jetP4.pt()/m_GeV*Corr,etabin,trackWIDTH);
426 if ( jetP4.pt() < m_punchThroughMinPt ) return Corr; //Applying punch through correction to low pT jets introduces a bias, default threshold is 50 GeV
427 //eta binning for the punch through correction differs from the rest of the GSC, so the eta bin is determined in the GetPunchThroughResponse method
428 else if (m_depth & ApplyPunchThrough) {
429 jetP4*=Corr; //The punch through correction is binned in E instead of pT, so we determine E from the corrected jet here
430 Corr*=1/getPunchThroughResponse(jetP4.e()/m_GeV,eta,Nsegments);
431 }
432 }
433 return Corr;
434}
435
437
438 //vector<float> that holds the fractional energy deposited by the jet in different layers of the calorimetery
439 /* Map of the entries in the vector to different layers of the calorimeter
440 Retrieved on July 14th 2014 from https://twiki.cern.ch/twiki/bin/view/AtlasProtected/Run2JetMoments
441 If July 14th 2014 was awhile ago, it might be worth double checking this is still valid...
442
443 Layer Index
444 LAr barrel
445 PreSamplerB 0
446 EMB1 1
447 EMB2 2
448 EMB3 3
449 LAr EM endcap
450 PreSamplerE 4
451 EME1 5
452 EME2 6
453 EME3 7
454 Hadronic endcap
455 HEC0 8
456 HEC1 9
457 HEC2 10
458 HEC3 11
459 Tile barrel
460 TileBar0 12
461 TileBar1 13
462 TileBar2 14
463 Tile gap (ITC & scint)
464 TileGap1 15
465 TileGap2 16
466 TileGap3 17
467 Tile extended barrel
468 TileExt0 18
469 TileExt1 19
470 TileExt2 20
471 Forward EM endcap
472 FCAL0 21
473 FCAL1 22
474 FCAL2 23
475 Mini FCAL
476 MINIFCAL0 24
477 MINIFCAL1 25
478 MINIFCAL2 26
479 MINIFCAL3 27
480 */
481
482 std::vector<float> samplingFrac = jet.getAttribute<std::vector<float> >("EnergyPerSampling");
483 //vector<int> that holds the number of tracks with pT > 1 GeV for different primary vertices
484 std::vector<int> nTrk;
485 if(m_depth & ApplynTrk){
486 if( !jet.getAttribute<std::vector<int> >("NumTrkPt1000",nTrk) ) {
487 ATH_MSG_ERROR("Failed to retrieve NumTrkPt1000!");
488 return StatusCode::FAILURE;
489 }
490 }
491 //vector<float> that holds the trackWIDTH variable calculated with tracks of pT > 1 GeV for different primary vertices
492 std::vector<float> trackWIDTH;
494 if( !jet.getAttribute<std::vector<float> >("TrackWidthPt1000",trackWIDTH) ) {
495 ATH_MSG_ERROR("Failed to retrieve TrackWidthPt1000!");
496 return StatusCode::FAILURE;
497 }
498 }
499 //Nsegments number of ghost associated muon segments behind each jet
500 int Nsegments = 0;
502 static const SG::ConstAccessor<int> GhostMuonSegmentCountAcc ("GhostMuonSegmentCount");
503 if( GhostMuonSegmentCountAcc.isAvailable(jet) ) {
504 Nsegments = GhostMuonSegmentCountAcc(jet);
505 } else {
506 ATH_MSG_WARNING("GhostMuonSegmentCount is not available, Nsegments=0 will be used, so NO PunchThrough Correction will be applied!");
507 }
508 }
509
510 xAOD::JetFourMom_t jetconstitP4 = jet.getAttribute<xAOD::JetFourMom_t>("JetConstitScaleMomentum");
511
512 //Entry 0 of the ChargedFraction, nTrk, and trackWIDTH vectors should correspond to PV0
513 //other entries are for other primary vertices in the event
514 //Check what index the user wants just in case (default to PVIndex, which is typically PV0)
515 int PVindex = jetEventInfo.PVIndex();
516
518 // Retrieve the vertex the jet was reconstructed with respect to
519 PVindex = jet.getAssociatedObject<xAOD::Vertex>("OriginVertex")->index();
520 }
521
522 double ChargedFraction = 0;
523 if( m_PFlow ) ChargedFraction = (jet.getAttribute<std::vector<float> >("SumPtChargedPFOPt500"))[PVindex]/jetconstitP4.Pt();
524
525 xAOD::JetFourMom_t jetStartP4;
527 jetStartP4 = jet.jetP4();
528
529 float jetE_constitscale = jetconstitP4.e();
530 float detectorEta = jet.getAttribute<float>("DetectorEta");
531
532 int nTrkPVX = (m_depth & ApplynTrk) ? nTrk[PVindex] : 0;
533 float trackWIDTHPVX = (m_depth & ApplytrackWIDTH) ? trackWIDTH[PVindex] : 0;
534 //EM3 and Tile0 fraction calculations
535 //EM3 = (EMB3+EME3)/energy, Tile0 = (TileBar0+TileExt0)/energy
536 //Check the map above to make sure the correct entries of samplingFrac are being used
537 float EM3 = (samplingFrac[3]+samplingFrac[7])/jetE_constitscale;
538 float Tile0 = (samplingFrac[12]+samplingFrac[18])/jetE_constitscale;
539
540 double N90Constituents = 0;
541 double caloWIDTH = 0;
542 float TG3 = 0;
543 if (m_caloBased) {
545 //numConstituents = jet.numConstituents();
546 N90Constituents = jet.getAttribute<float>("N90Constituents");
547 }
548 if (m_depth & ApplycaloWIDTH) {
549 caloWIDTH = jet.getAttribute<double>("Width");
550 }
551 if (m_depth & ApplyTileGap3) {
552 //TileGap3 at index 17 of samplingFrac, see map above
553 TG3 = (samplingFrac[17])/jetE_constitscale;
554 }
555 }
556
557 xAOD::JetFourMom_t calibP4 = jetStartP4*getGSCCorrection( jetStartP4, fabs(detectorEta), trackWIDTHPVX, nTrkPVX, Tile0, EM3, Nsegments, ChargedFraction, caloWIDTH, N90Constituents, TG3);
558
559 //Transfer calibrated jet properties to the Jet object
560 jet.setAttribute<xAOD::JetFourMom_t>("JetGSCScaleMomentum",calibP4);
561 jet.setJetP4( calibP4 );
562
563 return StatusCode::SUCCESS;
564
565}
566
567
Scalar eta() const
pseudorapidity method
#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)
@ Data
Definition BaseObject.h:11
Helper class to provide constant type-safe access to aux data.
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
double getChargedFractionResponse(double pT, uint etabin, double ChargedFraction) const
void setPunchThroughEtaBins(const VecD &etabins)
double getEM3Response(double pT, uint etabin, double EM3) const
double getGSCCorrection(xAOD::JetFourMom_t jetP4, double eta, double trackWIDTH, double nTrk, double Tile0, double EM3, int Nsegments, double ChargedFraction, double caloWIDTH, double N90Constituents, double TileGap3) const
double getN90ConstituentsResponse(double pT, uint etabin, double N90Constituents) const
double getCaloWIDTHResponse(double pT, uint etabin, double caloWIDTH) const
virtual StatusCode initialize() override
double readPtJetPropertyHisto(double pT, double jetProperty, const TH2 &respFactors) const
virtual StatusCode calibrate(xAOD::Jet &jet, JetEventInfo &) const override
double getTrackWIDTHResponse(double pT, uint etabin, double trackWIDTH) const
double getTileGap3Response(double pT, uint etabin, double TileGap3) const
double getPunchThroughResponse(double E, double eta_det, int Nsegments) const
double getNTrkResponse(double pT, uint etabin, double nTrk) const
double getTile0Response(double pT, uint etabin, double Tile0) const
virtual StatusCode setStartP4(xAOD::Jet &jet) const
JetCalibrationStep(const char *name="JetCalibrationStep")
Helper class to provide constant type-safe access to aux data.
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
std::string depth
tag string for intendation
Definition fastadd.cxx:46
std::unique_ptr< const TH2 > GetHisto2(TFile &file, const TString &hname)
VecD VectorizeD(const TString &str, const TString &sep=" ")
Definition index.py:1
STL namespace.
Jet_v1 Jet
Definition of the current "jet version".
Vertex_v1 Vertex
Define the latest version of the vertex class.
ROOT::Math::LorentzVector< ROOT::Math::PtEtaPhiM4D< double > > JetFourMom_t
Base 4 Momentum type for Jet.
Definition JetTypes.h:17