59 def __init__(self, flags: AthConfigFlags, inputFile: Path |
None =
None):
70 L1MenuFlags.CTPVersion = 4
76 log.error(
"Generating L1 menu %s is not possible", self.
menuInfo.menuBaseName)
77 raise RuntimeError(
"Generating L1 menu is not possible, menu file does not exist")
127 """Resolve the menu name to the actual menu to be used based from the mapping above.
131 menuBaseName = fullMenuName
132 if fullMenuName.endswith(
'prescale'):
134 if (m := re.match(
r'\w*_v\d*', fullMenuName))
is not None:
135 menuBaseName = m.group(0)
137 if (menuInfo := menuMap.get(menuBaseName))
is not None:
138 menuFile, menuInputFile, _ = (menuInfo + [
"",
""])[:3]
140 menuFile = menuBaseName
141 menuInputFile = menuFile +
"_inputs"
143 menuPurpose = MenuMetaInfo.MenuType.PHYSICS
144 if "MC_" in menuBaseName:
145 menuPurpose = MenuMetaInfo.MenuType.MC
146 elif "Dev_" in menuBaseName:
147 menuPurpose = MenuMetaInfo.MenuType.DEV
148 elif "HI_" in menuBaseName:
149 menuPurpose = MenuMetaInfo.MenuType.HI
150 elif "AllCTPIn_" in menuBaseName:
151 menuPurpose = MenuMetaInfo.MenuType.ALLCTPIN
154 moduleName =
'TriggerMenuMT.L1.Menu.Menu_%s' % menuFile
155 if not moduleExists(moduleName):
156 log.info(
"Could not find menu definition for %s (module %s does not exist)", fullMenuName, moduleName)
157 raise ModuleNotFoundError(f
"Could not find menu definition for {fullMenuName}")
159 return MenuMetaInfo(fullMenuName, menuBaseName=menuBaseName,
160 menuFile=menuFile, menuInputFile=menuInputFile,
161 menuPurpose=menuPurpose)
211 Register all L1Global triggers that are available as allowed input to the menu
217 if isinstance(algo, GlobalMultiplicityAlgo):
219 outputLines += algo.output()
if (isinstance(algo.output(), list))
else [algo.output()]
220 _globalTriggers = sorted(outputLines)
221 log.info(
"... found %i global triggerlines", len(_globalTriggers))
222 log.debug(
"%r", _globalTriggers)
224 multibitPattern = re.compile(
r"(?P<line>.*)\[(?P<bit>\d+)\]")
225 multibitTopoTriggers =
set()
226 for topoLineName
in _globalTriggers:
227 m = multibitPattern.match(topoLineName)
229 topoThrName = m.groupdict()[
'line']
230 multibitTopoTriggers.add(topoThrName)
232 topoThrName = topoLineName
235 for topoThrName
in multibitTopoTriggers:
250 def writeJSON(self, outputFile, bgsOutputFile=None, destdir: Path = Path(
"./")):
252 outputFile = destdir / outputFile
253 if bgsOutputFile
is not None:
254 bgsOutputFile = destdir / bgsOutputFile
256 bgsOutputFile=bgsOutputFile).
writeJSON(pretty=
True)
257 return outputFile, bgsOutputFile
259 log.error(
"No menu was generated, can not create json file")
273 Defines the list if item and threshold names that will be in the menu
274 Calls defineMenu() of the correct module 'Menu_<menuname>.py'
275 Menu.defineMenu() defines the menu via L1MenuFlags "items", "thresholds",
279 log.info(
"Reading TriggerMenuMT.Menu.Menu_%s", self.
menuInfo.menuFile)
280 menumodule = __import__(
'TriggerMenuMT.L1.Menu.Menu_%s' % self.
menuInfo.menuFile, globals(), locals(), [
'defineMenu'], 0)
281 menumodule.defineMenu()
282 log.info(
"... L1 menu '%s' contains %i items", self.
menuInfo.menuFile, len(L1MenuFlags.items()))
283 if log.getEffectiveLevel() <= logging.DEBUG:
284 log.debug(
"Items: %s",
', '.join(L1MenuFlags.items()))
286 log.info(
"Importing input definition from TriggerMenuMT.L1.Menu.Menu_%s", self.
menuInfo.menuInputFile)
287 topomenumodule = __import__(
'TriggerMenuMT.L1.Menu.Menu_%s' % self.
menuInfo.menuInputFile, globals(), locals(), [
'defineMenu'], 0)
288 topomenumodule.defineInputsMenu()
291 for _, boardDef
in L1MenuFlags.boards().items():
292 if "connectors" in boardDef:
293 connectorCount += len(boardDef[
"connectors"])
294 for c
in boardDef[
"connectors"]:
295 if "thresholds" in c:
296 algoCount += len(c[
"thresholds"])
297 elif "algorithmGroups" in c:
298 for t
in c[
"algorithmGroups"]:
299 algoCount += len(t[
"algorithms"])
301 for t
in c[
"signalGroups"]:
302 algoCount += len(t[
"signals"])
303 log.info(
" with %i connectors and %i input signals", connectorCount, algoCount)
307 Registers the list if items and thresholds that could be used in the menu
308 Calls registerItem() of the correct module 'ItemDef.py'
310 MenuItem.setMenuConfig(self)
311 Threshold.setMenuConfig(self)
314 defFile =
"TriggerMenuMT.L1.Config.GlobalAlgoDef"
315 log.info(
"Importing %s", defFile)
317 import_module(defFile).__getattribute__(
'GlobalAlgoDef').registerGlobalAlgos(self)
318 except ImportError
as ie:
319 log.fatal(
"No global algorithm definition file found. %s", ie.msg)
321 log.info(
"... registered %i global algorithms for the L1Global",
324 log.info(
"Importing TriggerMenuMT.Config.ThresholdDefRun4")
325 from .Config.ThresholdDefRun4
import ThresholdDef
326 ThresholdDef.registerThresholds(self, self.
menuFullName)
328 log.info(
"Turning global algorithm outputs into thresholds (except multiplicity counters)")
333 log.info(
"Registering items from TriggerMenuMT.Config.ItemDefRun4")
334 ItemDefRun4.registerItems(self, self.
menuInfo)
401 boardDef: dict[str, Any] = L1MenuFlags.boards().
get(boardName, {})
408 for connDef
in boardDef[
"connectors"]:
409 for algGrp
in connDef[
"algorithmGroups"]:
410 for topodef
in algGrp[
"algorithms"]:
412 nLines += len(topodef.outputlines)
414 outputlines = list(dict.fromkeys(
map(
lambda x: re.split(
r"\[\d\]", x)[0], topodef.outputlines)))
415 for lineName
in outputlines:
419 msg =
'Global threshold %s is required in Global2CTP connector %s (file L1/Menu/Menu_%s.py), but it is not registered. ' % (thrName, connDef[
'name'], self.
menuInfo.menuInputFile)
420 msg +=
'Please add the threshold output %s to L1/Config/ThresholdDefRun4.py or L1/Config/GlobalHypoAlgoDef.py.' % (thrName.split(
'_', 1)[-1])
422 raise RuntimeError(msg)
423 self.
l1menu.addThreshold(thr)
424 log.info(
"Generating global menu using %i global algorithms with %i trigger lines", nAlgos, nLines)
431 for connDef
in boardDef[
"connectors"]:
436 if connDef[
"format"] ==
'multiplicity':
437 for thrName
in connDef[
"thresholds"]:
440 nBits = connDef[
"nbitsDefault"]
441 if type(thrName)
is tuple:
442 (thrName, nBits) = thrName
445 algoname =
"Mult_" + thrName
446 algoNames += [algoname]
447 algoNbits += [int(nBits)]
449 elif connDef[
"format"] ==
'topological':
450 for algGrp
in connDef[
"algorithmGroups"]:
451 for topodef
in algGrp[
"algorithms"]:
452 algoNames += [topodef.algoname]
454 fpgaNames += [str(algGrp[
'fpga'])]
455 for algoName, algoBits, fpgaName
in zip(algoNames, algoNbits, fpgaNames):
459 if algoBits != algo.nbits:
460 msg =
"Algorithm %s defined with %i bits, but the associated threshold has %i bits " % (algo.name, algo.nbits, algoBits)
461 raise RuntimeError(msg)
462 self.
l1menu.checkBoardInputs(algo, connDef[
"name"], fpgaName)
464 self.
l1menu.addGlobalAlgo(algo)
468 if len(self.
l1menu.items) > 0:
469 log.info(
"L1MenuConfig.generate() has already been called. Will ignore")
473 Generates the menu structure from the list of item and threshold names in the L1MenuFlags
479 from .Base.BunchGroupSet
import createDefaultBunchGroupSet
480 self.
l1menu.ctp.bunchGroupSet = createDefaultBunchGroupSet(flags)
485 allBoards = (list(L1MenuFlags.boards().items()) + list(L1MenuFlags.legacyBoards().items()))
487 if self.
menuInfo.menuPurpose == MenuMetaInfo.MenuType.ALLCTPIN:
491 ItemDef.registerItems_AllCTPIn(self)
493 for (boardName, boardDef)
in L1MenuFlags.legacyBoards().items():
494 for connDef
in boardDef[
"connectors"]:
496 if connDef[
"type"] ==
"ctpin" and connDef[
"format"] ==
"multiplicity":
497 self.
l1menu.checkL1CaloThresholds(connDef[
"thresholds"], boardName, connDef[
"name"])
499 list_of_undefined_thresholds = []
501 for (boardName, boardDef)
in L1MenuFlags.boards().items():
502 for connDef
in boardDef[
"connectors"]:
503 if connDef[
"type"] ==
"ctpin" or connDef[
"format"] !=
"multiplicity":
505 for thrName
in connDef[
"thresholds"]:
506 if type(thrName)
is tuple:
507 (thrName, _) = thrName
508 if (thrName
is None)
or (thrName
in self.
l1menu.thresholds):
511 if threshold
is None:
512 log.error(
'Threshold %s is required in menu on board %s, connector %s, but it is not defined',
513 thrName, boardName, connDef[
'name'])
514 list_of_undefined_thresholds += [thrName]
516 self.
l1menu.addThreshold(threshold)
518 zbThrName = connDef[
"zeroBias"]
521 log.error(
'Zero bias threshold %s is listed in menu but not defined', zbThrName)
522 list_of_undefined_thresholds += [zbThrName]
524 self.
l1menu.addThreshold(zbThr)
529 for (boardName, boardDef)
in L1MenuFlags.boards().items():
530 for connDef
in boardDef[
"connectors"]:
531 if connDef[
"format"] !=
"simple":
533 for sGrp
in connDef[
"signalGroups"]:
534 for thrName
in sGrp[
"signals"]:
535 if type(thrName)
is tuple:
536 (thrName, _) = thrName
537 if thrName
is None or thrName
in self.
l1menu.thresholds:
540 if threshold
is None:
541 log.error(
'Threshold %s is required in menu on board %s, connector %s, but it is not defined',
542 thrName, boardName, connDef[
'name'])
543 list_of_undefined_thresholds += [thrName]
545 self.
l1menu.addThreshold(threshold)
548 for (_, boardDef)
in allBoards:
549 for connDef
in boardDef[
"connectors"]:
550 if connDef[
"type"] !=
"ctpin":
552 for entry
in connDef[
"thresholds"]:
554 if type(entry)
is dict:
556 thrNames = sum([x.outputlines
for x
in entry[
"algorithms"]], [])
557 elif type(entry)
is str:
559 elif type(entry)
is tuple:
560 thrNames = [entry[0]]
562 for thrName
in thrNames:
563 if thrName
is None or thrName
in self.
l1menu.thresholds:
566 if threshold
is None:
567 log.error(
'Threshold %s is listed in menu but not defined', thrName)
568 list_of_undefined_thresholds += [thrName]
570 self.
l1menu.addThreshold(threshold)
572 zbThrName = connDef[
"zeroBias"]
575 log.error(
'Zero bias threshold %s is listed in menu but not defined', zbThrName)
576 list_of_undefined_thresholds += [zbThrName]
578 self.
l1menu.addThreshold(zbThr)
582 if len(list_of_undefined_thresholds) > 0:
583 raise RuntimeError(
"Found undefined threshold in menu %s, please add these thresholds to l1menu/ThresholdDef.py: %s" %
584 (self.
l1menu.menuName,
', '.join(list_of_undefined_thresholds)))
591 ctpIdMap = L1MenuFlags.CtpIdMap()
592 for itemName
in L1MenuFlags.items():
594 if registeredItem
is None:
595 msg = f
"L1 item '{itemName}' has not been defined in L1/Config/ItemDef{'Run4' if L1MenuFlags.Run() == 4 else ''}.py"
597 raise RuntimeError(msg)
599 if itemName
in ctpIdMap:
600 newCTPID = ctpIdMap[itemName]
601 registeredItem.setCtpid(newCTPID)
603 for thrName
in registeredItem.thresholdNames():
604 if thrName
not in self.
l1menu.thresholds:
606 f
"L1 item {itemName} has been added to the menu L1/Menu/Menu_{self.menuInfo.menuFile}.py, "
607 f
"but the required threshold {thrName} is not listed as input in L1/Menu/Menu_{self.menuInfo.menuInputFile}.py"
610 raise RuntimeError(msg)
612 itemsForMenu += [registeredItem]
615 assigned_ctpids =
set([item.ctpid
for item
in itemsForMenu])
616 available_ctpids = sorted(list(
set(range(Limits.MaxTrigItems)) - assigned_ctpids), reverse=
True)
619 for item
in itemsForMenu:
621 if not item.name.startswith(
'L1_CALREQ'):
622 item.setTriggerType(item.trigger_type | TT.phys)
625 if len(available_ctpids) == 0:
626 raise RuntimeError(
"No more CTP IDs available at L1!!")
627 item.setCtpid(available_ctpids.pop())
635 for (_, boardDef)
in allBoards:
636 for connDef
in boardDef[
"connectors"]:
637 self.
l1menu.addConnector(connDef)
643 for (_, boardDef)
in allBoards:
644 self.
l1menu.addBoard(boardDef)
649 legacyThresholdsSet =
set()
650 for conn
in self.
l1menu.connectors:
651 if not conn.isLegacy():
653 legacyThresholdsSet.update(conn.triggerThresholds())
654 for item
in self.
l1menu.items:
655 item.markLegacy(legacyThresholdsSet)
666 self.
l1menu.setupCTPMonitoring()
678 if 'pp' in self.
l1menu.menuName:
679 self.
l1menu.checkLegacyThresholds()
683 TopoAlgoDefMultiplicity.checkMultAlgoFWconstraints(self.
l1menu)
686 self.
l1menu.checkCountCTPInputsOutput()
689 self.
l1menu.checkCTPINconnectors()
692 self.
l1menu.checkPerfThresholds()
695 self.
l1menu.checkItemsHaveInputs()
698 self.
l1menu.checkTOPObits()
702 self.
l1menu.checkHFmonitoring()
706 Set the correct mapping of thresholds according to the
707 order it was given in L1MenuFlags.thresholds list. That list
708 is usually defined in the setupMenu function of each menu
710 NIM and CALREQ types are not remapped !!
713 alreadyUsedMappingNumbers = ddict(set)
714 for thr
in self.
l1menu.thresholds:
717 alreadyUsedMappingNumbers[thr.ttype].
add(thr.mapping)
719 nextFreeMapping = ddict(
lambda: 0)
720 for k
in alreadyUsedMappingNumbers:
721 nextFreeMapping[k] = 0
722 for thr
in self.
l1menu.thresholds():
724 while nextFreeMapping[thr.ttype]
in alreadyUsedMappingNumbers[thr.ttype]:
725 nextFreeMapping[thr.ttype] += 1
726 log.debug(
'Setting mapping of threshold %s as %i', thr, nextFreeMapping[thr.ttype])
727 thr.mapping = nextFreeMapping[thr.ttype]
728 nextFreeMapping[thr.ttype] += 1