ATLAS Offline Software
Loading...
Searching...
No Matches
JetCalibStepsConfig.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3from AnaAlgorithm.DualUseConfig import isAthena
4if not isAthena:
5
8 import AnaAlgorithm.AlgSequence # noqa: F401
9 import JetRecConfig.JetAnalysisCommon # noqa: F401
10
11from AthenaCommon import Logging
12jcslog = Logging.logging.getLogger('JetCalibStepsConfig')
13
14from JetToolHelpers.HelperConfig import VarToolCfg, HistoInputCfg
15from AthenaConfiguration.ComponentFactory import CompFactory
16from PathResolver import PathResolver
17
18def smearingStep(flags, **configDict):
19 """ Configuration of the Smearing step. """
20
21 # HistoReaderMC and HistoReaderData can be specified simultaneously using a single "HistoReader" YAML block.
22 # This should contain the common configuration for both and histNameMC/histNameData entries for the histogram names.
23 # This cannot be used simultaneously with a HistoReaderMC or HistoReaderData block
24 if "HistoReader" in configDict:
25 if "HistoReaderMC" in configDict:
26 raise JetCalibConfigError("Both HistoReader and HistoReaderMC blocks included in YAML config")
27 if "HistoReaderData" in configDict:
28 raise JetCalibConfigError("Both HistoReader and HistoReaderData blocks included in YAML config")
29
30 # Build the HistoReaderMC and HistoReaderData blocks from the HistoReader block
31 histoReader = configDict.pop("HistoReader")
32 histNameMC = histoReader.pop("histNameMC")
33 histNameData = histoReader.pop("histNameData")
34 configDict["HistoReaderMC"] = dict(histoReader)
35 configDict["HistoReaderData"] = dict(histoReader)
36 configDict["HistoReaderMC"]["histName"] = histNameMC
37 configDict["HistoReaderData"]["histName"] = histNameData
38
39 configDict["HistoReaderMC"]["inputFile"] = PathResolver.FindCalibFile(configDict["HistoReaderMC"]["inputFile"])
40 configDict["HistoReaderData"]["inputFile"] = PathResolver.FindCalibFile(configDict["HistoReaderData"]["inputFile"])
41
42 histToolMC = HistoInputCfg(flags, "HistToolMC", **configDict["HistoReaderMC"])
43 histToolData = HistoInputCfg(flags, "HistToolData", **configDict["HistoReaderData"])
44 configDict["HistoReaderMC"] = histToolMC
45 configDict["HistoReaderData"] = histToolData
46
47 smearStep = CompFactory.SmearingCalibStep("SmearingCalibStep", **configDict)
48
49 return smearStep
50
51def puresidualStep(flags, **configDict):
52
53 configDict.setdefault('IsData', not flags.Input.isMC)
54
55 return CompFactory.Pileup1DResidualCalibStep("PUResid", **configDict)
56
57
58def gscStep(flags, **configDict):
59
60 defaultFileGSC = PathResolver.FindCalibFile(configDict.pop('fileGSC'))
61
62 # These HistoInput2D defaults can't be set in the C++, so are set here:
63 defaultHistTools = dict(
64 histTool_EM3 = [dict(varX = "pt", varY = "EM3", histName=f"AntiKt4EMPFlow_EM3_interpolation_resp_eta_{j}", inputFile=defaultFileGSC) for j in range(35)],
65 histTool_CharFrac = [dict(varX = "pt", varY = "ChargedFraction", histName = f"AntiKt4EMPFlow_chargedFraction_interpolation_resp_eta_{j}", inputFile=defaultFileGSC) for j in range(25)],
66 histTool_Tile0 = [dict(varX = "pt", varY = "Tile0", histName=f"AntiKt4EMPFlow_Tile0_interpolation_resp_eta_{j}", inputFile=defaultFileGSC) for j in range(18)],
67 histTool_nTrk=[dict(varX = "pt", varY = dict(Name="nTrk", Type="int",), histName=f"AntiKt4EMPFlow_nTrk_interpolation_resp_eta_{j}", inputFile=defaultFileGSC) for j in range(25)],
68 histTool_trackWIDTH=[dict(varX = "pt", varY = "trackWIDTH", histName=f"AntiKt4EMPFlow_trackWIDTH_interpolation_resp_eta_{j}", inputFile=defaultFileGSC) for j in range(25)],
69 histTool_PunchThrough=[dict(varX = "e", varY = dict(Name="Nsegments", Type="int",), histName=f"AntiKt4EMPFlow_PunchThrough_interpolation_resp_eta_{j}", inputFile=defaultFileGSC) for j in range(2)],
70 )
71
72 gsc_steps = ['histTool_EM3', 'histTool_CharFrac', 'histTool_Tile0', 'histTool_nTrk', 'histTool_trackWIDTH']
73 if configDict['applyPunchThrough']:
74 gsc_steps.append('histTool_PunchThrough')
75
76 # Build the hist tools
77 for key in gsc_steps:
78 # Use defaultHistTools by default
79 if key not in configDict:
80 toolArray = defaultHistTools[key]
81
82 # In this case the full list of sub-tools has been specified in the YAML
83 # and the defaultDict will be fully overwritten (ie. all parameters must be specified)
84 elif isinstance(configDict[key],list):
85 toolArray = configDict[key]
86 for subDict in toolArray:
87 subDict.setdefault('inputFile',defaultFileGSC)
88
89 # Functionality to build the arrays of histogram reader from a shorter block in the YAML file
90 # Fall back on defaultHistTools for defaults
91 else:
92 baseDict = dict(configDict[key])
93 N_hist = baseDict.pop('N_hist')
94 histNameBase = baseDict.pop('histNameBase')
95 inputFile = baseDict.pop('inputFile', defaultFileGSC)
96 varX = baseDict.pop('varX',defaultHistTools[key][0]['varX'])
97 varY = baseDict.pop('varY', defaultHistTools[key][0]['varY'])
98 toolArray = [dict(varX = varX, varY = varY, histName=f'{histNameBase}_{j}', inputFile = inputFile) for j in range(N_hist)]
99
100 # Convert array of properties to HistoInput tools
101 configDict[key] = [HistoInputCfg(flags, Tname=f"{key.split('_')[1]}_{j}", **toolConfig) for j, toolConfig in enumerate(toolArray)]
102
103 GSCstep = CompFactory.GSCCalibStep("gsccalibstep", **configDict)
104
105 return GSCstep
106
107def etajesStep(flags, **configDic):
108
109 pVars = configDic.pop("ParametrizedVars")
110
111 jesstep = CompFactory.EtaJESCalibStep("EtaJESCalib",
112 VarToolE= VarToolCfg(flags, var=pVars['varE']),
113 VarToolEta= VarToolCfg(flags, var=pVars["varEta"]),
114 **configDic
115 )
116 return jesstep
117
118def jmsStep(flags, **configDic):
119
120 histoParams = configDic.pop('histoParams')
121 histoParams['inputFile'] = PathResolver.FindCalibFile(configDic.pop('HistoFile'))
122
123 configDic["histoReaderJMS"] = HistoInputCfg(flags, "HistToolJMS", **histoParams)
124 configDic['varToolX'] = VarToolCfg(flags, var=histoParams['varX'], Tname="VarToolX_JMS")
125 configDic['varToolZ'] = VarToolCfg(flags, var=histoParams['varZ'], Tname="VarToolZ_JMS")
126
127 jmsstep = CompFactory.JMSCalibStep("JMSCalib",
128 **configDic
129 )
130 return jmsstep
131
132def insituStep(flags, **configDic):
133
134 histEtaInterCalib = configDic.pop('histEtaInterCalib')
135 histAbsCalib = configDic.pop('histAbsCalib')
136
137 histoReaderEta_vec, histoReaderAbs_vec = [], []
138
139 for infile in configDic.pop('fileInsitu'):
140 histoReaderEta_vec.append(dict(inputFile = PathResolver.FindCalibFile(infile), **histEtaInterCalib))
141 histoReaderAbs_vec.append(dict(inputFile = PathResolver.FindCalibFile(infile), **histAbsCalib))
142 configDic['HistoReaderEtaInter'] = [HistoInputCfg(flags, "HistToolEtaInter"+str(j), **etaDic) for j, etaDic in enumerate(histoReaderEta_vec)]
143 configDic['HistoReaderAbs'] = [HistoInputCfg(flags, "HistToolAbs"+str(j), **absDic) for j, absDic in enumerate(histoReaderAbs_vec)]
144
145 configDic['vartool1'] = VarToolCfg(flags, var=histEtaInterCalib['varX'], Tname="VarTool")
146 configDic['vartool2'] = VarToolCfg(flags, var=histEtaInterCalib['varY'], Tname="VarTool")
147 configDic['isMC'] = flags.Input.isMC
148
149 insituStep = CompFactory.InSituCalibStep("insitucalibstep", **configDic)
150
151 return insituStep
152
153
154
155calibStepDic = dict(
156 JetArea = None,
157 Residual = puresidualStep,
158 EtaJES = etajesStep,
159 JMS = jmsStep,
160 GSC = gscStep,
161 Insitu = insituStep,
162 Smear = smearingStep,
163)
164
165def calibConfigToToolList(flags, **configDict):
166 """
167 Returns a list of instantiated tools for each of the calibration steps.
168 The order of the steps is determined by the InScale and OutScale properties given in the config.
169 Tools are instantiated by calling functions declared in the calibStepDic dictionary.
170 """
171
172 toolDic = {}
173 foundCS = False # check at least one of the steps starts from constituent scale
174 for step in configDict:
175
176 configDict.get(step).pop('prereqs',{}) # removes the 'prereqs' entry not refined in steps
177 # expert option to skip a step
178 if configDict.get(step).pop('noRun',False):
179 jcslog.warning(f'Expert option: Skipping calib step {step}')
180 continue
181
182 # Skip Insitu for MC
183 if step=="Insitu" and flags.Input.isMC and not configDict.get("Insitu").get("CalibrateMC",False):
184 jcslog.info('Skipping Insitu for MC')
185 continue
186
187 calibFunc = calibStepDic.get(step,None)
188 if calibFunc is None:
189 raise NotImplementedError(f'Calibration step {step} is not found in calibStepDic')
190
191 calibConfig = configDict.get(step)
192
193 tool = calibFunc(flags, **calibConfig)
194
195 toolDic[step] = tool
196 if tool.InScale == "JetConstitScaleMomentum":
197 foundCS = True
198
199 if not foundCS:
200 raise JetCalibConfigError('At least one step must have InScale = JetConstitScaleMomentum')
201
202 ordered_tools = []
203 ordered_step_names = []
204
205 def findNextSteps(startScale = "JetConstitScaleMomentum"):
206 ''' Recursively add tools to ordered_tools based on in/out scale '''
207 for step in toolDic:
208 if toolDic[step].InScale == startScale:
209 ordered_tools.append(toolDic[step])
210 ordered_step_names.append(step)
211 findNextSteps(toolDic[step].OutScale)
212
213 findNextSteps()
214
215 # Check we've got all the steps
216 for step in toolDic:
217 if step not in ordered_step_names:
218 raise JetCalibConfigError(f'Could not place calib step {step} - have you set InScale and OutScale correctly?')
219
220 jcslog.info(f'Ordered jet calib steps: {"->".join(ordered_step_names)}')
221
222 return ordered_tools
223
224def calibToolFromConfigFile(flags, configFile, name = "jetcalib"):
225
226 configDic = load_yaml_cfg(configFile)
227
228 globalSettings = configDic.pop('Global',{})
229
230 calibTool = CompFactory.JetCalibTool(name, CalibSteps=calibConfigToToolList(flags, **configDic), **globalSettings)
231 return calibTool
232
233def load_yaml_cfg(configFile):
234 from yaml import safe_load
235
236 path_configFile = PathResolver.FindCalibFile(configFile)
237 configDic = safe_load(open(path_configFile))
238 return configDic
239
240
241class JetCalibConfigError(Exception):
242 """ Exception raised for invalid jet calibration config """
243
244 def __init__(self, message):
245 super().__init__(message)
246 self.message = message
247
248 def __str__(self):
249 return self.message
static std::string FindCalibFile(const std::string &logical_file_name)
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
calibToolFromConfigFile(flags, configFile, name="jetcalib")
insituStep(flags, **configDic)
smearingStep(flags, **configDict)
gscStep(flags, **configDict)
puresidualStep(flags, **configDict)
etajesStep(flags, **configDic)
calibConfigToToolList(flags, **configDict)
jmsStep(flags, **configDic)