ATLAS Offline Software
L1MenuConfig.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 import re
4 from importlib import import_module
5 from collections import defaultdict as ddict
6 from itertools import chain
7 
8 from AthenaCommon.Logging import logging
9 
10 from .Base.L1MenuFlags import L1MenuFlags
11 from .Base.Limits import Limits
12 from .Base.Boards import BoardType
13 from .Base.L1Menu import L1Menu
14 from .Base.Thresholds import TopoThreshold
15 from .Base.TopoAlgorithms import AlgCategory
16 from .Base.L1Menu2JSON import L1MenuJSONConverter
17 from .Config.TriggerTypeDef import TT
18 from .Config.TopoAlgoDefMultiplicity import TopoAlgoDefMultiplicity
19 from .Config.ItemDef import ItemDef
20 
21 """
22 L1MenuConfig is responsible for building the L1 Menu
23 
24 Building a menu happens in two stages
25 
26 1) Configuration objects are defined in the directory TriggerMenuMT/Config/ in *Def.py files
27  * Items are definded in Config/ItemDef.py
28  * Topo algorithms are define in files TopoAlgoDef*.py, with separate files for
29  - multiplicity counting algorithms on the Run 3 topo boards
30  - topological selection algorithms on the Run 3 topo boards
31  - topological selection algorithms on the MUCTPI board
32  - topological selection algorithms on the Run 2 topo boards (legacy boards)
33  * Thresholds are defined in files ThresholdDef.py
34 """
35 
36 log = logging.getLogger(__name__)
37 
39 
40  def __init__(self, flags, inputFile = None):
41 
42  L1MenuFlags.MenuSetup = flags.Trigger.triggerMenuSetup
43 
44  self.menuFullName = L1MenuFlags.MenuSetup()
46  self.menuName = self.menuFilesToLoad[0]
47  self.inputFile = inputFile
48  self.l1menuFromFile = (self.inputFile is not None)
49  self.generated = False
50 
51  # all registered items
52  self.registeredItems = {}
53 
54  # all registered thresholds
56  self._registeredThresholdsStats = { "muon": 0, "calo": 0, "nim": 0, "legacy": 0,
57  AlgCategory.TOPO : 0, AlgCategory.MUCTPI : 0, AlgCategory.LEGACY : 0 }
58 
59  # all registered topo algos
61  for cat in AlgCategory.getAllCategories():
62  self._registeredTopoAlgos[cat] = {}
63 
64  # menu
65  L1MenuFlags.CTPVersion = 4 # this needs to be done here already, since L1Menu depends on it during init
66  self.l1menu = L1Menu(self.menuName, flags)
67 
68  self.l1menu.setBunchGroupSplitting() # store bunchgroups separate from other item inputs
69 
70  if not self._checkMenuExistence():
71  log.error("Generating L1 menu %s is not possible", self.menuName)
72  else:
73  log.info("=== Generating L1 menu %s ===", self.menuName)
74  self._generate(flags)
75 
76  def _generate(self, flags):
77 
78  log.info("=== Reading definition of algorithms, thresholds, and items ===")
79 
80  self._registerDefinedConfigurationObjects() # defines and registers all items, thresholds, ...
81 
82  log.info("=== Reading definition of menu ===")
83 
84  # Build menu
85  self._importMenuDefinition() # puts thresholds and items names for the menu into the LVL1Flags
86 
87  self._extendInformation()
88 
89  self._generateTopoMenu()
90 
91  self._generateMenu(flags)
92 
93  self.generated = True
94 
95 
96  def thresholdExists(self,thrName):
97  return thrName in self._registeredThresholds
98 
99  def getDefinedThreshold(self, name):
100  try:
101  return self._registeredThresholds[name]
102  except KeyError as ex:
103  if name.startswith("R2TOPO"):
104  log.error("No legacy topo output %s is registered. Make sure it is defined in L1/Config/TopoAlgoDefLegacy.py", name)
105  elif name.startswith("TOPO"):
106  log.error("No topo output %s is registered. Make sure it is defined in L1/Config/TopoAlgoDef.py", name)
107  else:
108  isLegacy = any(filter(lambda x: name.startswith(x), ["EM", "TAU", "J", "XE", "TE", "XS"]))
109  log.error("No threshold %s is registered. Make sure it is defined in L1/Config/ThresholdDef%s.py", name,"Legacy" if isLegacy else "")
110  raise ex
111 
113  return self._registeredThresholds.values()
114 
115 
116 
117 
120 
121 
122  def registerTopoAlgo(self, algo):
123  """ Add a L1Topo algo to the set of algos which are registered for further use"""
124 
125  if self.currentAlgoDef == AlgCategory.MULTI:
126  algo.name = "Mult_" + algo.name
127 
128  if algo.name in self._registeredTopoAlgos[self.currentAlgoDef]:
129  raise RuntimeError('%s algo %s is already registered as such' % (self.currentAlgoDef.desc, algo.name))
130  self._registeredTopoAlgos[self.currentAlgoDef][algo.name] = algo
131  log.debug("Added in the %s type the algo: %s", self.currentAlgoDef.desc, algo.name)
132 
133  return algo
134 
135 
136 
137  def registerThreshold(self, thr):
138  """
139  Add externally created L1 threshold to the list of available thresholds.
140  """
141  if thr.run!=0:
142  self._addThrToRegistry(thr)
143  else:
144  raise RuntimeError("For threshold %s the run (=2 or 3) was not set!" % thr.name)
145  return thr
146 
147  def _addThrToRegistry(self, thr):
148  if self.thresholdExists(thr.name):
149  raise RuntimeError("LVL1 threshold of name '%s' already defined, need to abort" % thr.name)
150 
151  self._registeredThresholds[thr.name] = thr
152 
153  # collect stats
154  isTopo = isinstance(thr, TopoThreshold)
155  if isTopo:
156  self._registeredThresholdsStats[thr.algCategory] += 1
157  return
158 
159  isNIM = thr.ttype in ['NIM','CALREQ','MBTSSI', 'MBTS', 'LUCID', 'BCM', 'BCMCMB', 'ZDC', 'BPTX', 'ZB']
160  if thr.isLegacy():
161  self._registeredThresholdsStats["legacy"] += 1
162  elif isNIM:
163  self._registeredThresholdsStats["nim"] += 1
164  elif thr.ttype == 'MU':
165  self._registeredThresholdsStats["muon"] += 1
166  else:
167  self._registeredThresholdsStats["calo"] += 1
168 
169 
170 
171 
173  """
174  Add all L1Topo triggers that are part of the menu as allowed input to the menu
175  """
176 
177  _topoTriggers = {}
178 
179  # for all topo algorithm categories the outputs (sometimes multiple) are defined as thresholds
180  for cat in AlgCategory.getAllCategories():
181  outputLines = []
182  for algo in self._registeredTopoAlgos[cat].values():
183  outputLines += algo.outputs if (type(algo.outputs) is list) else [ algo.outputs ]
184  _topoTriggers[cat] = sorted(outputLines)
185  log.info("... found %i topo triggerlines (source: %s)", len(_topoTriggers[cat]), cat )
186  log.debug("%r", _topoTriggers[cat])
187 
188 
189  multibitPattern = re.compile(r"(?P<line>.*)\[(?P<bit>\d+)\]")
190  for cat in [AlgCategory.TOPO, AlgCategory.MUCTPI, AlgCategory.LEGACY]:
191  multibitTopoTriggers = set()
192  for topoLineName in _topoTriggers[cat]:
193  m = multibitPattern.match(topoLineName) # tries to match "trigger[bit]"
194  if m:
195  topoThrName = cat.prefix + m.groupdict()['line']
196  multibitTopoTriggers.add( topoThrName )
197  else:
198  topoThrName = cat.prefix + topoLineName
199  TopoThreshold( name = topoThrName, algCategory = cat )
200  # create thresholds from topo-multibit
201  for topoThrName in multibitTopoTriggers: # ( 'MULT-CMU4ab', ...)
202  TopoThreshold( name = topoThrName, algCategory = cat )
203 
204 
205 
206 
207  def registerItem(self, name, item):
208  """ Adds a LVL1 item to the set of items which are registered for further use"""
209  if name in self.registeredItems:
210  log.error('LVL1 item %s is already registered with ctpid=%d',
211  name, int(self.registeredItems[name].ctpid))
212  else:
213  self.registeredItems[name] = item
214 
215  def getRegisteredItem(self, name):
216  if name in self.registeredItems:
217  return self.registeredItems[name]
218  return None
219 
220 
221  def writeJSON(self, outputFile, bgsOutputFile = None, destdir="./"):
222  if self.generated:
223  outputFile = destdir.rstrip('/') + '/' + outputFile
224  if bgsOutputFile is not None:
225  bgsOutputFile = destdir.rstrip('/') + '/' + bgsOutputFile
226  L1MenuJSONConverter(l1menu = self.l1menu, outputFile = outputFile,
227  bgsOutputFile = bgsOutputFile).writeJSON(pretty=True)
228  return outputFile, bgsOutputFile
229  else:
230  log.error("No menu was generated, can not create json file")
231  return None
232 
233  def _menuToLoad(self, silent=False):
234  """ resolve the menu name to the menu files to load"""
235  menuToLoadReq = self.menuFullName
236  # Extract the menu name, independent of menu prescale sets
237  if menuToLoadReq.endswith('prescale'):
238  menuToLoadReq = re.match(r'\w*_v\d*',self.menuFullName).group(0)
239  log.info(f'Base menu name {menuToLoadReq} extracted from {self.menuFullName}')
240  from .Menu.MenuMapping import menuMap
241  if menuToLoadReq in menuMap:
242  menuToLoad = menuMap[menuToLoadReq]
243  if not silent:
244  log.info("Menu %s was requested, but will load %s as specified in TriggerMenuMT.L1.Menu.menuMap", menuToLoadReq, menuToLoad[0])
245  else:
246  menuToLoad = [menuToLoadReq,str(menuToLoadReq)+"_inputs",str(menuToLoadReq)+"_inputs_legacy"]
247  return menuToLoad
248 
250  from PyUtils.moduleExists import moduleExists
251  modname = 'TriggerMenuMT.L1.Menu.Menu_%s' % self.menuFilesToLoad[0]
252  if not moduleExists (modname):
253  log.error("No L1 menu available for %s, module %s does not exist", self.menuName, modname )
254  return False
255 
256  return True
257 
258 
260  """
261  Defines the list if item and threshold names that will be in the menu
262  Calls defineMenu() of the correct module 'Menu_<menuname>.py'
263  Menu.defineMenu() defines the menu via L1MenuFlags "items", "thresholds",
264  """
265 
266  # we apply a hack here. menu group is working on Dev_pp_run3_v1, until ready we will use MC_pp_run3_v1
267  log.info("Reading TriggerMenuMT.Menu.Menu_%s", self.menuFilesToLoad[0])
268  menumodule = __import__('TriggerMenuMT.L1.Menu.Menu_%s' % self.menuFilesToLoad[0], globals(), locals(), ['defineMenu'], 0)
269  menumodule.defineMenu()
270  log.info("... L1 menu '%s' contains %i items", self.menuFilesToLoad[0], len(L1MenuFlags.items()))
271 
272  log.info("Reading TriggerMenuMT.Menu.Menu_%s", self.menuFilesToLoad[1])
273  topomenumodule = __import__('TriggerMenuMT.L1.Menu.Menu_%s' % self.menuFilesToLoad[1], globals(), locals(), ['defineMenu'], 0)
274  topomenumodule.defineInputsMenu() # this adds the inputs definition (boards) to L1MenuFlags.boards
275  connectorCount = 0
276  algoCount = 0
277  for boardName, boardDef in L1MenuFlags.boards().items():
278  if "connectors" in boardDef:
279  connectorCount += len(boardDef["connectors"])
280  for c in boardDef["connectors"]:
281  if "thresholds" in c:
282  algoCount += len(c["thresholds"])
283  elif "algorithmGroups" in c:
284  for t in c["algorithmGroups"]:
285  algoCount += len(t["algorithms"])
286  else:
287  for t in c["signalGroups"]:
288  algoCount += len(t["signals"])
289  log.info("... L1Topo menu '%s' contains %i boards (%s)", self.menuFilesToLoad[0], len(L1MenuFlags.boards()), ', '.join(L1MenuFlags.boards().keys()))
290  log.info(" with %i connectors and %i input signals", connectorCount, algoCount)
291 
292  try:
293  log.info("Reading TriggerMenuMT.Menu.Menu_%s", self.menuFilesToLoad[2])
294  legacymenumodule = __import__('TriggerMenuMT.L1.Menu.Menu_%s' % self.menuFilesToLoad[2], globals(), locals(), ['defineMenu'], 0)
295  legacymenumodule.defineLegacyInputsMenu()
296  log.info("... L1 legacy menu %s contains %i legacy boards (%s)", self.menuFilesToLoad[2], len(L1MenuFlags.legacyBoards()), ', '.join(L1MenuFlags.legacyBoards().keys()))
297  except ImportError as ie:
298  if ie.name == 'TriggerMenuMT.L1.Menu.Menu_%s' % self.menuFilesToLoad[2]:
299  log.info("==> No menu defining the legacy inputs was found, will assume this intended. %s %s %s",
300  ie.msg, ie.name, ie.path)
301  else:
302  raise
303 
305  """
306  Registers the list if items and thresholds that could be used in the menu
307  Calls registerItem() of the correct module 'ItemDef.py'
308  """
309  from .Base.Items import MenuItem
310  MenuItem.setMenuConfig(self) # from now on all newly created MenuItems are automatically registered here
311  from .Base.Thresholds import Threshold
312  Threshold.setMenuConfig(self) # from now on all newly created Thresholds definitions are automatically registered here
313 
314  # register Topo algorithms
315  for algCat in [AlgCategory.TOPO, AlgCategory.MUCTPI, AlgCategory.MULTI, AlgCategory.LEGACY]:
316  self.currentAlgoDef = algCat
317  defFile = "TriggerMenuMT.L1.Config.%s" % self.currentAlgoDef.defFile
318  log.info("Reading %s", defFile)
319  import_module(defFile).__getattribute__(self.currentAlgoDef.defFile).registerTopoAlgos(self)
320  log.info("... registered %i defined topo algos for the %s board(s)", len(self._registeredTopoAlgos[self.currentAlgoDef]), self.currentAlgoDef.desc)
321 
322  log.info("Reading TriggerMenuMT.Config.ThreholdDef")
323  from .Config.ThresholdDef import ThresholdDef
324  ThresholdDef.registerThresholds(self, self.menuFullName)
325  log.info("... registered %i calo thresholds", self._registeredThresholdsStats["calo"])
326  log.info("... registered %i muon thresholds", self._registeredThresholdsStats["muon"])
327  log.info("... registered %i nim thresholds", self._registeredThresholdsStats["nim"])
328 
329  log.info("Reading TriggerMenuMT.Config.ThreholdDefLegacy")
330  from .Config.ThresholdDefLegacy import ThresholdDefLegacy
331  ThresholdDefLegacy.registerThresholds(self, self.menuFullName)
332  log.info("... registered %i legacy calo thresholds", self._registeredThresholdsStats["legacy"])
333 
334  log.info("Turning topo algo outputs into thresholds (except multiplicity counters)")
336  log.info("... registered %i topo thresholds", self._registeredThresholdsStats[AlgCategory.TOPO])
337  log.info("... registered %i muctpi topo thresholds", self._registeredThresholdsStats[AlgCategory.MUCTPI])
338  log.info("... registered %i legacy topo thresholds", self._registeredThresholdsStats[AlgCategory.LEGACY])
339 
340  log.info("Reading TriggerMenuMT.Config.ItemDef")
341  ItemDef.registerItems(self, self.menuFullName)
342  log.info("... registered %i defined items", len(self.registeredItems))
343 
344 
345  def _getTopoAlgo(self, algoName, category):
346  if algoName in self._registeredTopoAlgos[category]:
347  return self._registeredTopoAlgos[category][algoName]
348  msg = "Algorithm of name %s in category %s is not registered. Please add the algorithm to L1/Config/%s.py" % (algoName, category, category.defFile)
349  log.error(msg)
350  log.info("Available algorithms in this category are %s", ",".join(self._registeredTopoAlgos[category].keys()))
351  raise RuntimeError(msg)
352 
353 
354  def _getSortingAlgoThatProvides(self, input, topoAlgCategory):
355  """
356  returns a list of all sorting algorithms that are needed to
357  produce the required output. A missing input will raise a
358  runtime exception
359  """
360  sortingAlgs = []
361  for name, alg in self._registeredTopoAlgos[topoAlgCategory].items():
362  if type(alg.outputs)==list:
363  foundOutput = (input in alg.outputs)
364  else:
365  foundOutput = (input == alg.outputs)
366  if foundOutput:
367  sortingAlgs += [alg]
368 
369  if len(sortingAlgs)==0:
370  msg = "No topo sorting algorithm is providing this output: %s. Please add the sorting algorithm to L1/Config/%s.py" % (input, topoAlgCategory.defFile)
371  raise RuntimeError(msg)
372  if len(sortingAlgs)>1:
373  msg = "More than one sorting algorithm is providing this output: %s. Here the list: %s" % (input, ', '.join(sortingAlgs))
374  raise RuntimeError(msg)
375 
376  return sortingAlgs[0]
377 
378 
380  """
381  this function is called first after the menu definition is imported
382  it can be used to update some of the information or to perform initial checks
383  """
384  allBoards = (list(L1MenuFlags.boards().items()) + list(L1MenuFlags.legacyBoards().items()))
385  # set boardName in each connector
386  for (boardName, boardDef) in allBoards:
387  boardDef["name"] = boardName
388  if "connectors" in boardDef:
389  for connDef in boardDef["connectors"]:
390  connDef["board"] = boardName
391  else:
392  for connDef in boardDef["inputConnectors"]:
393  connDef["board"] = boardName
394 
395 
396  def _generateTopoMenu(self):
397 
398  allBoardsWithTopo = list( filter (
399  lambda b : BoardType.fromBoardName(b[0]) in [BoardType.TOPO, BoardType.MUCTPI],
400  chain(L1MenuFlags.boards().items(), L1MenuFlags.legacyBoards().items())
401  ))
402 
403  #
404  # Add the topo thresholds to the menu
405  #
406  nAlgos = 0
407  nLines = 0
408  for (boardName, boardDef) in allBoardsWithTopo:
409  currentTopoCategory = AlgCategory.getCategoryFromBoardName(boardName)
410  for connDef in boardDef["connectors"]:
411  if connDef["format"] == 'multiplicity': # multiplicity algorithms don't define thresholds
412  continue
413  for algGrp in connDef["algorithmGroups"]:
414  for topodef in algGrp["algorithms"]:
415  nAlgos += 1
416  nLines += len(topodef.outputlines)
417  # this is identical to outputlines except that ["MULT-CMU4ab[0]", "MULT-CMU4ab[1]"] becomes [ "MULT-CMU4ab" ]
418  outputlines = list(dict.fromkeys(map(lambda x: re.split(r"\[\d\]",x)[0], topodef.outputlines)))
419  for lineName in outputlines:
420  thrName = currentTopoCategory.prefix + lineName
421  thr = self.getDefinedThreshold(thrName) # threshold has to be defined
422  if thr is None:
423  if 'legacy' in boardDef:
424  msg = 'Threshold %s is required for board %s, connector %s (file L1/Menu/Menu_%s.py), but it is not registered. ' % (thrName, boardName, connDef['name'], self.menuFilesToLoad[2])
425  msg += 'Please add L1Topo alg with output %s to L1/Config/TopoAlgoDefLegacy.py.' % (thrName.split('_',1)[-1])
426  else:
427  msg = 'Threshold %s is required for board %s, connector %s (file L1/Menu/Menu_%s.py), but it is not registered. ' % (thrName, boardName, connDef['name'], self.menuFilesToLoad[1])
428  msg += 'Please add L1Topo alg with output %s to L1/Config/TopoAlgoDef.py.' % (thrName.split('_',1)[-1])
429  log.error(msg)
430  raise RuntimeError(msg)
431  else:
432  self.l1menu.addThreshold( thr )
433  log.info("Generating topo menu using %i topo algorithms with %i trigger lines", nAlgos, nLines )
434 
435  #
436  # Add the topo algorithms to the menu
437  #
438 
439  # collect sorting algorithms from all decision algorithms (their inputs)
440  # they need to be kept separated by source at this point
441  allRequiredSortedInputs = {
442  AlgCategory.TOPO : set(),
443  AlgCategory.MUCTPI : set(), # TODO: think about MUCTP sorting input
444  AlgCategory.LEGACY : set()
445  }
446 
447  # loop over all topo boards and their connectors
448  for (boardName, boardDef) in allBoardsWithTopo:
449  for connDef in boardDef["connectors"]:
450  if ('muctpi' in boardName.lower()) and (connDef["format"]=='multiplicity'):
451  # muctpi doesn't need multiplicity algorithms defined
452  continue
453 
454  currentTopoCategory = AlgCategory.getCategoryFromBoardName(boardName)
455  if currentTopoCategory == AlgCategory.TOPO and connDef["format"] == 'multiplicity':
456  currentTopoCategory = AlgCategory.MULTI
457  algoNames = []
458  algoNbits = []
459  fpgaNames = []
460  if connDef["format"] == 'multiplicity':
461  for thrName in connDef["thresholds"]:
462  if thrName is None:
463  continue
464  nBits = connDef["nbitsDefault"]
465  if type(thrName)==tuple:
466  (thrName,nBits) = thrName
467  if thrName is None:
468  continue
469  algoname = "Mult_" + thrName
470  algoNames += [ algoname ]
471  algoNbits += [ int(nBits) ]
472  fpgaNames += ['']
473  elif connDef["format"] == 'topological':
474  for algGrp in connDef["algorithmGroups"]:
475  for topodef in algGrp["algorithms"]:
476  algoNames += [ topodef.algoname ]
477  algoNbits += [ -1 ]
478  fpgaNames += [str(algGrp['fpga'])]
479  for algoName, algoBits, fpgaName in zip(algoNames, algoNbits, fpgaNames):
480  algo = self._getTopoAlgo(algoName, currentTopoCategory)
481  # check that the output bits of the multiplicity topo algorithms are as many as the output bits of the associated thresholds
482  if algoBits>0:
483  if algoBits != algo.nbits:
484  msg = "Algorithm %s defined with %i bits, but the associated threshold has %i bits " % (algo.name, algo.nbits, algoBits)
485  raise RuntimeError(msg)
486  self.l1menu.checkBoardInputs(algo, connDef["name"], fpgaName)
487  # add the decision algorithms to the menu
488  self.l1menu.addTopoAlgo( algo, category = currentTopoCategory )
489 
490  # remember the inputs
491  if algo.isDecisionAlg():
492  allRequiredSortedInputs[currentTopoCategory].update( algo.inputs )
493 
494  # now also add the sorting algorithms to the menu
495  for cat in allRequiredSortedInputs:
496  for input in allRequiredSortedInputs[cat]:
497  searchCat = cat
498  sortingAlgo = self._getSortingAlgoThatProvides(input, searchCat)
499  self.l1menu.addTopoAlgo( sortingAlgo, category = cat )
500 
501 
502 
503  def _generateMenu(self, flags):
504 
505  if len(self.l1menu.items) > 0:
506  log.info("L1MenuConfig.generate() has already been called. Will ignore")
507  return
508 
509  """
510  Generates the menu structure from the list of item and threshold names in the L1MenuFlags
511  """
512 
513  # ------------------
514  # Bunchgroups
515  # ------------------
516  from .Base.BunchGroupSet import createDefaultBunchGroupSet
517  self.l1menu.ctp.bunchGroupSet = createDefaultBunchGroupSet(flags)
518 
519 
520  # ------------------
521  # Thresholds
522  # ------------------
523 
524  allBoards = (list(L1MenuFlags.boards().items()) + list(L1MenuFlags.legacyBoards().items()))
525 
526  if 'AllCTPIn' in self.menuName:
527  # Only after we know all boards are defined, in the special case
528  # that we are running the dummy L1 menu for CTP input configuration
529  # we need to register more items that access every input
530  ItemDef.registerItems_AllCTPIn(self)
531 
532  for (boardName, boardDef) in L1MenuFlags.legacyBoards().items():
533  for connDef in boardDef["connectors"]:
534  # Verify number and ordering of thresholds on L1Calo boards
535  if connDef["type"] == "ctpin" and connDef["format"] == "multiplicity":
536  self.l1menu.checkL1CaloThresholds(connDef["thresholds"], boardName, connDef["name"])
537 
538  list_of_undefined_thresholds = []
539  # new thresholds
540  for (boardName, boardDef) in L1MenuFlags.boards().items():
541  for connDef in boardDef["connectors"]:
542  if connDef["type"] == "ctpin" or connDef["format"] != "multiplicity":
543  continue
544  for thrName in connDef["thresholds"]:
545  if type(thrName) is tuple:
546  (thrName, _) = thrName
547  if (thrName is None) or (thrName in self.l1menu.thresholds):
548  continue
549  threshold = self.getDefinedThreshold(thrName)
550  if threshold is None:
551  log.error('Threshold %s is required in menu on board %s, connector %s, but it is not defined', thrName, boardName, connDef['name'] )
552  list_of_undefined_thresholds += [ thrName ]
553  else:
554  self.l1menu.addThreshold( threshold )
555  try:
556  zbThrName = connDef["zeroBias"]
557  zbThr = self.getDefinedThreshold(zbThrName)
558  if zbThr is None:
559  log.error('Zero bias threshold %s is listed in menu but not defined', zbThrName )
560  list_of_undefined_thresholds += [ zbThrName ]
561  else:
562  self.l1menu.addThreshold( zbThr )
563  except KeyError:
564  pass
565 
566 
567  # signals from merger boards
568  for (boardName, boardDef) in L1MenuFlags.boards().items():
569  for connDef in boardDef["connectors"]:
570  if connDef["format"] != "simple":
571  continue
572  for sGrp in connDef["signalGroups"]:
573  for thrName in sGrp["signals"]:
574  if type(thrName) is tuple:
575  (thrName, _) = thrName
576  if thrName is None or thrName in self.l1menu.thresholds:
577  continue
578  threshold = self.getDefinedThreshold(thrName)
579  if threshold is None:
580  log.error('Threshold %s is required in menu on board %s, connector %s, but it is not defined', thrName, boardName, connDef['name'] )
581  list_of_undefined_thresholds += [ thrName ]
582  else:
583  self.l1menu.addThreshold( threshold )
584 
585  # ctpin thresholds
586  for (boardName, boardDef) in allBoards:
587  for connDef in boardDef["connectors"]:
588  if connDef["type"] != "ctpin":
589  continue
590  for entry in connDef["thresholds"]:
591  if type(entry) is dict:
592  # section that defines topo legacy thresholds
593  thrNames = sum([x.outputlines for x in entry["algorithms"]],[])
594  elif type(entry) is str:
595  thrNames = [ entry ]
596  elif type(entry) is tuple:
597  thrNames = [ entry[0] ]
598 
599  for thrName in thrNames:
600  if thrName is None or thrName in self.l1menu.thresholds:
601  continue
602  threshold = self.getDefinedThreshold(thrName)
603  if threshold is None:
604  log.error('Threshold %s is listed in menu but not defined', thrName )
605  list_of_undefined_thresholds += [ thrName ]
606  else:
607  self.l1menu.addThreshold( threshold )
608  try:
609  zbThrName = connDef["zeroBias"]
610  zbThr = self.getDefinedThreshold(zbThrName)
611  if zbThr is None:
612  log.error('Zero bias threshold %s is listed in menu but not defined', zbThrName )
613  list_of_undefined_thresholds += [ zbThrName ]
614  else:
615  self.l1menu.addThreshold( zbThr )
616  except KeyError:
617  pass
618 
619  if len(list_of_undefined_thresholds)>0:
620  raise RuntimeError("Found undefined threshold in menu %s, please add these thresholds to l1menu/ThresholdDef.py: %s" % \
621  (self.l1menu.menuName, ', '.join(list_of_undefined_thresholds)) )
622 
623 
624  # ------------------
625  # Items
626  # ------------------
627 
628  # build list of items for the menu from the list of requested names
629  itemsForMenu = []
630  ctpIdMap = L1MenuFlags.CtpIdMap()
631  for itemName in L1MenuFlags.items():
632  registeredItem = self.getRegisteredItem(itemName)
633  if registeredItem is None:
634  msg = "L1 item '%s' has not been defined in L1/Config/ItemDef.py" % itemName
635  log.error(msg)
636  raise RuntimeError(msg)
637 
638  if itemName in ctpIdMap:
639  newCTPID = ctpIdMap[itemName]
640  registeredItem.setCtpid(newCTPID)
641 
642  for thrName in registeredItem.thresholdNames():
643  if thrName not in self.l1menu.thresholds:
644  isLegacyThr = any(filter(lambda x: thrName.startswith(x), ["R2TOPO_", "EM", "HA", "J", "XE", "TE", "XS"]))
645 
646  msg = "L1 item {item} has been added to the menu L1/Menu/Menu_{menu}.py, but the required threshold {thr} is not listed as input in L1/Menu/Menu_{menu_inputs}.py".format(item=itemName, thr=thrName, menu=self.menuFilesToLoad[0], menu_inputs=self.menuFilesToLoad[2] if isLegacyThr else self.menuFilesToLoad[1])
647  log.error(msg)
648  raise RuntimeError(msg)
649 
650  itemsForMenu += [ registeredItem ]
651 
652 
653 
654  # CTP IDs available for assignment
655  assigned_ctpids = set([item.ctpid for item in itemsForMenu])
656  available_ctpids = sorted( list( set(range(Limits.MaxTrigItems)) - assigned_ctpids ), reverse=True )
657 
658  # add the items to the menu
659  for item in itemsForMenu:
660  # set the physics bit
661  if not item.name.startswith('L1_CALREQ'):
662  item.setTriggerType( item.trigger_type | TT.phys )
663  # assign ctp IDs to items that don't have one
664  if item.ctpid == -1:
665  if len(available_ctpids)==0:
666  raise RuntimeError("No more CTP IDs available at L1!!")
667  item.setCtpid( available_ctpids.pop() )
668  # add the items into the menu
669  self.l1menu.addItem( item )
670 
671  # ------------------
672  # Connectors
673  # ------------------
674 
675  for (boardName, boardDef) in allBoards:
676  for connDef in boardDef["connectors"]:
677  self.l1menu.addConnector( connDef )
678 
679  # ------------------
680  # Boards
681  # ------------------
682 
683  for (boardName, boardDef) in allBoards:
684  self.l1menu.addBoard(boardDef)
685 
686  # ------------------
687  # Mark items legacy
688  # ------------------
689  legacyThresholdsSet = set() # determine from connectors
690  for conn in self.l1menu.connectors:
691  if not conn.isLegacy():
692  continue
693  legacyThresholdsSet.update(conn.triggerThresholds())
694  for item in self.l1menu.items:
695  item.markLegacy(legacyThresholdsSet)
696 
697 
698  # assign mapping to thresholds according to their use in the menu
699  self.mapThresholds()
700 
701  # ------------------
702  # CTP
703  # ------------------
704  self.l1menu.ctp.checkConnectorAvailability(self.l1menu.connectors, self.menuFilesToLoad)
705 
706  # set the ctp monitoring (only now after the menu is defined)
707  self.l1menu.setupCTPMonitoring()
708 
709  # ------------------
710  # final consistency check
711  # ------------------
712 
713  self.l1menu.check()
714 
715  # check that no L1 items are defined with BGRP0 only
716  self.l1menu.checkBGRP()
717 
718  # check that only the minimal set of legacy and detector thresholds is used
719  if 'pp' in self.l1menu.menuName:
720  self.l1menu.checkLegacyThresholds()
721 
722  # check for the topo multiplicity algorithms and CTP inputs
723  # TOPO1
724  TopoAlgoDefMultiplicity.checkMultAlgoFWconstraints(self.l1menu)
725 
726  # check #number of CTP inputs and outputs <=512
727  self.l1menu.checkCountCTPInputsOutput()
728 
729  # check #number of inputs on the CTPIN connectors
730  self.l1menu.checkCTPINconnectors()
731 
732  # check that performance thresholds are not used in the physics L1 menu
733  self.l1menu.checkPerfThresholds()
734 
735  # check that the minimum thresholds of the TOBs sent to TOPO are below the min thresholds used in menu (ATR-15450)
736  self.l1menu.checkPtMinToTopo()
737 
738  # check that the ordering of the L1Topo parameters matches those expected in the L1Topo firmware
739  self.l1menu.checkL1TopoParams()
740 
741  # check that every item in the menu is on a board connected to CTP
742  self.l1menu.checkItemsHaveInputs()
743 
744  def mapThresholds(self):
745  """
746  Set the correct mapping of thresholds according to the
747  order it was given in L1MenuFlags.thresholds list. That list
748  is usually defined in the setupMenu function of each menu
749 
750  NIM and CALREQ types are not remapped !!
751  """
752 
753  alreadyUsedMappingNumbers = ddict(set)
754  for thr in self.l1menu.thresholds:
755  if thr.mapping<0:
756  continue
757  alreadyUsedMappingNumbers[thr.ttype].add(thr.mapping)
758 
759  nextFreeMapping = ddict(lambda: 0)
760  for k in alreadyUsedMappingNumbers:
761  nextFreeMapping[k] = 0
762  for thr in self.l1menu.thresholds():
763  if thr.mapping < 0:
764  while nextFreeMapping[thr.ttype] in alreadyUsedMappingNumbers[thr.ttype]:
765  nextFreeMapping[thr.ttype] += 1
766  log.debug('Setting mapping of threshold %s as %i', thr, nextFreeMapping[thr.ttype])
767  thr.mapping = nextFreeMapping[thr.ttype]
768  nextFreeMapping[thr.ttype] += 1
769 
770 
772  for (it_name, ps) in L1MenuFlags.prescales().items():
773  item = self.l1menu.getItem(it_name)
774  if item:
775  item.prescale = ps
776  else:
777  log.warning('Cannot find item %s to set the prescale', it_name )
778 
779 
780  def configureCTP(self):
781  self.l1menu.ctp.addMonCounters()
782 
783  # remove prescale suffixes
784  def _getMenuBaseName(self, menuName):
785  pattern = re.compile(r'_v\d+|DC14')
786  patternPos = pattern.search(menuName)
787  if patternPos:
788  menuName=menuName[:patternPos.end()]
789  else:
790  log.info('Can\'t find pattern to shorten menu name, either non-existent in name or not implemented.')
791  return menuName
792 
python.L1.L1MenuConfig.L1MenuConfig.getDefinedThresholds
def getDefinedThresholds(self)
Definition: L1MenuConfig.py:112
python.L1.L1MenuConfig.L1MenuConfig.configureCTP
def configureCTP(self)
Definition: L1MenuConfig.py:780
python.L1.L1MenuConfig.L1MenuConfig.registerThreshold
def registerThreshold(self, thr)
Definition: L1MenuConfig.py:137
python.L1.L1MenuConfig.L1MenuConfig.updateItemPrescales
def updateItemPrescales(self)
Definition: L1MenuConfig.py:771
runLayerRecalibration.chain
chain
Definition: runLayerRecalibration.py:175
vtune_athena.format
format
Definition: vtune_athena.py:14
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
python.L1.Base.L1Menu2JSON.L1MenuJSONConverter
Definition: L1Menu2JSON.py:7
python.L1.L1MenuConfig.L1MenuConfig.menuFilesToLoad
menuFilesToLoad
Definition: L1MenuConfig.py:45
python.L1.L1MenuConfig.L1MenuConfig.mapThresholds
def mapThresholds(self)
Definition: L1MenuConfig.py:744
python.L1.Base.Thresholds.TopoThreshold
Definition: Trigger/TriggerCommon/TriggerMenuMT/python/L1/Base/Thresholds.py:1196
python.L1.L1MenuConfig.L1MenuConfig._registeredTopoAlgos
_registeredTopoAlgos
Definition: L1MenuConfig.py:60
python.L1.L1MenuConfig.L1MenuConfig._importMenuDefinition
def _importMenuDefinition(self)
Definition: L1MenuConfig.py:259
python.L1.L1MenuConfig.L1MenuConfig._getSortingAlgoThatProvides
def _getSortingAlgoThatProvides(self, input, topoAlgCategory)
Definition: L1MenuConfig.py:354
python.L1.L1MenuConfig.L1MenuConfig.generated
generated
Definition: L1MenuConfig.py:49
python.L1.Base.BunchGroupSet.createDefaultBunchGroupSet
def createDefaultBunchGroupSet(flags)
Definition: BunchGroupSet.py:27
python.L1.L1MenuConfig.L1MenuConfig.registerItem
def registerItem(self, name, item)
Items.
Definition: L1MenuConfig.py:207
python.L1.L1MenuConfig.L1MenuConfig._addThrToRegistry
def _addThrToRegistry(self, thr)
Definition: L1MenuConfig.py:147
python.L1.L1MenuConfig.L1MenuConfig.registeredItems
registeredItems
Definition: L1MenuConfig.py:52
python.Bindings.values
values
Definition: Control/AthenaPython/python/Bindings.py:797
covarianceTool.filter
filter
Definition: covarianceTool.py:514
python.L1.L1MenuConfig.L1MenuConfig._registerTopoOutputsAsThresholds
def _registerTopoOutputsAsThresholds(self)
Definition: L1MenuConfig.py:172
python.L1.L1MenuConfig.L1MenuConfig._registeredThresholds
_registeredThresholds
Definition: L1MenuConfig.py:55
python.L1.L1MenuConfig.L1MenuConfig._generate
def _generate(self, flags)
Definition: L1MenuConfig.py:76
python.L1.L1MenuConfig.L1MenuConfig.currentAlgoDef
currentAlgoDef
Definition: L1MenuConfig.py:125
convertTimingResiduals.sum
sum
Definition: convertTimingResiduals.py:55
python.L1.L1MenuConfig.L1MenuConfig._generateTopoMenu
def _generateTopoMenu(self)
Definition: L1MenuConfig.py:396
python.L1.L1MenuConfig.L1MenuConfig._registerDefinedConfigurationObjects
def _registerDefinedConfigurationObjects(self)
Definition: L1MenuConfig.py:304
python.L1.L1MenuConfig.L1MenuConfig.thresholdExists
def thresholdExists(self, thrName)
Definition: L1MenuConfig.py:96
plotBeamSpotVxVal.range
range
Definition: plotBeamSpotVxVal.py:195
add
bool add(const std::string &hname, TKey *tobj)
Definition: fastadd.cxx:55
python.L1.L1MenuConfig.L1MenuConfig._registeredThresholdsStats
_registeredThresholdsStats
Definition: L1MenuConfig.py:56
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
python.L1.L1MenuConfig.L1MenuConfig.getRegisteredItem
def getRegisteredItem(self, name)
Definition: L1MenuConfig.py:215
DerivationFramework::TriggerMatchingUtils::sorted
std::vector< typename T::value_type > sorted(T begin, T end)
Helper function to create a sorted vector from an unsorted one.
python.L1.L1MenuConfig.L1MenuConfig.__init__
def __init__(self, flags, inputFile=None)
Definition: L1MenuConfig.py:40
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
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:79
python.L1.L1MenuConfig.L1MenuConfig.menuName
menuName
Definition: L1MenuConfig.py:46
LArNewCalib_Delay_OFC_Cali.check
check
Definition: LArNewCalib_Delay_OFC_Cali.py:208
python.L1.L1MenuConfig.L1MenuConfig.l1menu
l1menu
Definition: L1MenuConfig.py:66
python.L1.L1MenuConfig.L1MenuConfig._getMenuBaseName
def _getMenuBaseName(self, menuName)
Definition: L1MenuConfig.py:784
python.L1.L1MenuConfig.L1MenuConfig._menuToLoad
def _menuToLoad(self, silent=False)
Definition: L1MenuConfig.py:233
dqt_zlumi_pandas.update
update
Definition: dqt_zlumi_pandas.py:42
CaloLCW_tf.group
group
Definition: CaloLCW_tf.py:28
python.L1.L1MenuConfig.L1MenuConfig.getDefinedThreshold
def getDefinedThreshold(self, name)
Definition: L1MenuConfig.py:99
python.L1.L1MenuConfig.L1MenuConfig._extendInformation
def _extendInformation(self)
Definition: L1MenuConfig.py:379
python.L1.Base.L1Menu.L1Menu
Definition: L1Menu.py:19
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
python.L1.L1MenuConfig.L1MenuConfig._getTopoAlgo
def _getTopoAlgo(self, algoName, category)
Definition: L1MenuConfig.py:345
python.L1.L1MenuConfig.L1MenuConfig
Definition: L1MenuConfig.py:38
pickleTool.object
object
Definition: pickleTool.py:30
str
Definition: BTagTrackIpAccessor.cxx:11
python.Bindings.keys
keys
Definition: Control/AthenaPython/python/Bindings.py:790
python.L1.L1MenuConfig.L1MenuConfig._generateMenu
def _generateMenu(self, flags)
Definition: L1MenuConfig.py:503
python.L1.L1MenuConfig.L1MenuConfig.registerTopoAlgo
def registerTopoAlgo(self, algo)
registration of available components
Definition: L1MenuConfig.py:122
python.L1.L1MenuConfig.L1MenuConfig._checkMenuExistence
def _checkMenuExistence(self)
Definition: L1MenuConfig.py:249
python.L1.L1MenuConfig.L1MenuConfig.inputFile
inputFile
Definition: L1MenuConfig.py:47
python.L1.L1MenuConfig.L1MenuConfig.l1menuFromFile
l1menuFromFile
Definition: L1MenuConfig.py:48
python.L1.L1MenuConfig.L1MenuConfig.menuFullName
menuFullName
Definition: L1MenuConfig.py:44
python.L1.L1MenuConfig.L1MenuConfig.writeJSON
def writeJSON(self, outputFile, bgsOutputFile=None, destdir="./")
Definition: L1MenuConfig.py:221