ATLAS Offline Software
Loading...
Searching...
No Matches
test_menu_dump.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3
4"""
5Dumps the trigger menu, optionally running some checks for name
6consistency.
7"""
8# help strings
9_h_names = "print the names of all chains"
10_h_parse = "parse names to dictionary"
11_h_menu = "name of the menu to dump (default Physics_pp_run3_v1)"
12_h_l1check = "do check of L1 items vs L1 menu"
13_h_stream = "filter by stream"
14_h_dump_dicts = "dump dicts to json"
15_h_check_CPS = "verify that Support chains are in CPS"
16
17import sys
18from AthenaCommon.Logging import logging
19
20# hack to turn off logging on imports
21logging.INFO = logging.DEBUG
22
23from TriggerMenuMT.HLT.Config.Utility.DictFromChainName import dictFromChainName
24
25import importlib
26
27MENU_ALIASES = {
28 'dev': 'Dev_pp_run3_v1',
29 'hi': 'PhysicsP1_HI_run3_v1',
30 'mc': 'MC_pp_run3_v1'
31}
32
33def get_parser(flags):
34 aliases = '\n'.join(f'{a} -> {f}' for a, f in MENU_ALIASES.items())
35 epi='menu aliases:\n' + aliases
36 parser = flags.getArgumentParser(
37 description=__doc__, epilog=epi,
38 )
39 parser.add_argument('-m', '--menu',
40 default='Physics_pp_run3_v1',
41 help=_h_menu)
42 output = parser.add_mutually_exclusive_group()
43 output.add_argument('-n', '--names', action='store_true',
44 help=_h_names)
45 output.add_argument('-p', '--parse-names', action='store_true',
46 help=_h_parse)
47 parser.add_argument('-L', '--check-l1', action='store_true',
48 help=_h_l1check)
49 parser.add_argument('-C', '--check-CPS', action='store_true',
50 help=_h_check_CPS)
51 parser.add_argument('-s', '--stream', const='Main', nargs='?',
52 help=_h_stream)
53 parser.add_argument('-D', '--dump-dicts', action='store_true',
54 help=_h_dump_dicts)
55 group = parser.add_mutually_exclusive_group()
56 group.add_argument(
57 '--primary',
58 dest='group',
59 action='store_const',
60 const='Primary:',
61 )
62 group.add_argument(
63 '--support',
64 dest='group',
65 action='store_const',
66 const='Support:',
67 )
68 return parser
69
70def run():
71 # The Physics menu (at least) depends on a check of the menu name
72 # in order to decide if PS:Online chains should be retained.
73 # Should do this in a more explicit way
74 from AthenaConfiguration.AllConfigFlags import initConfigFlags
75 flags = initConfigFlags()
76 parser = get_parser(flags)
77
78 args = flags.fillFromArgs(parser=parser)
79 menu_name = MENU_ALIASES.get(args.menu, args.menu)
80
81 # Can't do these without parsing
82 if args.check_l1 or args.check_CPS or args.dump_dicts:
83 args.parse_names = True
84
85 from AthenaConfiguration.TestDefaults import defaultGeometryTags
86 if "run4" in args.menu:
87 flags.GeoModel.AtlasVersion = defaultGeometryTags.RUN4
88 else:
89 flags.GeoModel.AtlasVersion = defaultGeometryTags.RUN3
90
91 flags.Trigger.triggerConfig='FILE'
92 flags.Input.Files=[]
93 flags.Trigger.triggerMenuSetup=menu_name
94 flags.lock()
95
96 if args.parse_names:
97 from TrigConfigSvc.TrigConfigSvcCfg import generateL1Menu
98 generateL1Menu(flags)
99
100 # Import menu by name
101 menumodule = importlib.import_module(f'TriggerMenuMT.HLT.Menu.{menu_name}')
102 menu = menumodule.setupMenu()
103
104 # filter chains
105 if args.stream:
106 def filt(chain):
107 return args.stream in chain.stream
108 else:
109 def filt(x):
110 return True
111
112 if args.group:
113 groupstr = args.group
114 def filt(x, old=filt):
115 if not old(x):
116 return False
117 for group in x.groups:
118 if group.startswith(groupstr):
119 return True
120 return False
121
122 chains = chain_iter(menu, filt)
123 if args.names:
124 dump_chains(chains)
125 elif args.parse_names:
126 chain_to_dict, failed = get_chain_dicts(flags, chains)
127 if failed:
128 sys.exit(1)
129 if args.check_l1:
130 l1items = get_l1_list(args.menu)
131 missingl1 = set()
132 for chain, chain_dict in chain_to_dict.items():
133 if not chain_dict['L1item']: # Exception for L1All
134 continue
135 # Handle comma-separated list for multiseed
136 this_l1items = chain_dict['L1item'].split(',')
137 for this_l1 in this_l1items:
138 if this_l1 not in l1items:
139 sys.stderr.write(f'L1 item not in menu for HLT item {chain}\n')
140 missingl1.add(chain)
141 break
142 if missingl1:
143 sys.exit(1)
144
145 if args.check_CPS:
146 # Need to regenerate this because we already iterated through
147 chains = chain_iter(menu, filt)
148 def match_group(expr,chain):
149 for group in chain.groups:
150 if expr in group:
151 return True
152 return False
153
154 cps_to_chains = {}
155 L1_to_chains = {}
156
157 for chain in chains:
158 chain_dict = chain_to_dict[chain.name]
159 if (
160 not chain_dict['L1item'] # Exception for L1All
161 or not match_group('Support',chain)
162 or match_group('TagAndProbe',chain)
163 ):
164 continue
165
166 # Increment the number of support chains seeded by this L1
167 # Ignore multiseed
168 if len(chain_dict['L1item'].split(',')) == 1:
169 if chain_dict['L1item'] not in L1_to_chains:
170 L1_to_chains[chain_dict['L1item']] = set()
171 L1_to_chains[chain_dict['L1item']].add(chain.name)
172
173 if match_group('RATE:CPS',chain):
174 cps_item = None
175 for group in chain.groups:
176 if group.startswith('RATE:CPS_'):
177 cps_item = 'L1_'+group[9:]
178 if cps_item == 'L1_ZB':
179 cps_item = 'L1_ZeroBias'
180 if cps_item not in cps_to_chains:
181 cps_to_chains[cps_item] = set()
182 cps_to_chains[cps_item].add(chain.name)
183
184 for cps_item, cps_chains in cps_to_chains.items():
185 L1_chains = L1_to_chains[cps_item]
186 if len(L1_chains) < len(cps_chains):
187 raise RuntimeError('More CPS chains than L1-seeded, something wrong in parsing')
188 if len(cps_chains) < len(L1_chains):
189 print(f'CPS group seeded by {cps_item} does not include all support chains')
190 print(f' Contains {len(cps_chains)} / {len(L1_chains)}')
191 print(' Missing:')
192 for missing in L1_chains.difference(cps_chains):
193 print(' ', missing)
194
195 if args.dump_dicts:
196 dump_chain_dicts(chain_to_dict,args.menu)
197
198def chain_iter(menu, filt=lambda x: True):
199 for group, chains in menu.items():
200 for chain in chains:
201 if filt(chain):
202 yield chain
203
204def dump_chains(chains):
205 try:
206 for chain in chains:
207 sys.stdout.write(f'{chain.name}\n')
208 except BrokenPipeError:
209 # this might happen if e.g. you are piping the output
210 pass
211
212def get_l1_list(menu):
213 from TriggerMenuMT.L1.Menu import MenuMapping
214 l1menuname = MenuMapping.menuMap[menu][0]
215 l1module = importlib.import_module(f'TriggerMenuMT.L1.Menu.Menu_{l1menuname}')
216 l1module.defineMenu()
217 return set(l1module.L1MenuFlags.items())
218
219def get_chain_dicts(flags, chains):
220 """
221 returns map of chain names to dictionaries with a set of failed chains
222 """
223 # disable even more useless output
224 logging.WARNING = logging.DEBUG
225 passed = set()
226 known_failure = set()
227 new_failure = set()
228 chain_to_dict = {}
229 for chain in chains:
230 chain_dict = dictFromChainName(flags, chain)
231 name = chain_dict['chainName']
232 chain_to_dict[name] = chain_dict
233 passed.add(name)
234 sys.stdout.write(
235 f'Passed: {len(passed)}, Known failures: {len(known_failure)}\n')
236
237 return chain_to_dict, new_failure
238
239def dump_chain_dicts(chain_to_dict,menu):
240 import json
241 fname = f'dictdump_{menu}.json'
242 sys.stdout.write(f'Dumping chain dicts to file "{fname}"')
243 fdict = open(fname,'w')
244 json.dump(chain_to_dict,fdict,indent=2)
245 fdict.close()
246
247if __name__ == '__main__':
248 run()
249 sys.exit(0)
void print(char *figname, TCanvas *c1)
STL class.
bool add(const std::string &hname, TKey *tobj)
Definition fastadd.cxx:55
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
get_chain_dicts(flags, chains)
dump_chain_dicts(chain_to_dict, menu)
chain_iter(menu, filt=lambda x:True)