Loading [MathJax]/extensions/tex2jax.js
ATLAS Offline Software
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
GenerateMenuMT.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 from typing import Optional
4 import importlib, re, string
5 
6 from TriggerMenuMT.HLT.Config.Utility.HLTMenuConfig import HLTMenuConfig
7 
8 from AthenaCommon.Logging import logging
9 log = logging.getLogger(__name__)
10 
11 # _maxAllowedCustomCH: this variable keeps track of the number of custom ComboHypo that are named differently as expected from the ControlFlow rule (which sets one ComboHypo per step, both named the same). These violations are already investigated and allowed because the ComboHypos are able to handle the decisions internally. Any change of this parameter needs to be discussed with experts
12 _maxAllowedCustomCH = 10
13 
15  return ['Streaming','Monitor','Beamspot','Cosmic', 'Calib', 'EnhancedBias']
16 
18  return ['MinBias','Electron','Photon','Muon','Tau','Jet', 'Bjet','MET','UnconventionalTracking','HeavyIon']
19 
21  return ['Bjet', 'Egamma', 'Combined']
22 
24  return ['Streaming']
25 
27  return ['Test']
28 
30  return ['Bphysics']
31 
34 
35 
37  """Standard chain filter"""
38  def __init__(self, flags):
39  self.enabledSignatures = flags.Trigger.enabledSignatures if flags.hasFlag("Trigger.enabledSignatures") else []
40  self.disabledSignatures = flags.Trigger.disabledSignatures if flags.hasFlag("Trigger.disabledSignatures") else []
41  self.selectChains = flags.Trigger.selectChains if flags.hasFlag("Trigger.selectChains") else []
42  self.disableChains = flags.Trigger.disableChains if flags.hasFlag("Trigger.disableChains") else []
43 
44  def __call__(self, signame, chain):
45  return ((signame in self.enabledSignatures and signame not in self.disabledSignatures) and \
46  (not self.selectChains or chain in self.selectChains) and chain not in self.disableChains)
47 
48  def __str__(self) -> str:
49  return f'FilterChainsToGenerate(enabledSignatures={self.enabledSignatures}, disabledSignatures={self.disabledSignatures}, selectChains={self.selectChains}, disableChains={self.disableChains})'
50 
51 
52 class Singleton(type):
53  _instances = {}
54  def __call__(cls, *args, **kwargs):
55  if cls not in cls._instances:
56  cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
57  return cls._instances[cls]
58 
59  def clear(cls):
60  cls._instances.clear()
61 
62 
63 class GenerateMenuMT(metaclass=Singleton):
64  """Singleton class for the Trigger Menu"""
65  def __init__(self):
66  self.base_menu_name: str = ''
67 
68  self.chainsInMenu = {} # signature : [chains]
69 
71  self.chainDicts = []
74  self.configLengthDict = {}
75 
76  self.signaturesOverwritten = False
77  self.L1Prescales = None
78  self.HLTPrescales = None
79 
80  self.chainFilter = None
82 
83  self.sigDicts = {}
84 
85  self.chainDefModule = {} # Generate[SIG]ChainDefs module for each SIGnature
86 
87 
88  # Define which signatures (folders) are required for each slice
89  def getRequiredSignatures(theslice):
90  allSigs = allSignatures()
91  signatureDeps = {sig:[sig] for sig in allSigs}
92  # Special cases
93  signatureDeps.update({
94  # Bjet always requires jet
95  'Bjet': ['Bjet','Jet'],
96  # Egamma contains two signatures
97  'Egamma': ['Electron','Photon'],
98  'Combined': combinedSignatures(),
99  })
100  return set(signatureDeps[theslice]+defaultSignatures()) # always allow streamers
101 
102 
103  def setChainFilter(self, f):
104  """Set chain filter for menu generation.
105 
106  This can be any callable object taking two
107  arguments for signature and chain name and returning a boolean.
108  E.g. to only generate Egamma chains:
109  menu.setChainFilter(lambda slice,chain : slice=='Egamma').
110 
111  In the special case that f is a functor with the list attributes
112  selectChains and/or disableChains, the contents will be explicitly
113  checked to be in the menu.
114  """
115  fname = f.__class__.__name__ if isinstance(f,object) else f.__name__
116  import inspect
117  if len(inspect.signature(f).parameters)!=2:
118  log.error('%s is not a valid chain filter. Function/callable needs take two arguments '
119  'for signature and chain name and return a boolean', fname)
120  else:
121  log.info('Setting chain filter to: %s', f)
122  self.chainFilter = f
123 
124 
125  def getChainDicts(self, flags):
126 
127  def validSignature(currentSig, chainSig):
128  """Check if chain is assigned to the correct signature"""
129  reqd = GenerateMenuMT.getRequiredSignatures(currentSig)
130  isValid = chainSig.issubset( reqd )
131  log.debug("Chain signatures: %s, required signatures: %s",chainSig,reqd)
132  if not isValid:
133  log.error("Chain signatures %s not a subset of required signatures %s",set(chainSig),reqd)
134  return isValid
135 
136  from TriggerMenuMT.HLT.Config.Utility.DictFromChainName import dictFromChainName
137 
138  chainCounter = 0
139  invalid = False
140  for sig, chains in self.chainsInMenu.items():
141  for chain in chains:
142  log.debug("Now processing chain: %s from signature %s", chain, sig)
143  chainCounter += 1
144  chainDict = dictFromChainName(flags, chain)
145  chainDict['chainCounter'] = chainCounter
146  chainDict['prescale'] = 1 # set default chain prescale
147 
148  # Pick out the folder and subsignature directories to import
149  for sigfo, subsig in chainDict['sigDicts'].items():
150  if sigfo not in self.sigDicts:
151  self.sigDicts[sigfo] = subsig
152  else:
153  for ss in subsig:
154  if ss not in self.sigDicts[sigfo]:
155  self.sigDicts[sigfo].append(ss)
156 
157  self.chainDicts.append(chainDict)
158 
159  if not validSignature(sig, set(chainDict['signatures'])):
160  invalid=True
161  log.error('Chain %s assigned to signature %s but creates %s',
162  chainDict['chainName'], sig, set(chainDict['signatures']))
163  if invalid:
164  raise RuntimeError('Incorrect assignment of chains to slices -- see preceding messages.')
165 
167  """check if all the signature files can be imported and then import them"""
168 
169  for sig, subSigs in self.sigDicts.items():
170  try:
171  for ss in subSigs:
172  import_module = 'TriggerMenuMT.HLT.' + sig +'.Generate' + ss + 'ChainDefs'
173  self.chainDefModule[ss] = importlib.import_module(import_module)
174 
175  if ss not in self.availableSignatures:
176  self.availableSignatures.append(ss)
177 
178  except ImportError:
179  log.exception('Problems when importing ChainDef generating code for %s', sig)
180  import traceback
181  traceback.print_exc()
182 
183  log.info('Available signature(s) for chain generation: %s', self.availableSignatures)
184 
185  return
186 
187  def generateChains(self, flags):
188  all_chains = []
189  combinations_in_menu = []
190  alignmentGroups_to_align = set()
191  length_of_configs = {}
192 
193  nchainDicts = len(self.chainDicts)
194  notify_increment = max(int(nchainDicts / 10),1)
195  for ichainDict, chainDict in enumerate(self.chainDicts):
196  log.debug("Next: getting chain configuration for chain %s ", chainDict['chainName'])
197  if ichainDict % notify_increment==0:
198  log.info("Generating HLT chain %d / %d", ichainDict+1, nchainDicts)
199  chainConfig,lengthOfChainConfigs = self.__generateChainConfig(flags, chainDict)
200  all_chains += [(chainDict,chainConfig,lengthOfChainConfigs)]
201 
202  #update the alignment group length dictionary if we have a longer number of steps
203  #or the signature isn't registered in the dictionary yet
204  for config_length, config_grp in lengthOfChainConfigs:
205  if config_grp in length_of_configs:
206  if config_length > length_of_configs[config_grp]:
207  length_of_configs[config_grp] = config_length
208  else:
209  length_of_configs[config_grp] = config_length
210 
211  # find the chains that contain more than one alignment group, to keep track
212  # of what combinations do we need to deal with.
213  # we're using sets here so we don't end up with duplicates
214  if len(set(chainDict['alignmentGroups'])) > 1:
215  combinations_in_menu += [list(set(chainDict['alignmentGroups']))]
216  for align_group in list(set(chainDict['alignmentGroups'])):
217  alignmentGroups_to_align.update([align_group])
218 
219  self.allChainsForAlignment = all_chains
220  self.combinationsInMenu = combinations_in_menu
221  self.alignmentGroupsToAlign = alignmentGroups_to_align
222  self.configLengthDict = length_of_configs
223 
224  return
225 
226 
227  def generateAllChainConfigs(self, flags):
228  """
229  == Obtains chain configs for all chains in menu
230  """
231 
232  from TriggerMenuMT.HLT.Config.Utility.MenuAlignmentTools import MenuAlignment
233  from TriggerMenuMT.HLT.CommonSequences import EventBuildingSequences, TLABuildingSequences
234 
235  # get all chain names from menu
236  log.info("Will now get chains from the menu")
237  self.getChainsFromMenu(flags)
238 
239  # decoding of the chain name
240  log.info("Will now get chain dictionaries for each chain")
241  self.getChainDicts(flags)
242 
243  if flags.Trigger.disableCPS:
244  log.warning('Removing all CPS group because the flag Trigger.disableCPS is set')
245  for chainDict in self.chainDicts:
246  chainDict['groups'] = [g for g in chainDict['groups'] if not g.startswith('RATE:CPS_')]
247 
248  #import the necessary signatures
249  log.debug("Importing the necessary signatures")
251 
252  log.info("Will now generate the chain configuration for each chain")
253  self.generateChains(flags)
254 
255  log.info("Will now calculate the alignment parameters")
256  #dict of signature: set it belongs to
257  #e.g. {'Electron': ['Electron','Muon','Photon']}
258  menuAlignment = MenuAlignment(self.combinationsInMenu,
260  self.configLengthDict)
261  menuAlignment.analyse_combinations()
262 
263  # alignmentGroups_to_align = menuAlignment.groupsToAlign
264  # lengthOfChainConfigs = self.configLengthDict
265  # combinationsInMenu = menuAlignment.combinationsInMenu
266  # alignmentGroup_sets_to_align = menuAlignment.setsToAlign
267 
268  log.info('Aligning the following signatures: %s',sorted(menuAlignment.sets_to_align))
269  log.debug('Length of each of the alignment groups: %s',self.configLengthDict)
270 
271  chainConfigs = []
272 
273  for chainDict,chainConfig,lengthOfChainConfigs in self.allChainsForAlignment:
274 
275  # start by ordering electron, photon, muon by having e+mu, g+mu, e+g chains
276  # desired ordering: electron, photon, muon, tau, jet, met, b-jet
277 
278  # lengthOfChainConfigs is something like this: [(4, 'Photon'), (5, 'Muon')]
279  # needs to match up with the maximum number of steps in a signature in the menu (length_of_configs)
280  # start with electron! Only need to add post-steps for combined electron chains if the max length in a combined chain
281  # is greater than the number of electron steps combined chain. Assume that the max length of an electron chain occurs
282  # in a combined chain.
283 
284  log.debug("[generateAllChainConfigs] chain %s has config lengths %s and alignment groups %s", chainDict['chainName'], lengthOfChainConfigs, chainDict['alignmentGroups'])
285 
286  alignmentGroups = chainDict['alignmentGroups']
287 
288  #parallel-merged single-signature chains or single signature chains. Anything that needs no splitting!
289  if len(set(alignmentGroups)) == 1:
290  alignedChainConfig = menuAlignment.single_align(chainDict, chainConfig)
291  HLTMenuConfig.registerChain( chainDict )
292  chainConfigs.append( alignedChainConfig )
293 
294  elif len(alignmentGroups) >= 2:
295  alignedChainConfig = menuAlignment.multi_align(chainDict, chainConfig, lengthOfChainConfigs)
296  HLTMenuConfig.registerChain( chainDict )
297  chainConfigs.append( alignedChainConfig )
298 
299  else:
300  log.error("Menu can't deal with combined chains with more than two alignmentGroups at the moment. oops...")
301  raise NotImplementedError("more than three alignment groups still needs implementing in ChainMerging.py, ATR-22206")
302 
303  if not HLTMenuConfig.isChainRegistered(chainDict['chainName']):
304  log.error("Chain %s has not been registered in the menu!", chainDict['chainName'])
305  import pprint
306  pp = pprint.PrettyPrinter(indent=4, depth=8)
307  log.error('The chain dictionary is: %s', pp.pformat(chainDict))
308  raise Exception("Please fix the menu or the chain.")
309 
310  # align event building sequences
311  log.info("[generateAllChainConfigs] general alignment complete, will now align TLA chains")
312  TLABuildingSequences.alignTLASteps(chainConfigs, HLTMenuConfig.dicts())
313  log.info("[generateAllChainConfigs] general and TLA alignment complete, will now align PEB chains")
314  EventBuildingSequences.alignEventBuildingSteps(chainConfigs, HLTMenuConfig.dicts())
315 
316  log.info("[generateAllChainConfigs] all chain configurations have been generated.")
317  return chainConfigs
318 
319 
320  def getChainsFromMenu(self, flags):
321  """
322  == Returns the list of chain names that are in the menu
323  """
324 
325  self.base_menu_name = re.match(r'\w*_v\d*', flags.Trigger.triggerMenuSetup).group(0)
326  log.info(f'Menu name: {flags.Trigger.triggerMenuSetup}')
327  log.debug('Base menu name: %s', self.base_menu_name)
328 
329  # Generate the list of chains from the basic menu (terminated in a version number)
330  try:
331  menu_module = importlib.import_module(f'TriggerMenuMT.HLT.Menu.{self.base_menu_name}')
332  except Exception as e:
333  log.fatal(f'Failed to import menu module "{self.base_menu_name}" inferred from menu "{flags.Trigger.triggerMenuSetup}"')
334  raise e
335 
336  # Load Menu
337  self.chainsInMenu = menu_module.setupMenu()
338 
339  # Filter chains if requested
340  if self.chainFilter is not None:
341  self.signaturesOverwritten = True
342 
343  # Verify that if the chain filter has lists of chains
344  # they are all in the menu
345  chainsToCheck = []
346  if hasattr(self.chainFilter,'selectChains'):
347  chainsToCheck += self.chainFilter.selectChains
348  if hasattr(self.chainFilter,'disableChains'):
349  chainsToCheck += self.chainFilter.disableChains
350  for chain in chainsToCheck:
351  inMenu = False
352  for signame in self.chainsInMenu:
353  if chain in [c.name for c in self.chainsInMenu[signame]]:
354  inMenu = True
355  break
356  if not inMenu:
357  raise RuntimeError(f'Request to enable/disable chain {chain} that is not in menu')
358 
359  for signame in self.chainsInMenu:
360  self.chainsInMenu[signame] = [c for c in self.chainsInMenu[signame]
361  if self.chainFilter(signame, c.name)]
362 
363  if not self.chainsInMenu:
364  log.warning("There seem to be no chains in the menu - please check")
365  elif log.isEnabledFor(logging.DEBUG):
366  import pprint
367  log.debug("The following chains were found in the menu:")
368  pprint.pprint(self.chainsInMenu)
369 
370 
371  def __generateChainConfig(self, flags, mainChainDict):
372  """
373  # Assembles the chain configuration and returns a chain object with (name, L1see and list of ChainSteps)
374  """
375 
376  from TriggerMenuMT.HLT.Config.Utility.ChainDictTools import splitInterSignatureChainDict
377  from TriggerMenuMT.HLT.Config.Utility.ComboHypoHandling import addTopoInfo, comboConfigurator, topoLegIndices, anomdetWPIndices
378  from TriggerMenuMT.HLT.Config.Utility.ChainMerging import mergeChainDefs
379  from TriggerMenuMT.HLT.CommonSequences import EventBuildingSequences, TLABuildingSequences
380 
381  # split the the chainDictionaries for each chain and print them in a pretty way
382  chainDicts = splitInterSignatureChainDict(mainChainDict)
383 
384  if log.isEnabledFor(logging.DEBUG):
385  import pprint
386  pp = pprint.PrettyPrinter(indent=4, depth=8)
387  log.debug('dictionary is: %s', pp.pformat(chainDicts))
388 
389  # Loop over all chainDicts and send them off to their respective assembly code
390  listOfChainConfigs = []
391  perSig_lengthOfChainConfigs = []
392 
393  for chainPartDict in chainDicts:
394  chainPartConfig = None
395  currentSig = chainPartDict['signature']
396  currentAlignGroup = None
397  if len(chainPartDict['chainParts']) == 1:
398  currentAlignGroup = chainPartDict['chainParts'][0]['alignmentGroup']
399 
400  chainName = chainPartDict['chainName']
401  log.debug('Checking chainDict for chain %s in signature %s, alignment group %s' , chainName, currentSig, currentAlignGroup)
402 
403  if currentSig in self.availableSignatures:
404  try:
405  log.debug("[__generateChainConfigs] Trying to get chain config for %s", currentSig)
406  if currentSig in ['Electron', 'Photon', 'Muon', 'Tau', 'Bphysics'] :
407  chainPartConfig, perSig_lengthOfChainConfigs = self.chainDefModule[currentSig].generateChainConfigs(flags, chainPartDict, perSig_lengthOfChainConfigs)
408  else:
409  chainPartConfig = self.chainDefModule[currentSig].generateChainConfigs(flags, chainPartDict)
410  if currentSig == 'Test' and isinstance(chainPartConfig, tuple):
411  chainPartConfig = chainPartConfig[0]
412  except Exception:
413  log.error('[__generateChainConfigs] Problems creating ChainDef for chain %s ', chainName)
414  log.error('[__generateChainConfigs] I am in chain part\n %s ', chainPartDict)
415  log.exception('[__generateChainConfigs] Full chain dictionary is\n %s ', mainChainDict)
416  raise Exception('[__generateChainConfigs] Stopping menu generation. Please investigate the exception shown above.')
417  else:
418  log.error('Chain %s cannot be generated - Signature "%s" not available', chainPartDict['chainName'], currentSig)
419  log.error('Available signature(s): %s', self.availableSignatures)
420  raise Exception('Stopping the execution. Please correct the configuration.')
421 
422  log.debug("Chain %s \n chain config: %s",chainPartDict['chainName'],chainPartConfig)
423 
424  listOfChainConfigs.append(chainPartConfig)
425  log.debug("[__generateChainConfigs] adding to the perSig_lengthOfChainConfigs list (%s, %s)",chainPartConfig.nSteps,chainPartConfig.alignmentGroups)
426  perSig_lengthOfChainConfigs.append((chainPartConfig.nSteps,chainPartConfig.alignmentGroups))
427 
428  # this will be a list of lists for inter-sig combined chains and a list with one
429  # multi-element list for intra-sig combined chains
430  # here, we flatten it accordingly (works for both cases!)
431  lengthOfChainConfigs = []
432  for nSteps, aGrps in perSig_lengthOfChainConfigs:
433  if len(nSteps) != len(aGrps):
434  log.error("Chain part has %s steps and %s alignment groups - these don't match!",nSteps,aGrps)
435  else:
436  for a,b in zip(nSteps,aGrps):
437  lengthOfChainConfigs.append((a,b))
438 
439 
440  # This part is to deal with combined chains between different signatures
441  try:
442  if len(listOfChainConfigs) == 0:
443  raise Exception('[__generateChainConfigs] No Chain Configuration found for {0}'.format(mainChainDict['chainName']))
444  else:
445  if len(listOfChainConfigs)>1:
446  log.debug("Merging strategy from dictionary: %s", mainChainDict["mergingStrategy"])
447  theChainConfig, perSig_lengthOfChainConfigs = mergeChainDefs(listOfChainConfigs, mainChainDict, perSig_lengthOfChainConfigs)
448  lengthOfChainConfigs = []
449  for nSteps, aGrps in perSig_lengthOfChainConfigs:
450  if len(nSteps) != len(aGrps):
451  log.error("Post-merged chain part has %s steps and %s alignment groups - these don't match!",nSteps,aGrps)
452  else:
453  for a,b in zip(nSteps,aGrps):
454  lengthOfChainConfigs.append((a,b))
455  else:
456  theChainConfig = listOfChainConfigs[0]
457 
458  for topoID in range(len(mainChainDict['extraComboHypos'])):
459  thetopo = mainChainDict['extraComboHypos'][topoID].strip(string.digits).rstrip(topoLegIndices)
460 
461 
462  if "anomdet" in thetopo:
463  thetopo = thetopo.rstrip(anomdetWPIndices)
464 
465  theChainConfig.addTopo((comboConfigurator[thetopo],thetopo))
466 
467  # Now we know where the topos should go, we can insert them in the right steps
468  if len(theChainConfig.topoMap) > 0:
469  log.debug("Trying to add extra ComboHypoTool for %s",mainChainDict['extraComboHypos'])
470  addTopoInfo(theChainConfig,mainChainDict,listOfChainConfigs,lengthOfChainConfigs)
471  except RuntimeError:
472  log.error('[__generateChainConfigs] Problems creating ChainDef for chain %s ', chainName)
473  log.error('[__generateChainConfigs] I am in the extraComboHypos section, for %s ', mainChainDict['extraComboHypos'])
474  log.exception('[__generateChainConfigs] Full chain dictionary is\n %s ', mainChainDict)
475  raise Exception('[__generateChainConfigs] Stopping menu generation. Please investigate the exception shown above.')
476  except AttributeError:
477  raise Exception('[__generateChainConfigs] Stopping menu generation. Please investigate the exception shown above.')
478 
479  # Configure event building strategy
480  eventBuildType = mainChainDict['eventBuildType']
481  if eventBuildType:
482  try:
483  if 'PhysicsTLA' in eventBuildType:
484  log.debug("Adding TLA Step for chain %s", mainChainDict['chainName'])
485  TLABuildingSequences.addTLAStep(flags, theChainConfig, mainChainDict)
486  log.debug('Configuring event building sequence %s for chain %s', eventBuildType, mainChainDict['chainName'])
487  EventBuildingSequences.addEventBuildingSequence(flags, theChainConfig, eventBuildType, mainChainDict)
488  except TypeError as ex:
489  log.error(ex)
490  raise Exception('[__generateChainConfigs] Stopping menu generation for EventBuilding/TLA sequences. Please investigate the exception shown above.')
491 
492  log.debug('[__generateChainConfigs] lengthOfChainConfigs %s, ChainConfigs %s ', lengthOfChainConfigs, theChainConfig)
493  return theChainConfig,lengthOfChainConfigs
494 
495 
496  def resolveEmptySteps(self,chainConfigs):
497  max_steps = max([len(cc.steps) for cc in chainConfigs], default=0)
498  steps_are_empty = [True for i in range(0,max_steps)]
499  emptySteps = []
500  for cc in chainConfigs:
501  for istep, the_step in enumerate(cc.steps):
502  if not the_step.isEmpty:
503  steps_are_empty[istep] = False
504  else:
505  emptySteps.append(the_step)
506 
507  log.debug("Are there any fully empty steps? %s", steps_are_empty)
508  log.debug("The empty step(s) and associated chain(s) are: %s", emptySteps)
509  empty_step_indices = [i for i,is_empty in enumerate(steps_are_empty) if is_empty]
510 
511  if len(empty_step_indices) == 0:
512  return chainConfigs
513 
514  special_test_menu = self.chainFilter and ( getattr(self.chainFilter, "selectChains", False) or \
515  getattr(self.chainFilter, "disableChains", False) or \
516  getattr(self.chainFilter, "disabledSignatures", False) or \
517  getattr(self.chainFilter, "enabledSignatures", False) )
518 
519 
520  if len(self.availableSignatures) != 1 and not special_test_menu:
521  raise Exception("[resolveEmptySteps] Please find the reason for this empty step and resolve it / remove it from the menu: %s", emptySteps)
522 
523  log.info("Will now delete steps %s (indexed from zero)",empty_step_indices)
524 
525  for cc in chainConfigs:
526  new_steps = []
527  #only add non-empty steps to the new steps list!
528  for istep,step in enumerate(cc.steps):
529  if istep not in empty_step_indices:
530  new_steps += [step]
531  cc.steps = new_steps
532 
533  return chainConfigs
534 
535  def generatePrescales(self, flags, prescale_set: Optional[str] = '__auto__'):
536  '''Add prescales for disabling items (e.g. MC production)'''
537 
538  menu_name = flags.Trigger.triggerMenuSetup
539  if prescale_set == '__auto__':
540  if menu_name.endswith('_prescale'):
541  # Get the prescale set name from the Menu
542  prescale_set = menu_name.removeprefix(f'{self.base_menu_name}_').removesuffix('_prescale')
543  else:
544  prescale_set = None
545 
546  if prescale_set:
547  from TriggerMenuMT.HLT.Menu.MenuPrescaleConfig import menu_prescale_set_gens
548  if prescale_set not in menu_prescale_set_gens:
549  raise RuntimeError(f'Unknown menu prescale set for menu {flags.Trigger.triggerMenuSetup}')
550 
551  gen = menu_prescale_set_gens[prescale_set]
552  else:
553  from TriggerMenuMT.HLT.Config.Utility.MenuPrescaleSet import AutoPrescaleSetGen
554  gen = AutoPrescaleSetGen()
555 
556  # Generate prescale set
557  log.info(f'Generating automatic prescale set: {prescale_set}')
558  ps_set = gen.generate(flags, store=True)
559  self.L1Prescales = ps_set.l1_prescales
560  self.HLTPrescales = ps_set.hlt_prescales
561 
562 
563 
564 def generateMenuMT(flags):
565  """
566  == Main function to generate the L1, L1Topo and HLT menu configs and CA, using the GenerateMenuMT class
567  """
568  # Generate L1 menu
569  # The L1Menu json file is produced here
570  from TrigConfigSvc.TrigConfigSvcCfg import generateL1Menu
571  generateL1Menu(flags)
572 
573 
574  menu = GenerateMenuMT()
575 
576  # Apply generation filter (enable/disable chains and signatures)
577  chains_gen_filter = FilterChainsToGenerate(flags)
578  menu.setChainFilter(chains_gen_filter)
579  log.debug('Filtering chains: %d', menu.chainFilter is not None)
580 
581  # Generate all chains configuration
582  finalListOfChainConfigs = menu.generateAllChainConfigs(flags)
583 
584  log.info('Number of configured chains: %d', len(finalListOfChainConfigs))
585  from TriggerMenuMT.HLT.Config import MenuComponents
586  if len(MenuComponents._CustomComboHypoAllowed)> _maxAllowedCustomCH:
587  log.error(f'Found {len(MenuComponents._CustomComboHypoAllowed)} ComboHypo algorithms violating the one-CH-per-step rule, only {_maxAllowedCustomCH} are allowed (which are BLS ComboHypos). This is the list of current violations: {MenuComponents._CustomComboHypoAllowed}. Please consolidate your choice of ComboHypo, by checking that it is able to handle decisions internally; if yes eventually increase the limit set by _maxAllowedCustomCH, after discussing with experts')
588  # Generate and apply the automatic prescale sets (e.g. for disabling items in an MC production)
589  menu.generatePrescales(flags)
590 
591 
592  # Remove any remaining steps that are fully empty in all chains
593  finalListOfChainConfigs = menu.resolveEmptySteps(finalListOfChainConfigs)
594  log.debug("finalListOfChainConfig: %s", finalListOfChainConfigs)
595 
596  # Make the HLT configuration tree
597  # The HLTMenu json file is produced here.
598  log.info("Making the HLT configuration tree")
599  menuAcc, CFseq_list = makeHLTTree(flags, finalListOfChainConfigs)
600 
601  # Configure ChainFilters for ROBPrefetching
602  from TriggerJobOpts.TriggerConfigFlags import ROBPrefetching
603  if ROBPrefetching.InitialRoI in flags.Trigger.ROBPrefetchingOptions:
604  from TrigGenericAlgs.TrigGenericAlgsConfig import prefetchingInitialRoIConfig
605  menuAcc.merge(prefetchingInitialRoIConfig(flags, CFseq_list), 'HLTBeginSeq')
606 
607 
608  # Post-generation checks:
609  log.info("Checking the L1HLTConsistency...")
610  from TriggerMenuMT.HLT.Config.Validation.CheckL1HLTConsistency import checkL1HLTConsistency
611  checkL1HLTConsistency(flags)
612 
613  log.info("Checking the Coherent Prescale assignments...")
614  from TriggerMenuMT.HLT.Config.Validation.CheckCPSGroups import checkCPSGroups
615  checkCPSGroups(HLTMenuConfig.dictsList())
616 
617 
618  # Cleanup menu singletons to allow garbage collection (ATR-28855)
619  GenerateMenuMT.clear()
620  from TriggerMenuMT.HLT.Config import MenuComponents
621  MenuComponents._ComboHypoPool.clear()
622  MenuComponents._CustomComboHypoAllowed.clear()
623 
624  return menuAcc
625 
626 
627 def makeHLTTree(flags, chainConfigs):
628  """
629  Generate appropriate Control Flow Graph wiht all HLT algorithms
630  """
631  from TriggerMenuMT.HLT.Config.ControlFlow.HLTCFConfig import decisionTreeFromChains, sequenceScanner
632  from TriggerJobOpts.TriggerConfig import collectViewMakers
633  from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
634  from AthenaCommon.CFElements import seqAND
635 
636  acc = ComponentAccumulator()
637  steps = seqAND('HLTAllSteps')
638  finalDecisions, CFseq_list, menuAcc = decisionTreeFromChains(flags, steps, chainConfigs, HLTMenuConfig.dictsList())
639  if log.getEffectiveLevel() <= logging.DEBUG:
640  menuAcc.printConfig()
641 
642  acc.merge(menuAcc)
643  successful_scan = sequenceScanner( steps )
644  if not successful_scan:
645  raise Exception("[makeHLTTree] At least one sequence is expected in more than one step. Check error messages and fix!")
646 
647  flatDecisions=[]
648  for step in finalDecisions:
649  flatDecisions.extend (step)
650 
651  viewMakers = collectViewMakers(steps)
652  viewMakerMap = {vm.name:vm for vm in viewMakers}
653  for vmname, vm in viewMakerMap.items():
654  log.debug(f"[makeHLTTree] {vmname} InputMakerOutputDecisions: {vm.InputMakerOutputDecisions}")
655  if vmname.endswith("_probe"):
656  try:
657  log.debug(f"Setting InputCachedViews on {vmname} to read decisions from tag leg {vmname[:-6]}: {vm.InputMakerOutputDecisions}")
658  vm.InputCachedViews = viewMakerMap[vmname[:-6]].InputMakerOutputDecisions
659  except KeyError: # We may be using a probe leg that has different reco from the tag
660  log.debug(f"Tag leg does not match probe: '{vmname[:-6]}', will not use cached views")
661 
662 
663  # Generate JSON representation of the config
664  from TriggerMenuMT.HLT.Config.JSON.HLTMenuJSON import generateJSON
665  generateJSON(flags, HLTMenuConfig.dictsList(), menuAcc.getSequence("HLTAllSteps"))
666 
667  # Store the HLTMonitoring json file
668  from TriggerMenuMT.HLT.Config.JSON.HLTMonitoringJSON import generateDefaultMonitoringJSON
669  generateDefaultMonitoringJSON(flags, HLTMenuConfig.dictsList())
670 
671 
672  from AthenaCommon.CFElements import checkSequenceConsistency
674  return acc, CFseq_list
DerivationFramework::TriggerMatchingUtils::sorted
std::vector< typename R::value_type > sorted(const R &r, PROJ proj={})
Helper function to create a sorted vector from an unsorted range.
GenerateMenuMT.calibCosmicMonSignatures
def calibCosmicMonSignatures()
Definition: GenerateMenuMT.py:14
GenerateMenuMT.FilterChainsToGenerate.enabledSignatures
enabledSignatures
Definition: GenerateMenuMT.py:39
GenerateMenuMT.allSignatures
def allSignatures()
Definition: GenerateMenuMT.py:32
python.JetAnalysisCommon.ComponentAccumulator
ComponentAccumulator
Definition: JetAnalysisCommon.py:302
vtune_athena.format
format
Definition: vtune_athena.py:14
GenerateMenuMT.GenerateMenuMT.chainDefModule
chainDefModule
Definition: GenerateMenuMT.py:85
GenerateMenuMT.FilterChainsToGenerate.disabledSignatures
disabledSignatures
Definition: GenerateMenuMT.py:40
GenerateMenuMT.defaultSignatures
def defaultSignatures()
Definition: GenerateMenuMT.py:23
GenerateMenuMT.Singleton.clear
def clear(cls)
Definition: GenerateMenuMT.py:59
GenerateMenuMT.FilterChainsToGenerate
Definition: GenerateMenuMT.py:36
GenerateMenuMT.Singleton
Definition: GenerateMenuMT.py:52
max
constexpr double max()
Definition: ap_fixedTest.cxx:33
GenerateMenuMT.GenerateMenuMT.__generateChainConfig
def __generateChainConfig(self, flags, mainChainDict)
Definition: GenerateMenuMT.py:371
GenerateMenuMT.FilterChainsToGenerate.__init__
def __init__(self, flags)
Definition: GenerateMenuMT.py:38
GenerateMenuMT.GenerateMenuMT.chainFilter
chainFilter
Definition: GenerateMenuMT.py:80
GenerateMenuMT.GenerateMenuMT.configLengthDict
configLengthDict
Definition: GenerateMenuMT.py:74
python.TrigConfigSvcCfg.generateL1Menu
def generateL1Menu(flags)
Definition: TrigConfigSvcCfg.py:189
GenerateMenuMT.makeHLTTree
def makeHLTTree(flags, chainConfigs)
Definition: GenerateMenuMT.py:627
CheckL1HLTConsistency.checkL1HLTConsistency
def checkL1HLTConsistency(flags)
Definition: CheckL1HLTConsistency.py:48
GenerateMenuMT.GenerateMenuMT.setChainFilter
def setChainFilter(self, f)
Definition: GenerateMenuMT.py:103
DictFromChainName.dictFromChainName
def dictFromChainName(flags, chainInfo)
Definition: DictFromChainName.py:630
HLTCFConfig.decisionTreeFromChains
def decisionTreeFromChains(flags, HLTNode, chains, allDicts)
Definition: HLTCFConfig.py:166
ComboHypoHandling.addTopoInfo
def addTopoInfo(theChainConfig, mainChainDict, listOfChainDefs, lengthOfChainConfigs)
Definition: ComboHypoHandling.py:216
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
GenerateMenuMT.GenerateMenuMT.base_menu_name
base_menu_name
Definition: GenerateMenuMT.py:325
GenerateMenuMT.bphysicsSignatures
def bphysicsSignatures()
Definition: GenerateMenuMT.py:29
GenerateMenuMT.GenerateMenuMT.getChainDicts
def getChainDicts(self, flags)
Definition: GenerateMenuMT.py:125
GenerateMenuMT.GenerateMenuMT.allChainsForAlignment
allChainsForAlignment
Definition: GenerateMenuMT.py:70
GenerateMenuMT.GenerateMenuMT.availableSignatures
availableSignatures
Definition: GenerateMenuMT.py:81
python.CFElements.seqAND
def seqAND(name, subs=[])
Definition: CFElements.py:25
HLTCFConfig.sequenceScanner
def sequenceScanner(HLTNode)
Definition: HLTCFConfig.py:110
GenerateMenuMT.Singleton.__call__
def __call__(cls, *args, **kwargs)
Definition: GenerateMenuMT.py:54
GenerateMenuMT.GenerateMenuMT.HLTPrescales
HLTPrescales
Definition: GenerateMenuMT.py:78
GenerateMenuMT.combinedSignatures
def combinedSignatures()
Definition: GenerateMenuMT.py:17
python.CFElements.checkSequenceConsistency
def checkSequenceConsistency(seq)
Definition: CFElements.py:69
GenerateMenuMT.GenerateMenuMT.chainDicts
chainDicts
Definition: GenerateMenuMT.py:71
GenerateMenuMT.GenerateMenuMT.chainsInMenu
chainsInMenu
Definition: GenerateMenuMT.py:68
python.LArMinBiasAlgConfig.int
int
Definition: LArMinBiasAlgConfig.py:59
GenerateMenuMT.FilterChainsToGenerate.selectChains
selectChains
Definition: GenerateMenuMT.py:41
GenerateMenuMT.GenerateMenuMT.resolveEmptySteps
def resolveEmptySteps(self, chainConfigs)
Definition: GenerateMenuMT.py:496
GenerateMenuMT.GenerateMenuMT
Definition: GenerateMenuMT.py:63
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
GenerateMenuMT.GenerateMenuMT.__init__
def __init__(self)
Definition: GenerateMenuMT.py:65
GenerateMenuMT.generateMenuMT
def generateMenuMT(flags)
Definition: GenerateMenuMT.py:564
GenerateMenuMT.GenerateMenuMT.combinationsInMenu
combinationsInMenu
Definition: GenerateMenuMT.py:72
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
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:232
GenerateMenuMT.GenerateMenuMT.sigDicts
sigDicts
Definition: GenerateMenuMT.py:83
GenerateMenuMT.GenerateMenuMT.getRequiredSignatures
def getRequiredSignatures(theslice)
Definition: GenerateMenuMT.py:89
GenerateMenuMT.Singleton._instances
_instances
Definition: GenerateMenuMT.py:53
GenerateMenuMT.FilterChainsToGenerate.__str__
str __str__(self)
Definition: GenerateMenuMT.py:48
GenerateMenuMT.GenerateMenuMT.generateChains
def generateChains(self, flags)
Definition: GenerateMenuMT.py:187
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:71
GenerateMenuMT.jointSignatures
def jointSignatures()
Definition: GenerateMenuMT.py:20
python.TriggerConfig.collectViewMakers
def collectViewMakers(steps)
Definition: TriggerConfig.py:67
GenerateMenuMT.GenerateMenuMT.signaturesOverwritten
signaturesOverwritten
Definition: GenerateMenuMT.py:76
GenerateMenuMT.GenerateMenuMT.importSignaturesToGenerate
def importSignaturesToGenerate(self)
Definition: GenerateMenuMT.py:166
HLTMonitoringJSON.generateDefaultMonitoringJSON
def generateDefaultMonitoringJSON(flags, chainDicts)
Definition: HLTMonitoringJSON.py:21
CaloLCW_tf.group
group
Definition: CaloLCW_tf.py:28
ChainMerging.mergeChainDefs
def mergeChainDefs(listOfChainDefs, chainDict, perSig_lengthOfChainConfigs=None)
Definition: ChainMerging.py:15
python.TrigGenericAlgsConfig.prefetchingInitialRoIConfig
def prefetchingInitialRoIConfig(flags, CFseq_list)
Definition: TrigGenericAlgsConfig.py:159
GenerateMenuMT.GenerateMenuMT.L1Prescales
L1Prescales
Definition: GenerateMenuMT.py:77
GenerateMenuMT.GenerateMenuMT.getChainsFromMenu
def getChainsFromMenu(self, flags)
Definition: GenerateMenuMT.py:320
HLTMenuJSON.generateJSON
def generateJSON(flags, chainDicts, HLTAllSteps)
Definition: HLTMenuJSON.py:83
GenerateMenuMT.FilterChainsToGenerate.__call__
def __call__(self, signame, chain)
Definition: GenerateMenuMT.py:44
GenerateMenuMT.FilterChainsToGenerate.disableChains
disableChains
Definition: GenerateMenuMT.py:42
pickleTool.object
object
Definition: pickleTool.py:30
ChainDictTools.splitInterSignatureChainDict
def splitInterSignatureChainDict(chainDict)
Definition: ChainDictTools.py:9
CheckCPSGroups.checkCPSGroups
def checkCPSGroups(chainDicts)
Definition: CheckCPSGroups.py:19
GenerateMenuMT.GenerateMenuMT.alignmentGroupsToAlign
alignmentGroupsToAlign
Definition: GenerateMenuMT.py:73
GenerateMenuMT.GenerateMenuMT.generateAllChainConfigs
def generateAllChainConfigs(self, flags)
Definition: GenerateMenuMT.py:227
python.HLT.Bjet.GenerateBjetChainDefs.generateChainConfigs
def generateChainConfigs(flags, chainDict)
Definition: GenerateBjetChainDefs.py:13
GenerateMenuMT.testSignatures
def testSignatures()
Definition: GenerateMenuMT.py:26
GenerateMenuMT.GenerateMenuMT.generatePrescales
def generatePrescales(self, flags, Optional[str] prescale_set='__auto__')
Definition: GenerateMenuMT.py:535