ATLAS Offline Software
Loading...
Searching...
No Matches
TriggerDataAccess.py
Go to the documentation of this file.
1# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2
3__author__ = 'Javier Montejo'
4__version__="$Revision: 2.0 $"
5__doc__="Access to Trigger DB and TriggerMenu to read past and future prescales"
6
7import itertools
8import sys
9from TriggerMenuMT.TriggerAPI.TriggerEnums import TriggerPeriod, LBexceptions, TriggerRenaming
10from TriggerMenuMT.TriggerAPI.TriggerPeriodData import TriggerPeriodData
11from AthenaCommon.Logging import logging
12log = logging.getLogger(__name__)
13
14import os
15
16def getRunLBFromU64(runlb):
17 run = runlb >> 32
18 lb = runlb & ((1<<32)-1)
19 return ( int(run), int(lb) )
20
21
23 """
24 returns all runs in the given period which have the ReadyForPhysics flag set in at least 1 LB
25 """
26
27 log.info("Loading COOL libs...")
28 from CoolLumiUtilities.CoolDataReader import CoolDataReader
29 log.info("Done loading libs, starting now ...")
30
31 myReader = CoolDataReader('COOLONL_TDAQ/CONDBR2', '/TDAQ/RunCtrl/DataTakingMode')
32 runsWithReady = {}
33
34 firstRun = min([x for x in period.keys()])
35 lastRun = max([x for x in period.keys()])+1
36 since = (firstRun << 32)
37 until = (lastRun << 32)
38
39 myReader.setIOVRange( since, until )
40 myReader.readData()
41
42 for obj in myReader.data:
43 isReady = (obj.payload()['ReadyForPhysics'] == 1)
44 if not isReady:
45 continue
46 sincerun, sincelb = getRunLBFromU64(obj.since())
47 untilrun, untillb = getRunLBFromU64(obj.until())
48 if sincerun != untilrun:
49 log.info("WARNING: ready block crosses run boundaries: %d %d", sincerun, untilrun)
50 if sincerun not in period: continue
51 if sincerun in runsWithReady:
52 runsWithReady[sincerun] += [ (sincelb, untillb) ]
53 else:
54 runsWithReady[sincerun] = [ (sincelb, untillb) ]
55
56
57 return runsWithReady
58
59
60def getKeys( listOfRuns, doPrint = False ):
61
62 from CoolLumiUtilities.CoolDataReader import CoolDataReader
63
64 keysByRun = {}
65
66 mySmkReader = CoolDataReader('COOLONL_TRIGGER/CONDBR2', '/TRIGGER/HLT/HltConfigKeys')
67 myL1pskReader = CoolDataReader('COOLONL_TRIGGER/CONDBR2', '/TRIGGER/LVL1/Lvl1ConfigKey')
68 myHltpskReader = CoolDataReader('COOLONL_TRIGGER/CONDBR2', '/TRIGGER/HLT/PrescaleKey')
69 #myBgskReader = CoolDataReader('COOLONL_TRIGGER/CONDBR2', '/TRIGGER/LVL1/BunchGroupKey')
70
71 import tqdm
72 pbar = tqdm.tqdm(sorted(listOfRuns),unit=" runs",bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}')
73 for run in pbar:
74
75 listOfReadyBlocks = listOfRuns[run]
76
77 pbar.set_description(f"Getting keys for run {run}")
78
79 since = (run << 32)
80 until = ((run+1) << 32)
81
82 # super master key
83 mySmkReader.setIOVRange( since, until - 1 )
84 mySmkReader.readData()
85 for obj in mySmkReader.data:
86 smk = obj.payload()['MasterConfigurationKey']
87 sincerun, sincelb = getRunLBFromU64(obj.since())
88 untilrun, untillb = getRunLBFromU64(obj.until())
89 keysByRun.setdefault(run,{})['smk'] = smk
90
91 for sincelb, untillb in listOfReadyBlocks:
92
93 since = (run << 32) + sincelb
94 until = (run << 32) + untillb
95
96 # l1 prescale keys
97 myL1pskReader.setIOVRange( since, until )
98 myL1pskReader.readData()
99 for obj in myL1pskReader.data:
100 l1psk = obj.payload()['Lvl1PrescaleConfigurationKey']
101 sincerun2, sincelb2 = getRunLBFromU64(obj.since())
102 untilrun2, untillb2 = getRunLBFromU64(obj.until())
103 if sincelb2 == untillb: break
104 keysByRun.setdefault(run,{}).setdefault('l1psk',[]).append((l1psk,sincerun2, sincelb2,untilrun2, untillb2-1)) #use same convention as GRL, last lb is included
105
106 # hlt prescale keys
107 myHltpskReader.setIOVRange( since, until )
108 myHltpskReader.readData()
109 for obj in myHltpskReader.data:
110 hltpsk = obj.payload()['HltPrescaleKey']
111 sincerun2, sincelb2 = getRunLBFromU64(obj.since())
112 untilrun2, untillb2 = getRunLBFromU64(obj.until())
113 if sincelb2 == untillb: break
114 keysByRun.setdefault(run,{}).setdefault('hltpsk',[]).append((hltpsk,sincerun2, sincelb2,untilrun2, untillb2-1)) #use same convention as GRL, last lb is included
115
116
124
125 if doPrint:
126 log.info(keysByRun)
127
128 return keysByRun
129
130def getHLTPrescalesRun2(connection,psk):
131 """returns set name, prescale and passthrough
132 values for a given HLT prescale key
133 @connection - connection string, e.g. TRIGGERDB
134 @psk - HLT prescale key
135 @return (ps name, [('L2/EF',chainId,prescale,pass-through),...])
136 """
137
138 res = queryHLTPrescaleTableRun2(connection,psk)
139 prescales = {r[0]:r[3] for r in res if r and r[1]=='Prescale'}
140 rerun = {r[0]:r[3] for r in res if r and r[1]=='ReRun'}
141 for x in prescales:
142 if x not in rerun: rerun[x] = False
143 return {x: (prescales[x],rerun[x]) for x in prescales}
144
145def queryHLTPrescaleTableRun2(connection,psk):
146
147 from TrigConfigSvc.TrigConfigSvcUtils import getTriggerDBCursor, executeQuery
148
149 global cursor, schemaname
150 cursor,schemaname = getTriggerDBCursor(connection)
151
152 output = [ "PS.HPR_CHAIN_COUNTER", "PS.HPR_TYPE", "PS.HPR_CONDITION" , "PS.HPR_VALUE"]
153
154 tables = {}
155 tables['PS'] = 'HLT_PRESCALE'
156
157 condition = [ "PS.HPR_PRESCALE_SET_ID = :psk" ]
158
159 bindvars = { "psk": psk }
160
161 res = executeQuery(cursor, output, condition, schemaname, tables, bindvars)
162
163 return res
164
165
166def fillHLTmap( info, hltMap_prev , lbCount, run, grlblocks):
167 from TrigConfigSvc.TrigConfigSvcUtils import getL1Items, getL1Prescales
168
169 from TrigConfIO.L1TriggerConfigAccess import L1MenuAccess,L1PrescalesSetAccess # run3 menu access
170 from TrigConfIO.HLTTriggerConfigAccess import HLTMenuAccess,HLTPrescalesSetAccess # run3 menu access
171
172 from collections import defaultdict
173
174 # for run2 or earlier, need to quieten output of TrigConfigSvcUtils
175 tcsLogger = logging.getLogger("TrigConfigSvcUtils.py")
176 tcsLogLevel = tcsLogger.level
177 tcsLogger.setLevel(logging.ERROR)
178
179 lvl = int(logging.root.level)
180 logging.root.setLevel(logging.WARNING)
181
182 # obtain map l1 item name => CTP ID
183 # obtain map hltid => (hltname, l1seed)
184 if run > 400000:
185 items = {}; chainsHLT = {}
186 for name,value in L1MenuAccess(dbalias = 'TRIGGERDB_RUN3', smkey = info['smk']).items().items():
187 items[name] = value["ctpid"]
188 for name,value in HLTMenuAccess(dbalias = 'TRIGGERDB_RUN3', smkey = info['smk']).chains().items():
189 if "L1" not in value["l1item"]: continue # filtering
190 chainsHLT[value["nameHash"]] = (name,value["l1item"])
191 else:
192 items = getL1Items('oracle://ATLAS_CONFIG/ATLAS_CONF_TRIGGER_RUN2', info['smk'])
193 chainsHLT = getChainsWithL1seed('oracle://ATLAS_CONFIG/ATLAS_CONF_TRIGGER_RUN2', info['smk']) # returns map HLT ID => (HLT name, L1 seed)
194 chainsHLT = {k:v for (k,v) in chainsHLT.items() if "L1" in v[1]} # filtering
195
196
197
198 tmphltList = []
199 for lbrange in info['hltpsk']:
200 lbstart, lbend = lbrange[2], lbrange[4]
201 if lbend ==-1: lbend = 2000
202 if run > 400000:
203 hltprescales = {}
204 for name,value in HLTPrescalesSetAccess(dbalias='TRIGGERDB_RUN3',hltpskey=lbrange[0]).prescales().items():
205 rerun=-1.0 # how to determine?
206 # key seems to be a float (from looking at type(list(getHLTPrescalesRun2("TRIGGERDB",3000).keys())[0]))
207 # ATR-30554: There is at least one instance in smk:3393 hltpsk:11710 where the prescale is string encoded
208 hltprescales[value["hash"]] = (float(value["prescale"]),rerun)
209 else:
210 hltprescales = getHLTPrescalesRun2('oracle://ATLAS_CONFIG/ATLAS_CONF_TRIGGER_RUN2', lbrange[0])
211 tmphltList.append(( lbstart, lbend,hltprescales) )
212
213 tmpl1List = []
214 for lbrange in info['l1psk']:
215 lbstart, lbend = lbrange[2], lbrange[4]
216 if lbend ==-1: lbend = 2000
217 if run > 400000:
218 l1ps = L1PrescalesSetAccess(dbalias='TRIGGERDB_RUN3',l1pskey=lbrange[0])
219 l1prescales = {name: l1ps.prescale(name) for name in l1ps.itemNames()}
220 else:
221 l1psname, l1prescales = getL1Prescales('oracle://ATLAS_CONFIG/ATLAS_CONF_TRIGGER_RUN2', lbrange[0])
222 l1prescales = list(l1prescales)
223 l1prescales = {l1name: l1prescales[int(l1id)] for (l1name, l1id) in items.items()}
224 tmpl1List.append(( lbstart, lbend,l1prescales) )
225
226 logging.root.setLevel(lvl)
227 tcsLogger.setLevel(tcsLogLevel)
228
229 #merge the lb ranges of HLT and L1
230 hltindex, l1index = 0,0
231 mergedList = []
232 while hltindex < len(tmphltList) and l1index < len(tmpl1List) :
233 if tmphltList[hltindex][1] == tmpl1List[l1index][1]:
234 lbstart, lbend = max(tmphltList[hltindex][0],tmpl1List[l1index][0]), tmphltList[hltindex][1]
235 mergedList.append((lbstart, lbend,tmphltList[hltindex][2],tmpl1List[l1index][2]))
236 hltindex += 1
237 l1index += 1
238 elif tmphltList[hltindex][1] > tmpl1List[l1index][1]:
239 lbstart, lbend = max(tmphltList[hltindex][0],tmpl1List[l1index][0]), tmpl1List[l1index][1]
240 mergedList.append((lbstart, lbend,tmphltList[hltindex][2],tmpl1List[l1index][2]))
241 l1index += 1
242 else:
243 lbstart, lbend = max(tmphltList[hltindex][0],tmpl1List[l1index][0]), tmphltList[hltindex][1]
244 mergedList.append((lbstart, lbend,tmphltList[hltindex][2],tmpl1List[l1index][2]))
245 hltindex += 1
246
247 # if user does a "touch liveFractions.txt" then we will populate info to that file for further debugging
248 f = open("liveFractions.txt","a") if os.path.exists("liveFractions.txt") else None
249
250 hltMap = {}
251 for lbstart, lbend, hltprescales, l1prescales in mergedList:
252 if run in LBexceptions.exceptions:
253 if any([lbstart>=exc_start and lbstart<=exc_end for exc_start, exc_end in LBexceptions.exceptions[run]]): continue
254 if any([lbend>=exc_start and lbend<=exc_end for exc_start, exc_end in LBexceptions.exceptions[run]]): continue
255
256 for grllbstart,grllbend in grlblocks:
257 lboverlap = (min(lbend,grllbend) - max(lbstart,grllbstart))+1
258 if lboverlap <= 0: continue
259
260 lbCount += lboverlap
261 for hltid, (hltps, hltrerun) in hltprescales.items():
262 if hltid not in chainsHLT: continue
263 if hltps < 1: hltps = 1e99
264 l1seeds = chainsHLT[hltid][1]
265 l1ps = 1e99
266 for l1seed in l1seeds.split(","): #protect 'L1_MU20,L1_MU21'
267 if l1seed not in l1prescales and len(l1seeds) > 10: continue #Protection against buggy HLT_noalg_Standby
268 tmpl1ps = l1prescales[l1seed]
269 if tmpl1ps < 1: tmpl1ps = 1e99
270 l1ps = min(l1ps, tmpl1ps)
271
272
273 if hltps*l1ps < 1e99: efflb = lboverlap/(hltps*l1ps)
274 else: efflb = 0
275 if not chainsHLT[hltid][0] in hltMap: hltMap[chainsHLT[hltid][0]] = [l1seeds, 0, hltrerun>0, defaultdict(int)]
276 hltMap[chainsHLT[hltid][0]][1] += efflb
277 hltMap[chainsHLT[hltid][0]][3][run] += efflb
278 if f: f.write(f"{chainsHLT[hltid][0]},{run},{lbstart},{lbend},{grllbstart},{grllbend},{lboverlap},{l1ps},{hltps}\n")
279
280 if f: f.close()
281
282 for hlt,(l1,efflb,rerun,efflbByRun) in hltMap_prev.items():
283 if hlt in hltMap:
284 hltMap[hlt][1] += efflb
285 hltMap[hlt][2] |= rerun
286 for run,runefflb in efflbByRun.items():
287 hltMap[hlt][3][run] += runefflb
288 else: hltMap[hlt] = [l1, efflb,rerun, efflbByRun]
289 return hltMap, lbCount
290
291
292def getChainsWithL1seed(connection, smk):
293 '''copy of getChains but retrieving also the L1 seed and assuming always run2
294 https://gitlab.cern.ch/atlas/athena/blob/master/Trigger/TrigConfiguration/TrigConfigSvc/python/TrigConfigSvcUtils.py#L611
295 '''
296 from TrigConfigSvc.TrigConfigSvcUtils import getTriggerDBCursor, executeQuery
297 cursor,schemaname = getTriggerDBCursor(connection)
298
299 output = ['TC.HTC_ID', 'TC.HTC_CHAIN_COUNTER', 'TC.HTC_NAME', 'TC.HTC_LOWER_CHAIN_NAME']
300 tables = {}
301 tables['SM'] = 'SUPER_MASTER_TABLE'
302 tables['M2C'] = 'HLT_TM_TO_TC'
303 tables['TC'] = 'HLT_TRIGGER_CHAIN'
304 tables['MT'] = 'HLT_MASTER_TABLE'
305
306 condition = [ "SM.SMT_ID = :smk",
307 'SM.SMT_HLT_MASTER_TABLE_ID = MT.HMT_ID',
308 'MT.HMT_TRIGGER_MENU_ID = M2C.HTM2TC_TRIGGER_MENU_ID',
309 'M2C.HTM2TC_TRIGGER_CHAIN_ID = TC.HTC_ID' ]
310
311 bindvars = { "smk": smk }
312
313 res = executeQuery(cursor, output, condition, schemaname, tables, bindvars)
314
315 chainsef = {}
316 for x in res:
317 if len(x)!=4: continue #protect against HLT_noalg_bkg_L1Bkg and similars
318 chainsef[x[1]] = (x[2],x[3])
319
320 return chainsef
321
322
323
324def getHLTmap_fromDB(period, customGRL):
325 ''' Return a map of HLT chain: (L1 seed, active LBs, is-rerun) for a given period
326 '''
327
328 triggerPeriod = TriggerPeriodData( period, customGRL ).grl
329 if not triggerPeriod: return {},0
330 runsWithReadyForPhysics = getReadyForPhysicsInRange(triggerPeriod)
331 keys = getKeys( runsWithReadyForPhysics)
332
333 hltMap = {}
334 lbCount = 0
335 lbByRun = {}
336 import tqdm
337 pbar = tqdm.tqdm(keys,unit=" runs",bar_format='{l_bar}{bar:10}{r_bar}{bar:-10b}')
338 for run in pbar:
339 pbar.set_description(f"Getting prescales for run {run}")
340 prev_lbCount = int(lbCount)
341 hltMap, lbCount = fillHLTmap( keys[run], hltMap, lbCount , run, triggerPeriod[run])
342 lbByRun[run] = (lbCount - prev_lbCount)
343
344 return hltMap, lbCount, lbByRun
345
346def getHLTmap_fromTM(flags, period, release):
347 ''' Return a map of HLT chain: (L1 seed, active LBs, is-rerun) for a given period
348 Only "Future" periods make sense here
349 The format is the same as for TriggerDBAccess for compatibility but rerun is always false
350 '''
351
352 if not period & TriggerPeriod.future: return {}, 0
353 hltMap = {}
354 dummyfutureLBs = 1e6
355
356 from TrigConfigSvc.TrigConfigSvcCfg import getTrigConfigFromFlag
357 if (flags.Input.Files and os.path.exists(flags.Input.Files[0]) and getTrigConfigFromFlag(flags)["SOURCE"]=='INFILE' and
358 (flags.Input.isMC or flags.Input.DataYear>=2022) ): # R2 data should not use this infile menu for now, to keep outputs the same as before this feature was added
359 # get menu out of the first input file
360 from TrigConfigSvc.TriggerConfigAccess import getHLTMenuAccess
361 try:
362 menu = getHLTMenuAccess(flags)
363 for hltname,chain in menu.chains().items():
364 l1seed = chain["l1item"]
365 if l1seed == "": l1seed = "All"
366 primary = any('Primary' in g or 'TagAndProbe' in g for g in chain["groups"])
367 ps = 1 if primary else 0
368 hltMap[hltname] = (l1seed, dummyfutureLBs*ps, False, {}) #third arg is hasRerun=False
369 except RuntimeError:
370 log.info("Failed to read infile menu, which can happen with old MC, reverting to release menu")
371
372 if not hltMap:
373 # use the generated menus from the release, and pick the menu given according to the flags (Trigger.triggerMenuSetup)
374 from TriggerMenuMT.HLT.Config.GenerateMenuMT import GenerateMenuMT
375 menu = GenerateMenuMT()
376 menu.getChainsFromMenu(flags)
377 for chain in itertools.chain.from_iterable(menu.chainsInMenu.values()):
378 hltname = chain.name
379 l1seed = chain.name[chain.name.rfind("_L1")+3:] #surely a better way to do this
380 primary = any('Primary' in g or 'TagAndProbe' in g for g in chain.groups)
381 ps = 1 if primary else 0
382 hltMap[hltname] = (l1seed, dummyfutureLBs*ps, False, {}) #third arg is hasRerun=False
383
384 return hltMap, dummyfutureLBs, {}
385
387 if release: #already format-proofed in TriggerAPI
388 return "/cvmfs/atlas.cern.ch/repo/sw/software/21.1/AthenaP1/%s/InstallArea/x86_64-slc6-gcc62-opt/python/TriggerMenu/menu"%release
389 #21.1.50 contains the final menu, no need to find the last release
390 return "/cvmfs/atlas.cern.ch/repo/sw/software/21.1/AthenaP1/21.1.50/InstallArea/x86_64-slc6-gcc62-opt/python/TriggerMenu/menu"
391
392
393def getHLTlist(period, customGRL, release, flags=None):
394 ''' For a given period it returns: [HLT chain, L1 seed, average livefraction, active LB, is-rerun], total LB
395 The average livefraction is an approximation weighting the PS by number of lumiblocks.
396 *** Don't use this number in analysis!!! ***
397 For "future" periods, the average livefraction is 1 for items flagged as primary in TM and 0 for non-primaries
398 '''
399 if not period & TriggerPeriod.future or TriggerPeriod.isRunNumber(period):
400 hltmap, totalLB, totalLBByRun = getHLTmap_fromDB(period, customGRL)
401 # # add empty chainGroups list to every item
402 # for name,vals in hltmap.items():
403 # hltmap[name] = vals + [[],]
404 else:
405 if flags is None:
406 raise RuntimeError('ConfigFlags need to be provided via TriggerAPI.setConfigFlags for "future" periods.')
407 hltmap, totalLB, totalLBByRun = getHLTmap_fromTM(flags, period, release)
408
409 hltlist = cleanHLTmap(hltmap, totalLB)
410 return (hltlist, totalLB, totalLBByRun)
411
412def cleanHLTmap(hltmap, totalLB):
413
414 from copy import deepcopy
415 for name, (l1seed, activeLB, hasRerun,activLBByRun) in deepcopy(hltmap).items(): #since it will modify on the fly
416 for pair in TriggerRenaming.pairs:
417 if name==pair[0] and pair[1] in hltmap:
418 hltmap[pair[1]][1] += activeLB
419 for run,efflb in activLBByRun.items(): hltmap[pair[1]][3][run] += efflb
420 #if name==pair[0] and not pair[1] in hltmap: hltmap[pair[1]] = [l1seed, activeLB, hasRerun]
421 if name==pair[1] and pair[0] in hltmap:
422 hltmap[pair[0]][1] += activeLB
423 for run,efflb in activLBByRun.items(): hltmap[pair[0]][3][run] += efflb
424 #if name==pair[1] and not pair[0] in hltmap: hltmap[pair[0]] = [l1seed, activeLB, hasRerun]
425
426 vetoes = ['calib','noise','noalg','satmon','peb']
427 hltlist = [(name, l1seed, activeLB/totalLB, activeLB, hasRerun,activLBByRun) for name, (l1seed, activeLB, hasRerun,activLBByRun) in hltmap.items() if not any(v in name for v in vetoes)]
428 return hltlist
429
430def test():
431 log.info(getHLTlist(TriggerPeriod.future,None, None))
432
433if __name__ == "__main__":
434 sys.exit(test())
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
fillHLTmap(info, hltMap_prev, lbCount, run, grlblocks)
getKeys(listOfRuns, doPrint=False)
getHLTlist(period, customGRL, release, flags=None)
getHLTmap_fromTM(flags, period, release)