ATLAS Offline Software
Loading...
Searching...
No Matches
JetCalibToolsConfig.py
Go to the documentation of this file.
1# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3
13from AthenaConfiguration.Enums import LHCPeriod
14from JetRecConfig.StandardJetConstits import inputsFromContext
15
16from AthenaCommon import Logging
17jetcaliblog = Logging.logging.getLogger('JetCalibToolsConfig')
18
19all = ['getJetCalibTool']
20
21# These context definitions could be placed in another package and made
22# more robust with a small python class to hold the info.
23# The convention is: config file, calibarea, default calibration sequence
24pflowcontexts = {
25 "T0":("JES_MC15cRecommendation_PFlow_Aug2016_rel21.config","00-04-77","JetArea_Residual_EtaJES"),
26 # Omit smearing, to avoid any efficiency loss
27 "AnalysisLatest":("PreRec_R22_PFlow_ResPU_EtaJES_GSC_February23_230215.config","00-04-82","JetArea_Residual_EtaJES_GSC_Insitu"),
28 "TrigLS2":("JES_MC16Recommendation_Consolidated_PFlow_Apr2019_Rel21_Trigger.config","00-04-82","JetArea_Residual_EtaJES_GSC_Insitu"),
29 "Trigger":("JES_MC16Recommendation_Consolidated_PFlow_30May2022_Rel22_Trigger.config","00-04-82","JetArea_Residual_EtaJES_GSC_Insitu"),
30 "TrigR22Prerec":("PreRec_R22_PFlow_ResPU_EtaJES_GSC_February23_230215.config", "00-04-82", "JetArea_Residual_EtaJES_GSC_Insitu"),
31 "TrigHIUPC" : ("JES_MC16Recommendation_LowMu1718_MCJES_GSC_nTrkOn_PFlow_Sep2023_Rel21.config", "00-04-82", "EtaJES_GSC"),
32}
33
34topocontexts = {
35 "T0":("JES_MC15cRecommendation_May2016_rel21.config","00-04-77","JetArea_Residual_EtaJES"),
36 # Omit smearing, to avoid any efficiency loss
37 "AnalysisLatest":("JES_MC16Recommendation_Consolidated_EMTopo_Apr2019_Rel21.config","00-04-82","JetArea_Residual_EtaJES_GSC_Insitu"),
38 "TrigRun2":("JES_MC15cRecommendation_May2016_Trigger.config","00-04-77","JetArea_EtaJES_GSC_Insitu"),
39 "TrigRun2GSC":("JES_data2016_data2015_Recommendation_Dec2016_rel21.config","00-04-77","JetArea_EtaJES_GSC_Insitu"),
40 "TrigLS2":("JES_MC16Recommendation_Consolidated_EMTopo_Apr2019_Rel21_Trigger.config","00-04-82","JetArea_Residual_EtaJES_GSC_Insitu"),
41 "Trigger":("JES_MC16Recommendation_Consolidated_EMTopo_Apr2019_Rel21_Trigger.config","00-04-82","JetArea_Residual_EtaJES_GSC_Insitu"),
42 "HLLHC":("HLLHC/JES_MC16_HLLHC_Aug2021_rel21.config","00-04-82","JetArea_Residual_EtaJES"),
43}
44
45ufocontexts = {
46 "T0":("Consolidated_R22_CSSKUFO_ResPU_EtaJES_GNNC_20231103.config", "00-04-83", "Residual_EtaJES_GNNC"),
47}
48
49rscanlc2 = {
50 "RScanLatest":("JES_MC16Recommendation_Rscan2LC_22Feb2018_rel21.config","00-04-81","JetArea_Residual_EtaJES_GSC_Insitu")
51}
52
53rscanlc6 = {
54 "RScanLatest":("JES_MC16Recommendation_Rscan6LC_22Feb2018_rel21.config","00-04-81","JetArea_Residual_EtaJES_GSC_Insitu")
55}
56
57fatjetcontexts = {
58 "CombinedMass": ("JES_MC16recommendation_FatJet_Trimmed_JMS_comb_17Oct2018.config","00-04-82","EtaJES_JMS"),
59 "CaloMass": ("JES_MC16recommendation_FatJet_Trimmed_JMS_calo_12Oct2018.config","00-04-82","EtaJES_JMS"),
60 "TAMass": ("JES_MC16recommendation_FatJet_Trimmed_JMS_TA_12Oct2018.config","00-04-82","EtaJES_JMS"),
61 "SoftDrop": ("JES_MC20PreRecommendation_R10_UFO_CSSK_SoftDrop_JMS_R21Insitu_26Nov2024.config","00-04-83","EtaJES_JMS"),
62 "TrigUngroomed": ("JES_Full2012dataset_Rscan_June2014.config","00-04-77","JetArea_EtaJES"),
63 "TrigTrimmed": ("JES_MC15recommendation_FatJet_June2015_PtFrac4.config","00-04-82","EtaJES_JMS"),
64 "TrigSoftDrop": ("JES_MC16recommendation_R10_UFO_CSSK_SoftDrop_JMS_01April2020.config","00-04-82","EtaJES_JMS"),
65 "TrigHLTSoftDrop":("JES_JMS_MC21_R10_PFlow_CSSK_SoftDrop_Dec2023_Trigger.config", "00-04-83","EtaJES_JMS"),
66 "LargeRDNN": ("JES_JMS_MC20dnnc_R10_UFO_CSSK_SoftDrop_Jun2023.config","00-04-83","LargeRDNN"),
67}
68
69# List AFII config files separately, to avoid needing to specify a different context
70af2configs = {
71 "AntiKt4EMPFlow": "JES_MC16Recommendation_AFII_PFlow_Apr2019_Rel21.config",
72 "AntiKt4GPFlow": "JES_MC16Recommendation_AFII_PFlow_Apr2019_Rel21.config",
73 "AntiKt4EMTopo": "JES_MC16Recommendation_AFII_EMTopo_Apr2019_Rel21.config",
74 "AntiKt4LCTopo": "JES_MC16Recommendation_AFII_EMTopo_Apr2019_Rel21.config",
75}
76
77calibcontexts = {
78 # Standard AntiKt4
79 "AntiKt4EMPFlow":pflowcontexts,
80 "AntiKt4EMPFlow_noElectrons":pflowcontexts,
81 "AntiKt4EMPFlow_noMuons":pflowcontexts,
82 "AntiKt4EMPFlow_noLeptons":pflowcontexts,
83 "AntiKt4EMPFlow_inclMuons":pflowcontexts,
84 "AntiKt4EMPFlow_tauSeedEleRM":pflowcontexts,
85 "AntiKt4EMPFlowCustomVtx":pflowcontexts,
86 "AntiKt4EMPFlowByVertex":pflowcontexts,
87 "AntiKt4GPFlow":pflowcontexts,
88 "AntiKt4UFOCSSK":ufocontexts,
89 "AntiKt4EMTopo":topocontexts,
90 "AntiKt4LCTopo":topocontexts,
91 "AntiKt4EMTopoCustomVtxGNN":topocontexts,
92 "AntiKt10LCTopo":fatjetcontexts,
93 # Standard trimmed
94 "AntiKt10LCTopoTrimmedPtFrac5SmallR20":fatjetcontexts,
95 "AntiKt10LCTopoTrimmedPtFrac4SmallR20":fatjetcontexts,
96 # Standard UFO CS+SK jets
97 "AntiKt10UFOCSSKSoftDropBeta100Zcut10":fatjetcontexts,
98 # UFO CS+SK jets with leptons removed
99 "AntiKt10UFOCSSK_noElectronsSoftDropBeta100Zcut10":fatjetcontexts,
100 "AntiKt10UFOCSSK_noMuonsSoftDropBeta100Zcut10":fatjetcontexts,
101 "AntiKt10UFOCSSK_noLeptonsSoftDropBeta100Zcut10":fatjetcontexts,
102 # Large-R PFlow Soft Drop CSSK
103 "AntiKt10EMPFlowCSSKSoftDropBeta100Zcut10":fatjetcontexts,
104 "AntiKt10UFOCSSK_inclMuonsSoftDropBeta100Zcut10":fatjetcontexts,
105 # R-Scan
106 "AntiKt2LCTopo":rscanlc2,
107 "AntiKt6LCTopo":rscanlc6,
108
109}
110
111hasInSitu = ["AntiKt4LCTopo", "AntiKt4EMTopo", "AntiKt4EMPFlow", "AntiKt4EMPFlow_noElectrons", "AntiKt4EMPFlow_noMuons", "AntiKt4EMPFlow_noLeptons", "AntiKt4EMPFlow_inclMuons","AntiKt4EMPFlow_tauSeedEleRM","TrigAntiKt4EMTopo"]
112
113# This method extracts the relevant configuration, does some consistency checks,
114# then forwards the configuration to defineJetCalibTool, returning the output.
115# At present the interface allows for the calibseq to be chosen freely, other
116# than checking that the data source is data for the in situ correction.
117def getJetCalibTool(jetdef, context, data_type, calibseq = "", rhoname = "", pvname = "PrimaryVertices", gscdepth = "auto"):
118
119 jetcollection = jetdef.basename
120
121 # In principle we could autoconfigure
122 if data_type not in ['data','mc','afii']:
123 jetcaliblog.error("JetCalibConfig accepts data_type values: 'data', 'mc', 'afii'")
124 raise ValueError("Unsupported data_type provided: '{0}".format(data_type))
125
126 if jetcollection.endswith("Jets"):
127 jetcaliblog.error("Jet collection '{0}'should be specified w/o 'Jets' in the name.".format(jetcollection))
128 raise ValueError("Bad jet collection formatting in getJetCalibTool.")
129
130 jetcaliblog.debug("Preparing calibration for {0}, in context {1} on sample type {2}".format(jetcollection,context,data_type))
131
132 jetcontexts = calibcontexts[jetcollection]
133
134 if jetcollection == "AntiKt4EMTopo" and context == "T0":
135 if jetdef._cflags.GeoModel.Run >= LHCPeriod.Run4:
136 context = "HLLHC"
137
138 try:
139 configfile, calibarea, calibseq_def = jetcontexts[context]
140 _calibseq = calibseq if calibseq else calibseq_def
141
142 # Check that the calib sequence requests something sensible for the in situ calibration
143 # Leave other checks for the tool code.
144 # Might need to specialise if we decide MC trigger jets should also have in situ.
145 if _calibseq.endswith("Insitu"):
146 if data_type == 'data':
147 if jetcollection not in hasInSitu:
148 raise ValueError("In situ calibration does not exist for {0}, context {1}".format(jetcollection,context))
149 else:
150 raise ValueError("In situ calibration requested for MC on {0}, context {1}".format(jetcollection,context))
151 _configfile = configfile
152 if data_type == "afii" and jetcollection in af2configs.keys():
153 _configfile = af2configs[jetcollection]
154 _data_type = data_type
155 # Most likely an oversight, but R20/21 JetRecCalibrationFinder did not set the data flag
156 # This affects the residual correction by scaling mu.
157 # We should revert this later on, set up now for validation purposes
158 if context == "T0":
159 _data_type = "data"
160 _pvname = ""
161 if "Residual" in _calibseq or "GSC" in _calibseq and gscdepth!="EM3" or "LargeRDNN" in _calibseq:
162 _pvname = pvname
163 # HACK: For Trigger HI UPC who want to do pflow but avoid track-GSC
164 if context == "TrigHIUPC":
165 _pvname = pvname
166 # HACK: For testing while we don't have finalised calibrations for trigger PF jets
167 _jetcollection = jetcollection
168 if "PFlow" in jetcollection and (context=="TrigSoftDrop" or context=="TrigHLTSoftDrop"):
169 _jetcollection = jetcollection.replace("EMPFlow","UFO")
170 # Use standard calibrations for certain jet collections
171 # with minor changes to their constituents that should
172 # not invalidate the JES
173 ignore_substr = [
174 '_noElectrons', '_noMuons', '_noLeptons', '_inclMuons',
175 '_tauSeedEleRM',
176 'ByVertex', 'CustomVtxGNN', 'CustomVtx',
177 ]
178 for text in ignore_substr:
179 if text in jetcollection :
180 _jetcollection = _jetcollection.replace(text,"")
181
182 return defineJetCalibTool(_jetcollection, context, _configfile, calibarea, _calibseq, _data_type, rhoname, _pvname, gscdepth)
183 except KeyError as e:
184 jetcaliblog.error("Context '{0}' not found for jet collection '{1}'".format(context,jetcollection))
185 jetcaliblog.error("Options are '{0}".format(','.join(jetcontexts.keys())))
186 raise e
187 return None
188
189# This method actually sets up the tool
190def defineJetCalibTool(jetcollection, context, configfile, calibarea, calibseq, data_type, rhoname, pvname, gscdepth):
191 # Abbreviate the calib sequence
192 calibseqshort = ''.join([ step[0] for step in calibseq.split('_') ])
193 toolname = "jetcalib_{0}_{1}_{2}".format(jetcollection,calibseqshort,context)
194 #
195 from AthenaConfiguration.ComponentFactory import CompFactory
196 jct = CompFactory.JetCalibrationTool(toolname,
197 JetCollection = jetcollection,
198 ConfigFile = configfile,
199 CalibArea = calibarea,
200 CalibSequence = calibseq,
201 IsData = (data_type == "data"),
202 RhoKey = rhoname,
203 PrimaryVerticesContainerName = pvname,
204 GSCDepth = gscdepth
205 )
206 return jct
207
208# This method extends the basic config getter to specify the requisite jet
209# moments or other inputs
210def getJetCalibToolPrereqs(modspec,jetdef):
211 calibcontext, data_type, calibseq, rhoname, pvname, gscdepth = getCalibSpecsFromString(jetdef, modspec)
212 if calibseq=="":
213 cfg, calibarea, calibseq = calibcontexts[jetdef.basename][calibcontext]
214
215 # For now, only dependent on calibseq -- can ignore Insitu, which is
216 # added when getting the concrete tool
217 prereqs = []
218 prereqs.append("mod:ConstitFourMom")
219 if "JetArea" in calibseq: # Will not insert a prefix here
220 if calibcontext.startswith("Trig"): prereqs.append("input:HLT_EventDensity")
221 elif pvname == "PrimaryVertices_initial": prereqs.append("input:EventDensityCustomVtxGNN")
222 elif pvname != "PrimaryVertices": prereqs.append("input:EventDensityCustomVtx")
223 else: prereqs.append(inputsFromContext("EventDensity")(jetdef))
224 if "GSC" in calibseq:
225 prereqs += ["mod:CaloEnergies"]
226 if calibcontext != "TrigRun2": # No track/MS GSC for trigger w/o FTK
227 prereqs += ["mod:TrackMoments",
228 "ghost:MuonSegment"]
229 if "GNNC" in calibseq:
230 prereqs += ["mod:CaloQuality","mod:TrackMoments"]
231 if "CombinedMass" in calibcontext:
232 prereqs += ["mod:TrackSumMoments"]
233 if "LargeRDNN" in calibseq:
234 prereqs += ["mod:CaloEnergiesLargeR","mod:ConstitFrac","mod:groomMRatio","mod:Width",
235 "mod:nsubjettiness","mod:nsubjettinessR","mod:ktsplitter","mod:ecorr",
236 "mod:ecorrR","mod:qw"]
237 jetcaliblog.debug("Prereqs for calibseq '{0}': {1}".format(calibseq,str(prereqs)))
238 return prereqs
239
240# This method translates the mod specification string into calibration specifications
241def getCalibSpecsFromString(jetdef, modspec):
242 calibseq = ""
243 # for the LCTopo EleRM context used for EleRM taus, we need alternative EventShape container
244 rhoname = "EleRM_Kt4LCTopoOriginEventShape" if jetdef.context == "EleRM" else "auto"
245 pvname = "PrimaryVertices"
246 gscdepth = "auto"
247 calibspecs = modspec.split(':')
248 # Probably want data_type to come from elsewhere
249 calibcontext, data_type = calibspecs[:2]
250 if len(calibspecs)>2: calibseq = calibspecs[2]
251 if len(calibspecs)>3: rhoname = calibspecs[3]
252 if len(calibspecs)>4: pvname = calibspecs[4]
253 if len(calibspecs)>5: gscdepth = calibspecs[5]
254
255 return calibcontext, data_type, calibseq, rhoname, pvname, gscdepth
256
257# This method instantiates the JetCalibTool given the input mod specification
258def getJetCalibToolFromString(jetdef, modspec):
259 calibcontext, data_type, calibseq, rhoname, pvname, gscdepth = getCalibSpecsFromString(jetdef, modspec)
260 return getJetCalibTool(jetdef,calibcontext,data_type,calibseq,rhoname,pvname,gscdepth)
defineJetCalibTool(jetcollection, context, configfile, calibarea, calibseq, data_type, rhoname, pvname, gscdepth)
getJetCalibTool(jetdef, context, data_type, calibseq="", rhoname="", pvname="PrimaryVertices", gscdepth="auto")
getJetCalibToolFromString(jetdef, modspec)
getJetCalibToolPrereqs(modspec, jetdef)
getCalibSpecsFromString(jetdef, modspec)