ATLAS Offline Software
Loading...
Searching...
No Matches
ConfigUtils.py
Go to the documentation of this file.
1# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2
3import json, os
4from AthenaCommon.Utils.unixtools import find_datafile
5from AthenaCommon.Logging import logging
6
7def custom_find_datafile( input_file_name ):
8 '''
9 wrapper around AthenaCommon.Utils.unixtools.find_datafile
10 to handle local paths in the same running directory, by
11 returning the absolute path ( thisFile.json -> /path_to/thisFile.json )
12 '''
13 new_file_name = input_file_name
14 if not os.path.dirname( new_file_name ) :
15 new_file_name = os.path.abspath( new_file_name ) # attach absolute path
16 return find_datafile( new_file_name )
17
18
19def getTrkAnaDicts( flags ):
20 '''
21 utility function to retrieve the flag dictionary
22 for every TrackAnalysis from an input JSON file
23 '''
24 analysesDict = {}
25
26
27 if flags.PhysVal.IDTPM.trkAnaCfgFile == "Default":
28 return analysesDict
29
30
31 dataPath = custom_find_datafile( flags.PhysVal.IDTPM.trkAnaCfgFile )
32 if dataPath is None:
33 raise Exception(f"Input file with analyses definition: {dataPath} could not be found")
34 return analysesDict
35
36
37 analysesDictTmp = {}
38 with open( dataPath, "r" ) as input_json_file:
39 analysesDictTmp = json.load( input_json_file )
40
41
42 if analysesDictTmp:
43 for trkAnaName, trkAnaDict in analysesDictTmp.items():
44
45 analysesDict.update( { trkAnaName : trkAnaDict } )
46
47 analysesDict[trkAnaName]["anaTag"] = "_" + trkAnaName
48
49 if ( "SubFolder" not in analysesDict[trkAnaName].keys() or
50 analysesDict[trkAnaName]["SubFolder"] == "" ) :
51 analysesDict[trkAnaName]["SubFolder"] = trkAnaName
52 analysesDict[trkAnaName]["SubFolder"] += "/"
53
54 if "ChainNames" in analysesDict[trkAnaName]:
55 fullChainList = getChainList( flags, analysesDict[trkAnaName]["ChainNames"] )
56 analysesDict[trkAnaName]["ChainNames"] = fullChainList
57
58 return unpackTrkAnaDicts( analysesDict ) if flags.PhysVal.IDTPM.unpackTrigChains else analysesDict
59
60
61def unpackTrkAnaDicts( analysesDictIn ):
62 '''
63 utility function to define a separate TrackAnalysis
64 for each configured trigger chain
65 '''
66 if not analysesDictIn : return analysesDictIn
67
68 analysesDictOut = {}
69 for trkAnaName, trkAnaDict in analysesDictIn.items():
70 if "ChainNames" in trkAnaDict:
71 chainList = trkAnaDict["ChainNames"]
72 for chain in chainList:
73 trkAnaName_new = trkAnaName + "_" + chain
74 trkAnaDict_new = dict( trkAnaDict )
75 trkAnaDict_new["anaTag"] = trkAnaDict["anaTag"] + "_" + chain
76 trkAnaDict_new["ChainNames"] = [ chain ]
77 analysesDictOut.update( { trkAnaName_new : trkAnaDict_new } )
78 else:
79 analysesDictOut.update( { trkAnaName : trkAnaDict } )
80
81 return analysesDictOut
82
83
84
85def getChainList( flags, regexChainList=[] ):
86 '''
87 utility function to retrieve full list of
88 configured trigger chains matching
89 the passed regex list of chains
90 '''
91 if not regexChainList: return regexChainList
92
93 if not flags.locked():
94 flags_tmp = flags.clone()
95 flags_tmp.lock()
96 flags = flags_tmp
97
98 from TrigConfigSvc.TriggerConfigAccess import getHLTMenuAccess
99 chainsMenu = getHLTMenuAccess( flags )
100
101 import re
102 configChains = []
103 for regexChain in regexChainList:
104 for item in chainsMenu:
105 chains = re.findall( regexChain, item )
106 for chain in chains:
107 if chain is not None and chain == item:
108 configChains.append( chain )
109
110 return configChains
111
112
113def getPlotsDefList( flags ):
114 '''
115 Open json files and load all merged contents
116 in a dictionary, which is later converted to a
117 list of strings, each to be parsed in a
118 (flattened) json format
119 '''
120 log = logging.getLogger( "getPlotsDefList" )
121
122 # open the list of json files
123 log.debug( "plotsDefFileList : %s", flags.PhysVal.IDTPM.plotsDefFileList )
124 listPath = custom_find_datafile( flags.PhysVal.IDTPM.plotsDefFileList )
125 if listPath is None:
126 log.error( "plotsDefFileList not found" )
127 return None
128
129 plotsDefFileNames = []
130 with open( listPath, "r" ) as input_flist :
131 plotsDefFileNames = input_flist.read().splitlines()
132
133 # creating the basic histogrm definition dictionary
134 plotsDefDict = {}
135
136 for plotsDefFileName in plotsDefFileNames :
137 dataPath = custom_find_datafile( plotsDefFileName )
138 log.debug( "Reading input plots definitions : %s", dataPath )
139 if dataPath is None:
140 log.error( "plotsDefFile %s not found", plotsDefFileName )
141 return None
142
143 with open( dataPath, "r" ) as input_json_file :
144 plotsDefDict.update( json.load( input_json_file ) )
145
146 # Expand plots definitions for resolutions and pulls
147 # from corresponding TH2F Helpers
148 plotsDefDict = updateResolutionPlots( plotsDefDict )
149
150 # Turn all histo definitions into a list of strings
151 # each string has a flattened json format
152 def flatten_json( y ) :
153 out = {}
154 def flatten(x, name=''):
155 if type(x) is dict:
156 for a in x:
157 flatten(x[a], name + a + '_')
158 else:
159 out[name[:-1]] = x
160 flatten(y)
161 return out
162
163 plotsDefStrList_v1 = []
164 for plotName, plotDict in plotsDefDict.items():
165 newPlotDict = plotDict.copy()
166 newPlotDict[ "name" ] = plotName
167
168 # flatten json histo dict
169 plotDictFlat = flatten_json( newPlotDict )
170
171 # Turn json into string
172 plotDefStr = str( json.dumps( plotDictFlat ) )
173
174 # append to list
175 plotsDefStrList_v1.append( plotDefStr )
176
177 # Replace standard common fields (e.g. &ETAMAX)
178 # with corresponding values (read from default json)
179 plotsCommonValuesFileName = flags.PhysVal.IDTPM.plotsCommonValuesFile
180 if not plotsCommonValuesFileName :
181 if flags.Detector.GeometryID :
182 plotsCommonValuesFileName = "InDetTrackPerfMon/PlotsDefCommonValues.json"
183 elif flags.Detector.GeometryITk :
184 plotsCommonValuesFileName = "InDetTrackPerfMon/PlotsDefCommonValues_ITk.json"
185 else :
186 log.error( "Could not get detector geometry for plotsCommonValuesFile" )
187 return None
188
189 commonValuesPath = custom_find_datafile( plotsCommonValuesFileName )
190 if commonValuesPath is None :
191 log.error( "plotsCommonValuesFile not found: %s", plotsCommonValuesFileName )
192 return None
193
194 commonValuesDict = {}
195 with open( commonValuesPath, "r" ) as input_commonValues :
196 commonValuesDict.update( json.load( input_commonValues ) )
197
198 plotsDefStrList_v2 = []
199 for plotDefStr in plotsDefStrList_v1 :
200 newPlotDefStr = plotDefStr
201 if commonValuesDict :
202 for key, value in commonValuesDict.items() :
203 plotDefStr_tmp = newPlotDefStr.replace( "$"+key, value[0] )
204 newPlotDefStr = plotDefStr_tmp
205 plotsDefStrList_v2.append( newPlotDefStr )
206
207 # Now expand the list to account for all required track types
208 testLabel = getLabel( flags, flags.PhysVal.IDTPM.currentTrkAna.TestType )
209 refLabel = getLabel( flags, flags.PhysVal.IDTPM.currentTrkAna.RefType )
210 trkLabels = [ testLabel, refLabel ]
211
212 testAllLabel = getAllTruthLabel( flags, flags.PhysVal.IDTPM.currentTrkAna.TestType )
213 refAllLabel = getAllTruthLabel( flags, flags.PhysVal.IDTPM.currentTrkAna.RefType )
214
215
216 if flags.PhysVal.IDTPM.currentTrkAna.MatchingType == "EFTruthMatch":
217 trkLabels.append( getLabel( flags, "Truth" ) )
218
219
220 plotsDefStrList = []
221 for plotsDefStr in plotsDefStrList_v2 :
222 plotsDefStr = plotsDefStr.replace( "$TESTALL", testAllLabel ).replace( "$REFALL", refAllLabel )
223 plotsDefStr = plotsDefStr.replace( "$TESTTYPE", testLabel[1] ).replace( "$TESTTAG", testLabel[0] )
224 plotsDefStr = plotsDefStr.replace( "$REFTYPE", refLabel[1] ).replace( "$REFTAG", refLabel[0] )
225 if ( "$TRKTAG" not in plotsDefStr ) and ( "$TRKTYPE" not in plotsDefStr ) :
226 plotsDefStrList.append( plotsDefStr )
227 continue
228 for trkLabel in trkLabels :
229 newPlotsDefStr = plotsDefStr.replace( "$TRKTYPE", trkLabel[1] ).replace( "$TRKTAG", trkLabel[0] )
230 if ( "$TRK2TAG" not in newPlotsDefStr ) and ( "$TRK2TYPE" not in newPlotsDefStr ) :
231 plotsDefStrList.append( newPlotsDefStr )
232 continue
233 for trk2Label in trkLabels :
234 newPlotsDefStr2 = newPlotsDefStr.replace( "$TRK2TYPE", trk2Label[1] ).replace( "$TRK2TAG", trk2Label[0] )
235 plotsDefStrList.append( newPlotsDefStr2 )
236
237
238 plotsDefStrList_v2 = []
239 for plotsDefStr in plotsDefStrList :
240 plotsDefStr = plotsDefStr.replace( "$TESTVTXTYPE", testLabel[2] ).replace( "$TESTVTXTAG", testLabel[0] )
241 plotsDefStr = plotsDefStr.replace( "$REFVTXTYPE", refLabel[2] ).replace( "$REFVTXTAG", refLabel[0] )
242 if ( "$VTXTAG" not in plotsDefStr ) and ( "$VTXTYPE" not in plotsDefStr ) :
243 plotsDefStrList_v2.append( plotsDefStr )
244 continue
245 for trkLabel in trkLabels :
246 newPlotsDefStr = plotsDefStr.replace( "$VTXTYPE", trkLabel[2] ).replace( "$VTXTAG", trkLabel[0] )
247 if ( "$VTX2TAG" not in newPlotsDefStr ) and ( "$VTX2TYPE" not in newPlotsDefStr ) :
248 plotsDefStrList_v2.append( newPlotsDefStr )
249 continue
250 for trk2Label in trkLabels :
251 newPlotsDefStr2 = newPlotsDefStr.replace( "$VTX2TYPE", trk2Label[2] ).replace( "$VTX2TAG", trk2Label[0] )
252 plotsDefStrList_v2.append( newPlotsDefStr2 )
253
254 return plotsDefStrList_v2
255
256
257def getLabel( flags, key ) :
258 if key == "Offline" and flags.PhysVal.IDTPM.currentTrkAna.SelectOfflineObject:
259 if "Truth" not in flags.PhysVal.IDTPM.currentTrkAna.SelectOfflineObject:
260 key += flags.PhysVal.IDTPM.currentTrkAna.SelectOfflineObject
261 trkLabelsDict = {
262 # key : [ trk/vtx_tag, track_type, vertex_type ]
263 "EFTrigger" : [ "eftrig", "EF Trigger track", "EF Trigger vertex" ],
264 "Trigger" : [ "trig", "Trigger track", "Trigger vertex" ],
265 "Offline" : [ "offl", "Offline track", "Offline vertex" ],
266 "OfflineElectron" : [ "offEle", "Offline e^{#pm} track", "Offline e^{#pm} vertex" ],
267 "OfflineMuon" : [ "offMu", "Offline #mu^{#pm} track", "Offline #mu^{#pm} vertex" ],
268 "OfflineTau" : [ "offTau", "Offline #tau^{#pm} track", "Offline #tau^{#pm} vertex" ],
269 "OfflineJet" : [ "offlJet", "Offline track in jet", "Offline vertex in jet" ],
270 "Truth" : [ "truth", "Truth particle", "Truth vertex" ],
271 "TruthElectron" : [ "truthEle", "Truth e^{#pm}", "Truth e^{#pm} vertex" ],
272 "TruthMuon" : [ "truthMu", "Truth #mu^{#pm}", "Truth #mu^{#pm} vertex" ],
273 "TruthTau" : [ "truthTau", "Truth #tau^{#pm}", "Truth #tau^{#pm} vertex" ]
274 }
275 return trkLabelsDict[ key ]
276
277
278def getTag( flags, key ) :
279 labels = getLabel( flags, key )
280 return labels[0]
281
282
283def updateResolutionPlots( myPlotsDefDict ) :
284 # initialize output dict to input
285 outDict = myPlotsDefDict.copy()
286
287 items = [ "res", "pull" ]
288 plist = [ "mean", "width" ]
289 iDict = {
290 "res" : {
291 "helper" : { "name" : "resHelper", "yTitle" : "residual" },
292 "mean" : { "name" : "resmean", "yTitle" : "bias" },
293 "width" : { "name" : "resolution", "yTitle" : "resolution" }
294 },
295 "pull" : {
296 "helper" : { "name" : "pullHelper", "yTitle" : "pull" },
297 "mean" : { "name" : "pullmean", "yTitle" : "pull mean" },
298 "width" : { "name" : "pullwidth", "yTitle" : "pull width" }
299 }
300 }
301
302 for plotName, plotDict in myPlotsDefDict.items() :
303 # processing resHelpers and pullHelpers
304 for i in items:
305 if iDict[i]["helper"]["name"] in plotName :
306 # processing mean and width plots
307 for p in plist :
308 # Computing the derived plot (mean or width) name from helper
309 pName = plotName.replace( iDict[i]["helper"]["name"], iDict[i][p]["name"] )
310
311 pDict = {}
312 if pName in outDict :
313 # plot definition already exists. Grabbing the original
314 pDict = outDict[ pName ]
315 else :
316 # plot definition doesn't exist.
317 # Computing and setting yAxis title from helper's yAxis'
318 # (e.g. "VAR residual [unit]" -> "VAR resolution [unit]")
319 yTitle = plotDict["yAxis"]["title"]
320 yTitle = yTitle.replace( iDict[i]["helper"]["yTitle"], iDict[i][p]["yTitle"] )
321 pDict.update( { "yAxis" : { "title" : yTitle } } )
322
323 # forcing x-axis to be the same as helper's (in all cases) and type = TH1F
324 pDict.update( {
325 "type" : "TH1F",
326 "xAxis" : plotDict["xAxis"]
327 } )
328
329 # update outdict
330 outDict.update( { pName : pDict } )
331
332 return outDict
333
334
335def getAllTruthLabel( flags, key ) :
336
338 if key != "Truth":
339 return "All"
340 if flags.PhysVal.IDTPM.currentTrkAna.pileupSwitch == "HardScatter" :
341 return "All HS"
342 if flags.PhysVal.IDTPM.currentTrkAna.pileupSwitch == "PileUp" :
343 return "All PU"
344 return "All"
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:310
unpackTrkAnaDicts(analysesDictIn)
getChainList(flags, regexChainList=[])
getPlotsDefList(flags)
custom_find_datafile(input_file_name)
Definition ConfigUtils.py:7
getAllTruthLabel(flags, key)
getTag(flags, key)
getTrkAnaDicts(flags)
getLabel(flags, key)
updateResolutionPlots(myPlotsDefDict)