4 __author__ =
'Will Buttinger'
5 __version__=
"$Revision: 1.0 $"
6 __doc__=
"Provides a helper class for managing a session of interactions with the TriggerAPI singleton"
8 from TriggerMenuMT.TriggerAPI
import SerializeAPI
9 from TriggerMenuMT.TriggerAPI.TriggerAPI
import TriggerAPI
10 from TriggerMenuMT.TriggerAPI.TriggerEnums
import TriggerPeriod,TriggerType
11 from AthenaCommon.Logging
import logging
12 log = logging.getLogger(__name__)
16 --------------------------------------------------------------------------------------------------------------------
17 TriggerAPI helper class. Use the following import in your code:
19 from TriggerMenuMT.TriggerAPI import TriggerAPISession,TriggerType,TriggerPeriod
24 Set of triggers of a given type that are unprescaled for an entire GRL:
26 s = TriggerAPISession("path/to/grl.xml") # can be a PathResolver path as well
27 triggers = s.getLowestUnprescaled(triggerType=TriggerType.el_single)
29 Dictionary of sets of triggers of a given type that are unprescaled, for each run in the GRL:
31 s = TriggerAPISession("path/to/grl.xml")
32 triggersByRun = s.getLowestUnprescaledByRun(triggerType=TriggerType.el_single)
34 Set of triggers that are unprescaled for all runs between two run numbers (inclusive), in a GRL:
36 s = TriggerAPISession("path/to/grl.xml")
37 triggers = s.getLowestUnprescaledByRun(triggerType=TriggerType.el_single,runStart=123456,runEnd=234567)
39 Other helpful methods are:
41 - Set of runs present in the session's GRL: s.runs()
42 - List of trigger types: [x.name for x in TriggerType]
43 - Dictionary of livefractions between given runs, key = trigger chain name:
44 liveFractions = s.getLiveFractions(triggerType=TriggerType.el_single,runStart=123456,runEnd=234567)
45 - Dictionary of chains (key is chain.name): s.chains()
46 - Set of triggers that are deemed to be of same type and lower threshold than a given trigger and unprescaled:
47 triggers = s.getLowerPrescaled(chainName="myChain")
49 Each method accepts an "additionalTriggerType" parameter that is used for multi-leg triggers of different type
52 Instead of passing a GRL you can pass a menu name ("menu_name") in the constructor, and the unprescaled
53 triggers will be the Primary|TagAndProbe triggers from the menu.
58 Sessions can be saved to json file and reloaded at a later time (to save requerying the database):
61 s2 = TriggerAPISession(json="myDump.json") # reloads the session
63 --------------------------------------------------------------------------------------------------------------------
67 def __init__(self, input=None, *, grl=None, flags=None, json=None, menu=None, file=None, period=None):
69 Specify one and only one of the following parameters to construct your API session:
71 :param input: If specified, will try to auto-infer which of the things below it is:
73 :param grl: Path to a GRL file, locatable by PathResolver
74 :param flags: flag container, used if reading triggers from the trigger menu (in the file or the release) - EXPERT OPTION
75 :param json: Path to a JSON file, locatable by PathResolver, containing a cache of TriggerAPI session
76 :param menu: Specify a menu to use, such as "Physics_pp_run3_v1". This is otherwise taken from flags
77 :param file: Specify a root file (AOD etc) from which the menu will be taken
78 :param period: Legacy option, can specify a TriggerPeriod and will load through the hardcoded GRLs (TriggerPeriodData)
85 if input.endswith(
".xml"):
86 log.info(
"Loading session for GRL:" + input)
88 elif input.endswith(
".json"):
89 log.info(
"Loading saved session from:" + input)
91 elif os.path.exists(input):
92 log.info(
"Loading session with menu from file:" + input)
95 log.info(
"Loading session for menu:" + input)
98 raise RuntimeError(
"Unsupported input type:" +
type(input).__name__)
110 elif grl
is not None:
111 from PathResolver
import PathResolver
114 elif flags
is not None:
116 elif menu
is not None:
117 from AthenaConfiguration.AllConfigFlags
import initConfigFlags
119 self.
flags.Trigger.triggerMenuSetup = menu
121 elif file
is not None:
122 from AthenaConfiguration.AllConfigFlags
import initConfigFlags
124 self.
flags.Input.Files = [file]
126 elif period
is not None:
128 TriggerAPI._loadTriggerPeriod(period,reparse=
False)
129 if not TriggerAPI.dbQueries:
130 raise RuntimeError(
"Failed to load TriggerAPI information for period")
132 self.
dbQueries = copy.deepcopy(TriggerAPI.dbQueries)
134 raise RuntimeError(
"Must specify one of: grl, flags, json, menu, period")
138 period = TriggerPeriod.future2e34
139 if self.
flags is not None:
140 TriggerAPI.setConfigFlags(self.
flags)
143 period = TriggerPeriod.customGRL
144 TriggerAPI._loadTriggerPeriod(period,reparse=
False)
145 if not TriggerAPI.dbQueries:
146 raise RuntimeError(
"Failed to load TriggerAPI information")
148 self.
dbQueries = copy.deepcopy(TriggerAPI.dbQueries)
160 :param path: Save a cache of the current session to the given json file
161 :return: result of json dump
163 return SerializeAPI.dump(self.
dbQueries,path)
166 def chains(self,*,triggerType=TriggerType.ALL):
168 :param triggerType: you can list available types with "[x.name for x in TriggerType]"
169 :return: dictionary of triggerChain objects of given types, key = chain Name
172 raise RuntimeError(
"Unsupported in multi-period TriggerAPI sessions (should only happen if using a period enum or an old json cache)")
174 if not isinstance(triggerType,list): triggerType = [triggerType,TriggerType.UNDEFINED]
175 if len(triggerType)==1: triggerType += [TriggerType.UNDEFINED]
176 elif len(triggerType) > 2:
177 raise RuntimeError(
"More than two trigger types not currently supported")
181 if not tc.passType(triggerType[0],triggerType[1]):
continue
190 :return: set of runs covered by this session
194 for tc
in ti.triggerChains:
195 for run
in tc.activeLBByRun.keys():
201 ti.setRunRange(start,end)
205 :param triggerType: list available types with "[x.name for x in TriggerType] .. provide a list of length 2 for multi-leg types"
206 :param livefraction: threshold to be considered unprescaled
209 :return: set of lowest unprescaled (according to livefraction) triggers of given type
213 if not isinstance(triggerType,list): triggerType = [triggerType,TriggerType.UNDEFINED]
214 if len(triggerType)==1: triggerType += [TriggerType.UNDEFINED]
215 elif len(triggerType) > 2:
216 raise RuntimeError(
"More than two trigger types not currently supported")
221 out.update(ti._getLowestUnprescaled(triggerType[0], triggerType[1],
"", livefraction))
224 if not out
and livefraction==1.0
and list(self.
dbQueries.
keys())[0][1]
and runStart!=runEnd:
225 log.warning(
"No triggers found that are fully unprescaled in your GRL ... checking for livefractions per run:")
228 liveFractions = self.
getLiveFractions(triggerType=triggerType,runStart=run,runEnd=run)
229 lf =
max(liveFractions.values())
230 if lf < 1
and lf > 0.9:
231 log.warning(f
"run {run} has maximum livefraction {lf} - prescaled LBs may have been included in your GRL accidentally. Please report this to Data Preparation")
233 log.info(f
"run {run} is unprescaled")
244 :return: lowest unprescaled trigger by run. If this session does not have per-run info, all triggers will be listed under a dummy key of ""
247 return {
"":self.
getLowestUnprescaled(triggerType=triggerType,livefraction=livefraction,runStart=runStart,runEnd=runEnd)}
250 pbar = tqdm.tqdm(self.
runs(),unit=
" runs",bar_format=
'{l_bar}{bar:10}{r_bar}{bar:-10b}')
252 pbar.set_description(f
"Determining lowest unprescaled for run {run}")
253 if int(run)<runStart
or int(run)>runEnd:
continue
254 out[run] = self.
getLowestUnprescaled(triggerType=triggerType,livefraction=livefraction,runStart=run,runEnd=run)
264 :param triggerType: can be a single type or a list of types
267 :return: a dictionary of live fractions for triggers matching given trigger types
272 out[x.name] = x.livefraction
276 def getLowerUnprescaled(self,*,chainName,triggerType=TriggerType.ALL,livefraction=1.0,runStart=0,runEnd=999999):
283 :return: set of chains of unprescaled triggers that were lower than the given chain
287 if chainName
not in chains:
288 raise RuntimeError(chainName +
" not found")
289 chain = chains[chainName]
293 if x.name==chain.name:
continue
294 if not x.isUnprescaled(livefraction):
continue
295 if x.isLowerThan(chain,period=self.
triggerInfo().period)==1: out.add(x)
300 if __name__ ==
"__main__":
303 class Formatter( argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
pass
305 parser = argparse.ArgumentParser(
307 description=
""" Example: tapis path/to/grl.xml getLowestUnprescaledByRun
309 See below for available commands. For help on a command, do: tapis dummy [command] --help""",
310 epilog=
'General command structure is: tapis [grl/menu/file/json] [command] [--commandOpt1] [--commandOpt2] ...',
311 formatter_class=Formatter)
313 parser.add_argument(
"--save",default=
None,help=
"If specified, the path to save the session to as a json file")
315 parser.add_argument(
"input",metavar=
"grl/menu/file/json",help=
"Either a GRL, a menu name, a pool file (with menu metadata), or a json session cache file. PathResolver paths supported")
316 subparsers = parser.add_subparsers(help=
"Available commands",dest=
"command",required=
True)
319 parser_getLowestUnprescaled = subparsers.add_parser(
'getLowestUnprescaled',help=
'Get lowest unprescaled chain names',
320 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
321 parser_getLowestUnprescaled.add_argument(
"--livefraction",type=float,default=1.0,help=
"EXPERT OPTION: lower the livefraction threshold for trigger to be considered unprescaled")
323 parser_chains = subparsers.add_parser(
'chains',help=
'Show info about a chain or selection of chains',
324 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
325 parser_chains.add_argument(
'chainName',type=str,help=
"name of chain or wildcarded string",default=
"*",nargs=
'?')
326 parser_chains.add_argument(
'--debug',action=
'store_true',help=
"Show additional information about each chain")
328 parser_runs = subparsers.add_parser(
'runs',help=
'List runs available in the session')
330 parser_getLowerUnprescaled = subparsers.add_parser(
'getLowerUnprescaled',help=
'Get chains that are deemed to be of same type but lower and also unprescaled compared to a given chain',
331 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
332 parser_getLowerUnprescaled.add_argument(
'chainName',type=str,help=
"name of chain")
333 parser_getLowerUnprescaled.add_argument(
"--livefraction",type=float,default=1.0,help=
"EXPERT OPTION: lower the livefraction threshold for trigger to be considered unprescaled")
335 parser_getLowerUnprescaledByRun = subparsers.add_parser(
'getLowestUnprescaledByRun',
336 help=
'Get lowest unprescaled chain names by run, results presented in terms of run ranges',
337 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
338 parser_getLowerUnprescaledByRun.add_argument(
"--livefraction",type=float,default=1.0,help=
"EXPERT OPTION: lower the livefraction threshold for trigger to be considered unprescaled")
341 for p
in [parser_getLowestUnprescaled,parser_chains,parser_runs,parser_getLowerUnprescaled,parser_getLowerUnprescaledByRun]:
342 p.add_argument(
"--triggerType",choices=[x.name
for x
in TriggerType],nargs=
'+',default=[
"ALL"],help=
"can specify up to two trigger types")
343 p.add_argument(
"--runStart",type=int,default=0,help=
"First runNumber to consider")
344 p.add_argument(
"--runEnd",type=int,default=999999,help=
"Last runNumber to consider")
348 args = parser.parse_args()
350 if args.command
is None: args.command =
"getLowestUnprescaled"
353 if args.save: s.save(args.save)
356 if "triggerType" in args:
357 args.triggerType = [TriggerType[t]
for t
in args.triggerType]
362 if args.command ==
"getLowestUnprescaled":
363 result = s.getLowestUnprescaled(triggerType=args.triggerType,
364 livefraction=args.livefraction,
365 runStart=args.runStart,runEnd=args.runEnd)
366 s.setRunRange(args.runStart,args.runEnd)
367 chains = s.chains(triggerType=args.triggerType)
368 result = [{
"name":chains[c].name,
"triggerType":TriggerType.toStr(chains[c].triggerType).
replace(
"|",
" "),
"livefraction":chains[c].livefraction}
for c
in result]
370 elif args.command ==
"getLowestUnprescaledByRun":
371 result = s.getLowestUnprescaledByRun(triggerType=args.triggerType,
372 livefraction=args.livefraction,
373 runStart=args.runStart,runEnd=args.runEnd)
378 chains = s.chains(triggerType=args.triggerType)
382 pbar = tqdm.tqdm(
sorted(result.keys()),unit=
" runs",bar_format=
'{l_bar}{bar:10}{r_bar}{bar:-10b}')
384 pbar.set_description(f
"Collating result for run {run}")
385 s.setRunRange(run,run)
387 result[run].
update([
"---"])
388 badRuns += [
str(run)]
389 for trig
in result[run]:
390 lf = chains[trig].livefraction
if trig !=
"---" else -1
391 if trig
not in runRanges:
392 runRanges[trig] = [[run,run,lf]]
393 elif runRanges[trig][-1][1] == prevRun
and runRanges[trig][-1][2]==lf:
394 runRanges[trig][-1][1] = run
396 runRanges[trig] += [[run,run,lf]]
400 for c,ranges
in runRanges.items():
401 for start,end,livefraction
in ranges:
403 result += [{
"runStart":start,
"runEnd":end,
"name":c,
"triggerType":TriggerType.toStr(chains[c].triggerType).
replace(
"|",
" ")
if c !=
"---" else "---",
404 "livefraction":livefraction
409 extraWarning =
"The following runs did not have a trigger of the requested type with livefraction >= " +
str(args.livefraction) +
": "
410 extraWarning +=
",".
join(badRuns)
411 if args.livefraction==1.0: extraWarning +=
". If this is unexpected please report the issue to Data Preparation"
413 elif args.command ==
"chains":
414 s.setRunRange(args.runStart,args.runEnd)
416 result = {k: v
for k,v
in s.chains(triggerType=args.triggerType).
items()
if fnmatch.fnmatch(k,args.chainName)}
418 result = [{
"name":c.name,
"legs":
str({l.legname:TriggerType.toStr(l.legtype)
for l
in c.legs}),
"triggerType":TriggerType.toStr(c.triggerType).
replace(
"|",
" "),
"livefraction":c.livefraction}
for c
in result.values()]
420 result = [{
"name":c.name,
"triggerType":TriggerType.toStr(c.triggerType).
replace(
"|",
" "),
"livefraction":c.livefraction}
for c
in result.values()]
422 elif args.command ==
"runs":
423 s.setRunRange(args.runStart,args.runEnd)
425 elif args.command ==
"getLowerUnprescaled":
426 result = s.getLowerUnprescaled(chainName=args.chainName,triggerType=args.triggerType,livefraction=args.livefraction,runStart=args.runStart,runEnd=args.runEnd)
427 result = [{
"name":c.name,
"triggerType":TriggerType.toStr(c.triggerType).
replace(
"|",
" "),
"livefraction":c.livefraction}
for c
in result]
432 df = pd.DataFrame(result)
if len(result)
else pd.DataFrame(columns=[
'name',
'triggerType',
'livefraction'])
433 if 'runStart' in df.columns:
435 dfStr = df.sort_values(by=[
'triggerType',
'name',
'runStart'],ascending=[
True,
True,
True]).
to_string(index=
False)
438 dfStr = df.sort_values(by=[
'triggerType',
'livefraction',
'name'],ascending=[
True,
False,
True]).
to_string(index=
False)
442 if result
is not None:
445 if extraWarning: log.warning(extraWarning)