ATLAS Offline Software
L1Menu.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2 
3 from .CTP import CTP
4 from .Items import MenuItemsCollection
5 from .Thresholds import MenuThresholdsCollection
6 from .TopoAlgorithms import MenuTopoAlgorithmsCollection, AlgType, AlgCategory
7 from .Boards import MenuBoardsCollection
8 from .Connectors import MenuConnectorsCollection, CType
9 from .MenuUtils import get_smk_psk_Name
10 from .Limits import Limits
11 from .L1MenuFlags import L1MenuFlags
12 from .ThresholdType import ThrType
13 from ..Config.TypeWideThresholdConfig import getTypeWideThresholdConfig
14 
15 from AthenaCommon.Logging import logging
16 log = logging.getLogger(__name__)
17 
18 class L1Menu(object):
19  """
20  This class holds everything that is needed to define the menu
21  """
22 
23  def __init__(self, menuName, flags):
24  self.menuName = menuName
25 
26  self.menuFullName = L1MenuFlags.MenuSetup()
27 
28  # items in menu
30 
31  # store cached flags
32  self.flags = flags
33 
34  # all thresholds that are in menu (new and legacy)
36 
37  # all thresholds that are in menu (new and legacy)
39 
40  # all connectors between legacyCalo, muctpi, topo and the CTPIN/CTPCORE
42 
43  # board definition
45 
46  # CTP Info in the menu
47  self.ctp = CTP()
48 
49  if self.menuName:
50  smk_psk_Name = get_smk_psk_Name(self.menuName)
51  self.items.menuName = smk_psk_Name["smkName"]
52  self.items.pssName = smk_psk_Name["pskName"]
53 
54 
55  def setBunchGroupSplitting(self, v = True):
56  MenuItemsCollection.splitBunchGroups = v
57 
58 
59  def addItem(self, item):
60  self.items += item
61 
62 
63  def getItem(self,name):
64  return self.items.findItemByName(name)
65 
66 
67  def addThreshold(self, threshold):
68  self.thresholds += threshold
69 
70 
71  def addTopoAlgo(self, algo, category):
72  algo.setThresholds( self.thresholds ) # each algo gets a pointer to the full thresholds definition (for the extrainfo)
73  self.topoAlgos.addAlgo(algo, category)
74 
75 
76  def addBoard(self, boardDef):
77  return self.boards.addBoard(boardDef)
78 
79 
80  def addConnector(self, connDef):
81  self.connectors.addConnector(connDef)
82 
83 
84  def setupCTPMonitoring(self):
85  self.ctp.setupMonitoring(self.menuName, self.items, self.thresholds, self.connectors, self.menuFullName)
86 
87  def check(self):
88  log.info("Doing L1 Menu checks")
89  from collections import defaultdict as dd
90  missing = dd(list)
91  allThresholds = set([thr.name for thr in self.thresholds])
92  allUsedThresholds = set()
93  for item in self.items:
94  for thrName in item.thresholdNames():
95  if 'SPARE' in thrName:
96  raise RuntimeError("CTP input %s is used by %s but SPARE thresholds are not to be used!" %(thrName, item) )
97  if thrName not in allThresholds:
98  missing[thrName].append(item.name)
99  else:
100  allUsedThresholds.add(thrName)
101 
102  for thrName in sorted(missing.keys()):
103  log.warning("Threshold %s (used by %s) is not defined in the menu", thrName,",".join(missing[thrName]))
104 
105  if len(allThresholds)-len(allUsedThresholds)>0:
106  unusedThresholds = allThresholds.difference(allUsedThresholds)
107  log.debug("The following thresholds are unused")
108  log.debug("MU: %s", ", ".join([thr for thr in unusedThresholds if thr.startswith("MU")]))
109  log.debug("EM: %s", ", ".join([thr for thr in unusedThresholds if thr.startswith("EM")]))
110  log.debug("HA: %s", ", ".join([thr for thr in unusedThresholds if thr.startswith("HA")]))
111  log.debug("J: %s", ", ".join([thr for thr in unusedThresholds if thr.startswith("J")]))
112  log.debug("eFEX: %s", ", ".join([thr for thr in unusedThresholds if thr.startswith("e")]))
113  log.debug("jFEX: %s", ", ".join([thr for thr in unusedThresholds if thr.startswith("j")]))
114  log.debug("cTAU: %s", ", ".join([thr for thr in unusedThresholds if thr.startswith("cTAU")]))
115  log.debug("gFEX: %s", ", ".join([thr for thr in unusedThresholds if thr.startswith("g")]))
116 
118  from collections import defaultdict as dd
119  from ..Menu.LegacyMenuThresholds import legacyThresholds
120  extraThresholds = dd(list)
121  for item in self.items:
122  for thrName in item.thresholdNames():
123  if thrName[:3]=='ZB_':
124  thrName = thrName[3:]
125  if thrName[0] not in ('e','j','g', 'c') and thrName[:2] not in ["MU"] and "TOPO" not in thrName[:4]:
126  if thrName not in legacyThresholds:
127  extraThresholds[thrName].append(item.name)
128 
129  for thrName in sorted(extraThresholds.keys()):
130  log.warning("Threshold %s (used by %s) should not be used!", thrName,",".join(extraThresholds[thrName]))
131 
133  if 'MC' not in self.menuName:
134  from collections import defaultdict as dd
135  perfThresholds = dd(list)
136  for item in self.items:
137  for thrName in item.thresholdNames():
138  if 'Perf' in thrName:
139  perfThresholds[thrName].append(item.name)
140  for thrName in sorted(perfThresholds.keys()):
141  raise RuntimeError("Threshold %s (used by %s) should not be used!", thrName,",".join(perfThresholds[thrName]))
142 
143  def checkBoardInputs(self, algo, connDefName, fpgaName ):
144  if 'MuCTPi' in connDefName or 'Legacy' in connDefName:
145  return
146 
147  boardName = connDefName+fpgaName
148 
149  allowedInputs = {}
150  allowedInputs['Topo1Opt0'] = ['MU', 'eEM', 'eTAU', 'gJ', 'gLJ', 'ZeroBiasA'] # TOPO1A, FPGA1
151  allowedInputs['Topo1Opt1'] = ['MU', 'eEM', 'eTAU', 'gJ', 'gLJ', ] # TOPO1A, FPGA2
152  allowedInputs['Topo1Opt2'] = ['MU', 'eTAU', 'cTAU', 'j', 'gXE', 'gTE', 'gMHT'] # TOPO1B, FPGA1
153  allowedInputs['Topo1Opt3'] = ['MU', 'eTAU', 'cTAU', 'j', 'gXE', 'gTE', 'gMHT', 'LArSaturation', 'ZeroBiasB'] # TOPO1B, FPGA2
154  allowedInputs['Topo2El0'] = ['MU', 'eTAU', 'j', ] # TOPO2, FPGA1
155  allowedInputs['Topo2El1'] = [ 'eEM', 'j', ] # TOPO2, FPGA2
156  allowedInputs['Topo3El0'] = [ 'eEM', 'eTAU', 'j', ] # TOPO3, FPGA1
157  allowedInputs['Topo3El1'] = ['MU', 'eEM', 'eTAU', 'g', ] # TOPO3, FPGA2
158 
159  if boardName not in allowedInputs.keys():
160  raise RuntimeError("Connector name %s not found" % boardName )
161 
162  if 'Mult_' in algo.name:
163  if not (any(x in algo.threshold for x in allowedInputs[boardName])):
164  raise RuntimeError("Algorithm %s in board %s with threshold %s not allowed" % (algo.name, boardName, algo.threshold ))
165 
166  if 'Mult_' not in algo.name:
167  for algoInput in algo.inputs:
168  if not (any(x in algoInput for x in allowedInputs[boardName])):
169  raise RuntimeError("Algorithm %s in board %s with input %s not allowed" % (algo.name, boardName, algoInput ))
170 
171  def checkL1CaloThresholds(self, thresholds, boardName, connName):
172  fullName = boardName + connName
173 
174  allowedInputs = {}
175  allowedInputs['Ctpin7EM1'] = 8*['EM']
176  allowedInputs['Ctpin7EM2'] = 8*['EM']
177  allowedInputs['Ctpin7TAU1'] = 8*['HA']
178  allowedInputs['Ctpin7TAU2'] = 8*['HA']
179 
180  allowedInputs['Ctpin8JET1'] = 10*['J'] # 3-bit JET
181  allowedInputs['Ctpin8JET2'] = 15*['J'] # 2-bit JET
182  allowedInputs['Ctpin8EN1'] = 8*['TE'] + 8*['XE'] + 8*['XS']
183  allowedInputs['Ctpin8EN2'] = 8*['TE'] + 8*['XE']
184 
185  invalidThresholds = False
186  for ithr,thr in enumerate(thresholds):
187  try:
188  allowedThr = allowedInputs[fullName][ithr]
189  if thr[:len(allowedThr)] != allowedThr:
190  log.error(f"Threshold {thr} does not match expected type {allowedThr} at position {ithr} in connector {fullName}")
191  invalidThresholds = True
192  except IndexError:
193  log.error(f"Too many thresholds ({len(thresholds)}) provided for connector {fullName}, which only supports {len(allowedInputs[fullName])} thresholds")
194  invalidThresholds = True
195  if invalidThresholds:
196  raise RuntimeError("Incorrect specification of legacy L1Calo thresholds")
197 
199  for conn in self.connectors:
200  if conn.ctype == CType.CTPIN:
201  if len(conn.triggerLines)>31:
202  raise RuntimeError("Too many CTP inputs in %s: %i but a max of 31 are allowed" %(conn.name,len(conn.triggerLines)))
203 
204  def checkTOPObits(self):
205  import re
206  pattern=r"topo[1-3](e|$)"
207  for conn in self.connectors:
208  flatindexs = []
209  if re.search(pattern, conn.name.lower()):
210  for tl in conn.triggerLines:
211  for thr in conn.triggerLines[tl]:
212  for thrname in conn.triggerLines[tl][thr]:
213  if thrname.flatindex not in flatindexs:
214  flatindexs.append(thrname.flatindex)
215  else:
216  log.error("TOPO connector %s has duplicate flatindex %i", conn.name, thrname.flatindex)
217  raise RuntimeError("Duplicate flatindex found in TOPO algorithm")
218 
219 
221  from collections import namedtuple
222  ctpInput = namedtuple('ctpInput',"name, conn, nbit")
223  ctpInputs = []
224  ctpUnusedInputs = []
225  ctpOutputs = []
226  thrNames = []
227  ctpInputBitSets = dict()
228  ctpInputNameSets = dict()
229  ctpUnusedInputBitSets = dict()
230  ctpUnusedInputNameSets = dict()
231  for item in self.items:
232  ctpOutputs.append(item.name)
233  for thrName in item.thresholdNames():
234  if thrName[:3]=='ZB_':
235  thrName = thrName[3:]
236  if thrName not in thrNames:
237  thrNames.append(thrName)
238  thrNames_notFound = []
239  for thrName in thrNames:
240  thrName_found = False
241  for conn in self.connectors:
242  if conn.ctype != CType.ELEC:
243  for tl in conn.triggerLines:
244  if thrName == tl.name:
245  ctpInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
246  thrName_found = True
247  else:
248  for fpga in conn.triggerLines:
249  for clock in conn.triggerLines[fpga]:
250  for tl in conn.triggerLines[fpga][clock]:
251  if thrName == tl.name:
252  ctpInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
253  thrName_found = True
254  if not thrName_found:
255  thrNames_notFound.append(thrName)
256 
257  for conn in self.connectors:
258  if conn.ctype != CType.ELEC:
259  for tl in conn.triggerLines:
260  thrName = tl.name
261  if thrName[:3]=='ZB_':
262  thrName = thrName[3:]
263  usedInput = False
264  for ctpIn in ctpInputs:
265  if thrName == ctpIn.name:
266  usedInput = True
267  if not usedInput:
268  ctpUnusedInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
269  else:
270  for fpga in conn.triggerLines:
271  for clock in conn.triggerLines[fpga]:
272  for tl in conn.triggerLines[fpga][clock]:
273  thrName = tl.name
274  if thrName[:3]=='ZB_':
275  thrName = thrName[3:]
276  usedInput = False
277  for ctpIn in ctpInputs:
278  if thrName == ctpIn.name:
279  usedInput = True
280  if not usedInput:
281  ctpUnusedInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
282 
283  if len(thrNames_notFound)>0:
284  log.error("Thresholds [%s] are not found", ",".join(thrNames_notFound))
285  log.error("Input thresholds are [%s]", ",".join([ input.name for input in ctpInputs]))
286  raise RuntimeError("Not all input thresholds found!")
287 
288  for ctpIn in ctpInputs:
289  thrset = None
290  thrName = ctpIn.name
291  if thrName[:2] in ['EM','HA','XE','TE','XS']:
292  thrset = 'legacyCalo'
293  elif thrName[:1]=='J':
294  thrset = 'legacyCalo'
295  elif thrName[:2]=='MU':
296  thrset = 'muon'
297  elif thrName[:3] in ['MBT','AFP','BCM','CAL','NIM','ZDC','BPT','LUC','BMA']:
298  thrset = 'detector'
299  elif thrName[:6]=='R2TOPO':
300  thrset = 'legacyTopo'
301  elif thrName[:1] in ['e','j','c','g']:
302  thrset = 'topo1'
303  elif thrName[:4]=='TOPO':
304  if 'Topo2' in ctpIn.conn:
305  thrset = 'topo2'
306  elif 'Topo3' in ctpIn.conn:
307  thrset = 'topo3'
308 
309  if thrset not in ctpInputBitSets:
310  ctpInputBitSets[thrset] = 0
311  ctpInputNameSets[thrset] = []
312  if thrName not in ctpInputNameSets[thrset]:
313  ctpInputNameSets[thrset].append(thrName)
314  ctpInputBitSets[thrset] += ctpIn.nbit
315 
316  for ctpIn in ctpUnusedInputs:
317  thrset = None
318  thrName = ctpIn.name
319  if thrName[:2] in ['EM','HA','XE','TE','XS']:
320  thrset = 'legacyCalo'
321  elif thrName[:1]=='J':
322  thrset = 'legacyCalo'
323  elif thrName[:2]=='MU':
324  thrset = 'muon'
325  elif thrName[:3] in ['MBT','AFP','BCM','CAL','NIM','ZDC','BPT','LUC']:
326  thrset = 'detector'
327  elif thrName[:6]=='R2TOPO':
328  thrset = 'legacyTopo'
329  elif thrName[:1] in ['e','j','c','g']:
330  thrset = 'topo1'
331  elif thrName[:4]=='TOPO':
332  if 'Topo2' in ctpIn.conn:
333  thrset = 'topo2'
334  elif 'Topo3' in ctpIn.conn:
335  thrset = 'topo3'
336 
337  if thrset not in ctpUnusedInputBitSets:
338  ctpUnusedInputBitSets[thrset] = 0
339  ctpUnusedInputNameSets[thrset] = []
340  if thrName not in ctpUnusedInputNameSets[thrset]:
341  ctpUnusedInputNameSets[thrset].append(thrName)
342  ctpUnusedInputBitSets[thrset] += ctpIn.nbit
343 
344  totalInputs = 0
345  log.info("Check total number of CTP input and output bits:")
346  log.info("Number of output bits: %i", len(ctpOutputs) )
347  for thrset in ctpInputBitSets:
348  log.info("Used inputs in %s: %i thresholds and %i bits", thrset, len(ctpInputNameSets[thrset]), ctpInputBitSets[thrset] )
349  if thrset is not None:
350  log.debug("Threshold set %s: %s", thrset, ",".join(ctpInputNameSets[thrset]) )
351  else:
352  log.info("Unrecognised CTP input bits: %s", ",".join(ctpInputNameSets[thrset]) )
353  totalInputs += ctpInputBitSets[thrset]
354  log.info("Number of used inputs bits: %i" , totalInputs )
355  totalUnusedInputs = 0
356  for thrset in ctpUnusedInputBitSets:
357  log.debug("Unused thresholds in %s: %i thresholds and %i bits", thrset, len(ctpUnusedInputNameSets[thrset]), ctpUnusedInputBitSets[thrset] )
358  if thrset is not None:
359  log.debug("Unused threshold set %s: %s", thrset, ",".join(ctpUnusedInputNameSets[thrset]) )
360  else:
361  log.debug("Unrecognised CTP input bits: %s", ",".join(ctpUnusedInputNameSets[thrset]) )
362  totalUnusedInputs += ctpUnusedInputBitSets[thrset]
363  log.debug("Number of un-used inputs bits: %i" , totalUnusedInputs )
364 
365  # Fail menu generation for menus going to P1:
366  if ( totalInputs > Limits.MaxTrigItems or len(ctpOutputs) > Limits.MaxTrigItems):
367  if 'AllCTPIn' in self.menuName:
368  log.warning(f"Input or output bits limit of {Limits.MaxTrigItems} exceeded in the dummy CTP menu -- OK")
369  else:
370  raise RuntimeError("Both the numbers of inputs and outputs need to be not greater than %i in a physics menu!" % Limits.MaxTrigItems)
371 
372  # Avoid that L1 item is defined only for BGRP0 as this include also the CALREQ BGRP2 (ATR-24781)
373  def checkBGRP(self):
374  for item in self.items:
375  if len(item.bunchGroups)==1 and item.bunchGroups[0]=='BGRP0':
376  raise RuntimeError("L1 item %s is defined with only BGRP0, ie it can trigger also in the CALREQ BGRP2 bunches. Please add another bunch group (ATR-24781)" % item.name)
377  if 'BGRP2' in item.bunchGroups:
378  thrtype = item.logic.content['threshold'].ttype
379  if thrtype in ThrType.CaloTypes():
380  # The LAr Digital Trigger sends an "align frame" to the FEXes in BCID 3500 (in BGRP2)
381  # No trigger can be sent during this align frame, so we block all calo triggers from this BGRP
382  raise RuntimeError(f"L1 item {item.name} with threshold type {thrtype} is in CALREQ BGRP2. This is not allowed!")
383 
384 
385  def checkPtMinToTopo(self):
386  # check that the ptMinToTopo for all types of thresholds is lower than the minimum Et cuts applied in multiplicity and decision algorithms
387 
388  # collect the ptMinToTopo values
389  ptMin = {}
390  for thrtype in ThrType.Run3Types():
391  ttconfig = getTypeWideThresholdConfig(thrtype, self.flags.Trigger.L1.Menu.doHeavyIonTobThresholds, self.flags.Trigger.L1.Menu.doeFexBDTTau)
392  inputtype = thrtype.name
393  if inputtype == 'cTAU':
394  inputtype = 'eTAU'
395  for key, value in ttconfig.items():
396  if "ptMinToTopo" in key:
397  if inputtype in ptMin:
398  if ptMin[inputtype] > value:
399  ptMin[inputtype] = value
400  else:
401  ptMin[inputtype] = value
402 
403  # loop over multiplicity algorithms and get the min et values
404  thresholdMin = {}
405  for algo in self.topoAlgos.topoAlgos[AlgCategory.MULTI][AlgType.MULT]:
406  alg = self.topoAlgos.topoAlgos[AlgCategory.MULTI][AlgType.MULT][algo]
407  threshold = alg.threshold
408  inputtype = alg.input
409  if 'cTAU' in inputtype:
410  inputtype = 'eTAU'
411  elif any(substring in inputtype for substring in ['XE','TE','MHT','LArSaturation','ZeroBias']):
412  continue
413  thr = self.thresholds.thresholds[threshold]
414  minEt = 99999
415  if hasattr(thr, 'thresholdValues'):
416  etvalues = thr.thresholdValues
417  for etvalue in etvalues:
418  et = etvalue.value
419  if et < minEt:
420  minEt = et
421  if hasattr(thr, 'et'):
422  if thr.et < minEt:
423  minEt = thr.et
424  if inputtype in thresholdMin:
425  if minEt < thresholdMin[inputtype]:
426  thresholdMin[inputtype] = minEt
427  else:
428  thresholdMin[inputtype] = minEt
429 
430  # loop over sorting algorithms and get the min et values
431  for algo in self.topoAlgos.topoAlgos[AlgCategory.TOPO][AlgType.SORT]:
432  alg = self.topoAlgos.topoAlgos[AlgCategory.TOPO][AlgType.SORT][algo]
433  if alg.inputvalue == 'MuonTobs':
434  continue
435  for (pos, variable) in enumerate(alg.variables):
436  if variable.name == "MinET":
437  value = variable.value/10 # convert energies from 100MeV to GeV units
438  inputtype = ''
439  if alg.inputvalue == 'eEmTobs':
440  inputtype = 'eEM'
441  elif alg.inputvalue == 'eTauTobs':
442  inputtype = 'eTAU'
443  elif alg.inputvalue == 'jJetTobs':
444  inputtype = 'jJ'
445  else:
446  raise RuntimeError("checkPtMinToTopo: input type %s in sorting algo not recognised" % alg.inputvalue)
447  if inputtype in thresholdMin:
448  if value < thresholdMin[inputtype]:
449  thresholdMin[inputtype] = value
450  else:
451  thresholdMin[inputtype] = value
452  for thr in thresholdMin:
453  if thr in ptMin:
454  if thresholdMin[thr] < ptMin[thr]:
455  raise RuntimeError("checkPtMinToTopo: for threshold type %s the minimum threshold %i is less than ptMinToTopo %i" % (thr, thresholdMin[thr], ptMin[thr]))
456  else:
457  raise RuntimeError("checkPtMinToTopo: for threshold type %s the minimum threshold is %i and no ptMinToTopo value is found" % (thr, thresholdMin[thr]))
458 
459  def checkL1TopoParams(self):
460  from ..Menu.L1TopoParams import L1TopoParams as params
461 
462  algo_param_mismatch = []
463  # No need to check multiplicity algs
464  for algtype in [AlgType.SORT, AlgType.DEC]:
465  # Only check Phase-I Topo algs
466  for algname,algo in self.topoAlgos.topoAlgos[AlgCategory.TOPO][algtype].items():
467  log.debug(f'Checking variable parameter ordering for {algname} ({algo.classtype})')
468  pars_for_algo = params[algo.classtype]
469  generics_map = {g.name:g.value for g in algo.generics}
470  # No conditional parameters
471  common_params = None # Common parameters at the beginning, not repeated on multiple algo instances
472  ordered_params = None # Parameters that can be repeated if configuring multiple algo instances
473  if 'common_parameters' in pars_for_algo:
474  common_params = pars_for_algo['common_parameters']
475  if 'parameters' in pars_for_algo:
476  ordered_params = pars_for_algo['parameters']
477  # If all of the param lists are None, we have conditionals
478  if common_params is None and ordered_params is None:
479  for cond in pars_for_algo.keys():
480  if cond == 'comment': continue
481 
482  # Check that the condition is valid
483  pass_condition = True
484  for c in cond.split(' and '):
485  condname, condval = c.split(' = ')
486  if condname in generics_map:
487  if int(condval) == generics_map[condname]:
488  continue
489  else:
490  pass_condition = False
491  break
492  elif int(condval) == 0: # If the generic is not defined, assume that false is ok
493  continue
494  else:
495  pass_condition = False
496  break
497 
498  if pass_condition:
499  if 'common_parameters' in pars_for_algo[cond]:
500  common_params = pars_for_algo[cond]['common_parameters']
501  if 'parameters' in pars_for_algo[cond]:
502  ordered_params = pars_for_algo[cond]['parameters']
503  break
504 
505  if common_params is None and ordered_params is None and common_params is None:
506  raise RuntimeError(f'checkL1TopoParams: Did not find ordered parameter list for L1Topo algorithm type {algo.classtype}')
507 
508  menu_params = [p.name for p in algo.variables]
509  log.debug(f'Menu contains parameter list: {menu_params}')
510 
511  if common_params is None: common_params = []
512  if ordered_params is None: ordered_params = []
513  log.debug(f'Expected parameter list: {common_params + ordered_params}')
514 
515  # Handle case where parameters are supplied repeatedly to
516  # configure multiple instances
517  non_common_param_count = len(menu_params) - len(common_params)
518  if non_common_param_count > len(ordered_params):
519  log.debug(f'Can repeat the parameters: {ordered_params}')
520  if non_common_param_count % len(ordered_params) == 0:
521  ordered_params = int(non_common_param_count/len(ordered_params)) * ordered_params
522  else:
523  log.error("Mismatch in number of parameters")
524 
525  total_params = common_params + ordered_params
526  if menu_params != total_params:
527  log.error(f'checkL1TopoParams: Parameter list for {algo.name}/{algo.classtype} does not match specification')
528  log.error(f' Menu contains parameter list {menu_params}')
529  log.error(f' Expected parameter list {total_params}')
530  algo_param_mismatch.append(algo)
531 
532  if algo_param_mismatch:
533  log.error('checkL1TopoParams: Following L1Topo algorithms have incorrect parameter ordering in L1Menu:')
534  for algo in algo_param_mismatch:
535  log.error(f' {algo.name} ({algo.classtype})')
536  raise RuntimeError('checkL1TopoParams: L1Topo algorithm parameters do not match specification')
537 
539  all_ctpin = []
540  connected_boards = []
541  for layout,connectors in self.ctp.inputConnectors.items():
542  for connector, contents in connectors.items():
543  if layout=='ctpin':
544  # Ignore empty
545  connected_boards += [board for board in contents.values() if board]
546  else:
547  connected_boards.append(contents)
548 
549  for conn_name in connected_boards:
550  conn = self.connectors[conn_name]
551  if conn.ctype != CType.ELEC:
552  for tl in conn.triggerLines:
553  thrName = tl.name
554  if thrName[:3]=='ZB_':
555  thrName = thrName[3:]
556  all_ctpin.append(thrName)
557  else:
558  for fpga in conn.triggerLines:
559  for clock in conn.triggerLines[fpga]:
560  for tl in conn.triggerLines[fpga][clock]:
561  thrName = tl.name
562  if thrName[:3]=='ZB_':
563  thrName = thrName[3:]
564  all_ctpin.append(thrName)
565 
566  for item in self.items:
567  for thrName in item.thresholdNames():
568  if thrName[:3]=='ZB_':
569  thrName = thrName[3:]
570  if thrName not in all_ctpin:
571  raise RuntimeError(
572  f'checkItemsHaveInputs: Threshold {thrName} used by {item.name} is not on a board connected to CTP')
573 
574  def checkHFmonitoring(self):
575  requiredItems = [
576  "L1_BCM_2A_FIRSTINTRAIN",
577  "L1_BCM_2C_FIRSTINTRAIN"
578  ]
579  missingItems = [item for item in requiredItems if self.items.items[item].monitorsHF == 0]
580  if missingItems:
581  raise RuntimeError(
582  f'The HF monitoring flags for {", ".join(missingItems)} are missing')
python.L1.Base.L1Menu.L1Menu.flags
flags
Definition: L1Menu.py:32
python.L1.Base.L1Menu.L1Menu.getItem
def getItem(self, name)
Definition: L1Menu.py:63
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.Config.TypeWideThresholdConfig.getTypeWideThresholdConfig
def getTypeWideThresholdConfig(ttype, do_HI_tob_thresholds=False, do_eFex_BDT_Tau=True)
Definition: TypeWideThresholdConfig.py:101
python.L1.Base.L1Menu.L1Menu.thresholds
thresholds
Definition: L1Menu.py:35
python.L1.Base.L1Menu.L1Menu.setBunchGroupSplitting
def setBunchGroupSplitting(self, v=True)
Definition: L1Menu.py:55
python.L1.Base.L1Menu.L1Menu.boards
boards
Definition: L1Menu.py:44
python.L1.Base.L1Menu.L1Menu.ctp
ctp
Definition: L1Menu.py:47
python.L1.Base.TopoAlgorithms.MenuTopoAlgorithmsCollection
Definition: TopoAlgorithms.py:52
python.L1.Base.L1Menu.L1Menu.addThreshold
def addThreshold(self, threshold)
Definition: L1Menu.py:67
python.L1.Base.L1Menu.L1Menu.checkCountCTPInputsOutput
def checkCountCTPInputsOutput(self)
Definition: L1Menu.py:220
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
python.L1.Base.L1Menu.L1Menu.checkPerfThresholds
def checkPerfThresholds(self)
Definition: L1Menu.py:132
python.L1.Base.L1Menu.L1Menu.checkBoardInputs
def checkBoardInputs(self, algo, connDefName, fpgaName)
Definition: L1Menu.py:143
python.L1.Base.L1Menu.L1Menu.checkHFmonitoring
def checkHFmonitoring(self)
Definition: L1Menu.py:574
python.L1.Base.MenuUtils.get_smk_psk_Name
def get_smk_psk_Name(menuName)
Definition: MenuUtils.py:12
python.L1.Base.L1Menu.L1Menu.addTopoAlgo
def addTopoAlgo(self, algo, category)
Definition: L1Menu.py:71
python.L1.Base.Connectors.MenuConnectorsCollection
Definition: Connectors.py:53
python.L1.Base.L1Menu.L1Menu.checkCTPINconnectors
def checkCTPINconnectors(self)
Definition: L1Menu.py:198
python.L1.Base.L1Menu.L1Menu.topoAlgos
topoAlgos
Definition: L1Menu.py:38
python.L1.Base.Thresholds.MenuThresholdsCollection
Definition: Trigger/TriggerCommon/TriggerMenuMT/python/L1/Base/Thresholds.py:17
python.L1.Base.L1Menu.L1Menu.addConnector
def addConnector(self, connDef)
Definition: L1Menu.py:80
python.L1.Base.L1Menu.L1Menu.checkBGRP
def checkBGRP(self)
Definition: L1Menu.py:373
python.L1.Base.L1Menu.L1Menu.addBoard
def addBoard(self, boardDef)
Definition: L1Menu.py:76
python.L1.Base.CTP.CTP
Definition: CTP.py:11
python.L1.Base.L1Menu.L1Menu.addItem
def addItem(self, item)
Definition: L1Menu.py:59
python.L1.Base.L1Menu.L1Menu.menuFullName
menuFullName
Definition: L1Menu.py:26
python.L1.Base.L1Menu.L1Menu.setupCTPMonitoring
def setupCTPMonitoring(self)
Definition: L1Menu.py:84
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
python.L1.Base.L1Menu.L1Menu.checkItemsHaveInputs
def checkItemsHaveInputs(self)
Definition: L1Menu.py:538
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
python.L1.Base.L1Menu.L1Menu.check
def check(self)
Definition: L1Menu.py:87
python.L1.Base.Items.MenuItemsCollection
Definition: Items.py:13
python.L1.Base.L1Menu.L1Menu.checkL1TopoParams
def checkL1TopoParams(self)
Definition: L1Menu.py:459
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
python.L1.Base.L1Menu.L1Menu
Definition: L1Menu.py:18
python.L1.Base.L1Menu.L1Menu.connectors
connectors
Definition: L1Menu.py:41
python.L1.Base.L1Menu.L1Menu.checkL1CaloThresholds
def checkL1CaloThresholds(self, thresholds, boardName, connName)
Definition: L1Menu.py:171
python.L1.Base.L1Menu.L1Menu.checkTOPObits
def checkTOPObits(self)
Definition: L1Menu.py:204
pickleTool.object
object
Definition: pickleTool.py:29
python.L1.Base.L1Menu.L1Menu.checkPtMinToTopo
def checkPtMinToTopo(self)
Definition: L1Menu.py:385
python.L1.Base.L1Menu.L1Menu.items
items
Definition: L1Menu.py:29
python.L1.Base.Boards.MenuBoardsCollection
Definition: Boards.py:35
python.L1.Base.L1Menu.L1Menu.menuName
menuName
Definition: L1Menu.py:24
python.L1.Base.L1Menu.L1Menu.__init__
def __init__(self, menuName, flags)
Definition: L1Menu.py:23
python.L1.Base.L1Menu.L1Menu.checkLegacyThresholds
def checkLegacyThresholds(self)
Definition: L1Menu.py:117