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