ATLAS Offline Software
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 """
5 Dumps the trigger menu, optionally running some checks for name
6 consistency.
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 
17 import sys
18 from AthenaCommon.Logging import logging
19 
20 # hack to turn off logging on imports
21 logging.INFO = logging.DEBUG
22 
23 from TriggerMenuMT.HLT.Config.Utility.DictFromChainName import dictFromChainName
24 
25 import importlib
26 
27 MENU_ALIASES = {
28  'dev': 'Dev_pp_run3_v1',
29  'hi': 'PhysicsP1_HI_run3_v1',
30  'mc': 'MC_pp_run3_v1'
31 }
32 
33 def 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 
70 def 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  flags.Trigger.triggerConfig='FILE'
86  flags.Input.Files=[]
87  flags.Trigger.triggerMenuSetup=menu_name
88  flags.lock()
89 
90  if args.parse_names:
91  from TrigConfigSvc.TrigConfigSvcCfg import generateL1Menu
92  generateL1Menu(flags)
93 
94  # Import menu by name
95  menumodule = importlib.import_module(f'TriggerMenuMT.HLT.Menu.{menu_name}')
96  menu = menumodule.setupMenu(menu_name)
97 
98  # filter chains
99  if args.stream:
100  def filt(chain):
101  return args.stream in chain.stream
102  else:
103  def filt(x):
104  return True
105 
106  if args.group:
107  groupstr = args.group
108  def filt(x, old=filt):
109  if not old(x):
110  return False
111  for group in x.groups:
112  if group.startswith(groupstr):
113  return True
114  return False
115 
116  chains = chain_iter(menu, filt)
117  if args.names:
118  dump_chains(chains)
119  elif args.parse_names:
120  chain_to_dict, failed = get_chain_dicts(flags, chains)
121  if failed:
122  sys.exit(1)
123  if args.check_l1:
124  l1items = get_l1_list(args.menu)
125  missingl1 = set()
126  for chain, chain_dict in chain_to_dict.items():
127  if not chain_dict['L1item']: # Exception for L1All
128  continue
129  # Handle comma-separated list for multiseed
130  this_l1items = chain_dict['L1item'].split(',')
131  for this_l1 in this_l1items:
132  if this_l1 not in l1items:
133  sys.stderr.write(f'L1 item not in menu for HLT item {chain}\n')
134  missingl1.add(chain)
135  break
136  if missingl1:
137  sys.exit(1)
138 
139  if args.check_CPS:
140  # Need to regenerate this because we already iterated through
141  chains = chain_iter(menu, filt)
142  def match_group(expr,chain):
143  for group in chain.groups:
144  if expr in group:
145  return True
146  return False
147 
148  cps_to_chains = {}
149  L1_to_chains = {}
150 
151  for chain in chains:
152  chain_dict = chain_to_dict[chain.name]
153  if (
154  not chain_dict['L1item'] # Exception for L1All
155  or not match_group('Support',chain)
156  or match_group('TagAndProbe',chain)
157  ):
158  continue
159 
160  # Increment the number of support chains seeded by this L1
161  # Ignore multiseed
162  if len(chain_dict['L1item'].split(',')) == 1:
163  if chain_dict['L1item'] not in L1_to_chains:
164  L1_to_chains[chain_dict['L1item']] = set()
165  L1_to_chains[chain_dict['L1item']].add(chain.name)
166 
167  if match_group('RATE:CPS',chain):
168  cps_item = None
169  for group in chain.groups:
170  if group.startswith('RATE:CPS_'):
171  cps_item = 'L1_'+group[9:]
172  if cps_item == 'L1_ZB':
173  cps_item = 'L1_ZeroBias'
174  if cps_item not in cps_to_chains:
175  cps_to_chains[cps_item] = set()
176  cps_to_chains[cps_item].add(chain.name)
177 
178  for cps_item, cps_chains in cps_to_chains.items():
179  L1_chains = L1_to_chains[cps_item]
180  if len(L1_chains) < len(cps_chains):
181  raise RuntimeError('More CPS chains than L1-seeded, something wrong in parsing')
182  if len(cps_chains) < len(L1_chains):
183  print(f'CPS group seeded by {cps_item} does not include all support chains')
184  print(f' Contains {len(cps_chains)} / {len(L1_chains)}')
185  print(' Missing:')
186  for missing in L1_chains.difference(cps_chains):
187  print(' ', missing)
188 
189  if args.dump_dicts:
190  dump_chain_dicts(chain_to_dict,args.menu)
191 
192 def chain_iter(menu, filt=lambda x: True):
193  for group, chains in menu.items():
194  for chain in chains:
195  if filt(chain):
196  yield chain
197 
198 def dump_chains(chains):
199  try:
200  for chain in chains:
201  sys.stdout.write(f'{chain.name}\n')
202  except BrokenPipeError:
203  # this might happen if e.g. you are piping the output
204  pass
205 
206 def get_l1_list(menu):
207  from TriggerMenuMT.L1.Menu import MenuMapping
208  l1menuname = MenuMapping.menuMap[menu][0]
209  l1module = importlib.import_module(f'TriggerMenuMT.L1.Menu.Menu_{l1menuname}')
210  l1module.defineMenu()
211  return set(l1module.L1MenuFlags.items())
212 
213 def get_chain_dicts(flags, chains):
214  """
215  returns map of chain names to dictionaries with a set of failed chains
216  """
217  # disable even more useless output
218  logging.WARNING = logging.DEBUG
219  passed = set()
220  known_failure = set()
221  new_failure = set()
222  chain_to_dict = {}
223  for chain in chains:
224  chain_dict = dictFromChainName(flags, chain)
225  name = chain_dict['chainName']
226  chain_to_dict[name] = chain_dict
227  passed.add(name)
228  sys.stdout.write(
229  f'Passed: {len(passed)}, Known failures: {len(known_failure)}\n')
230 
231  return chain_to_dict, new_failure
232 
233 def dump_chain_dicts(chain_to_dict,menu):
234  import json
235  fname = f'dictdump_{menu}.json'
236  sys.stdout.write(f'Dumping chain dicts to file "{fname}"')
237  fdict = open(fname,'w')
238  json.dump(chain_to_dict,fdict,indent=2)
239  fdict.close()
240 
241 if __name__ == '__main__':
242  run()
243  sys.exit(0)
test_menu_dump.dump_chain_dicts
def dump_chain_dicts(chain_to_dict, menu)
Definition: test_menu_dump.py:233
test_menu_dump.get_parser
def get_parser(flags)
Definition: test_menu_dump.py:33
test_menu_dump.get_l1_list
def get_l1_list(menu)
Definition: test_menu_dump.py:206
python.TrigConfigSvcCfg.generateL1Menu
def generateL1Menu(flags)
Definition: TrigConfigSvcCfg.py:184
test_menu_dump.run
def run()
Definition: test_menu_dump.py:70
test_menu_dump.chain_iter
def chain_iter(menu, filt=lambda x:True)
Definition: test_menu_dump.py:192
DictFromChainName.dictFromChainName
def dictFromChainName(flags, chainInfo)
Definition: DictFromChainName.py:626
add
bool add(const std::string &hname, TKey *tobj)
Definition: fastadd.cxx:55
run
Definition: run.py:1
test_menu_dump.get_chain_dicts
def get_chain_dicts(flags, chains)
Definition: test_menu_dump.py:213
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:224
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
test_menu_dump.dump_chains
def dump_chains(chains)
Definition: test_menu_dump.py:198
Trk::open
@ open
Definition: BinningType.h:40
CSV_InDetExporter.old
old
Definition: CSV_InDetExporter.py:145
python.AllConfigFlags.initConfigFlags
def initConfigFlags()
Definition: AllConfigFlags.py:19
Muon::print
std::string print(const MuPatSegment &)
Definition: MuonTrackSteering.cxx:28
Trk::split
@ split
Definition: LayerMaterialProperties.h:38