ATLAS Offline Software
Loading...
Searching...
No Matches
L1Menu.py
Go to the documentation of this file.
1# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
2
3from .CTP import CTP
4from .Items import MenuItemsCollection
5from .Thresholds import MenuThresholdsCollection
6from .TopoAlgorithms import MenuTopoAlgorithmsCollection, AlgType, AlgCategory
7from .Boards import MenuBoardsCollection
8from .Connectors import MenuConnectorsCollection, CType
9from .MenuUtils import get_smk_psk_Name
10from .Limits import Limits
11from .L1MenuFlags import L1MenuFlags
12from .ThresholdType import ThrType
13from ..Config.TypeWideThresholdConfig import getTypeWideThresholdConfig
14
15from AthenaCommon.Logging import logging
16log = logging.getLogger(__name__)
17
18class 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
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, fiber 1
151 allowedInputs['Topo1Opt1'] = ['MU', 'eEM', 'eTAU', 'gJ', 'gLJ', ] # TOPO1A, fiber 2
152 allowedInputs['Topo1Opt2'] = ['MU', 'eTAU', 'cTAU', 'j', 'cXE', 'gXE', 'gTE', 'gMHT', 'gESPRESSO', 'LArSaturation', 'ZeroBiasB'] # TOPO1B, fiber 1
153 allowedInputs['Topo1Opt3'] = ['MU', 'eTAU', 'cTAU', 'j', 'cXE', 'gXE', 'gTE', 'gMHT', 'gESPRESSO', 'gRISTRETTO', 'LArSaturation', 'ZeroBiasB'] # TOPO1B, fiber 2
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
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(ttype=thrtype, \
392 do_HI_tob_thresholds=self.flags.Trigger.L1.Menu.doHeavyIonTobThresholds, \
393 do_eFex_BDT_Tau=self.flags.Trigger.L1.Menu.doeFexBDTTau, \
394 collisions=self.flags.Beam.NumberOfCollisions)
395 inputtype = thrtype.name
396 if inputtype == 'cTAU':
397 inputtype = 'eTAU'
398 for key, value in ttconfig.items():
399 if "ptMinToTopo" in key:
400 if inputtype in ptMin:
401 if ptMin[inputtype] > value:
402 ptMin[inputtype] = value
403 else:
404 ptMin[inputtype] = value
405
406 # loop over multiplicity algorithms and get the min et values
407 thresholdMin = {}
408 for algo in self.topoAlgos.topoAlgos[AlgCategory.MULTI][AlgType.MULT]:
409 alg = self.topoAlgos.topoAlgos[AlgCategory.MULTI][AlgType.MULT][algo]
410 threshold = alg.threshold
411 inputtype = alg.input
412 if 'cTAU' in inputtype:
413 inputtype = 'eTAU'
414 elif any(substring in inputtype for substring in ['XE','TE','MHT', 'ESPRESSO', 'RISTRETTO', 'LArSaturation','ZeroBias']):
415 continue
416 thr = self.thresholds.thresholds[threshold]
417 minEt = 99999
418 if hasattr(thr, 'thresholdValues'):
419 etvalues = thr.thresholdValues
420 for etvalue in etvalues:
421 et = etvalue.value
422 if et < minEt:
423 minEt = et
424 if hasattr(thr, 'et'):
425 if thr.et < minEt:
426 minEt = thr.et
427 if inputtype in thresholdMin:
428 if minEt < thresholdMin[inputtype]:
429 thresholdMin[inputtype] = minEt
430 else:
431 thresholdMin[inputtype] = minEt
432
433 # loop over sorting algorithms and get the min et values
434 for algo in self.topoAlgos.topoAlgos[AlgCategory.TOPO][AlgType.SORT]:
435 alg = self.topoAlgos.topoAlgos[AlgCategory.TOPO][AlgType.SORT][algo]
436 if alg.inputvalue == 'MuonTobs':
437 continue
438 for (pos, variable) in enumerate(alg.variables):
439 if variable.name == "MinET":
440 value = variable.value/10 # convert energies from 100MeV to GeV units
441 inputtype = ''
442 if alg.inputvalue == 'eEmTobs':
443 inputtype = 'eEM'
444 elif alg.inputvalue == 'eTauTobs':
445 inputtype = 'eTAU'
446 elif alg.inputvalue == 'jJetTobs':
447 inputtype = 'jJ'
448 else:
449 raise RuntimeError("checkPtMinToTopo: input type %s in sorting algo not recognised" % alg.inputvalue)
450 if inputtype in thresholdMin:
451 if value < thresholdMin[inputtype]:
452 thresholdMin[inputtype] = value
453 else:
454 thresholdMin[inputtype] = value
455 for thr in thresholdMin:
456 if thr in ptMin:
457 if thresholdMin[thr] < ptMin[thr]:
458 raise RuntimeError("checkPtMinToTopo: for threshold type %s the minimum threshold %i is less than ptMinToTopo %i" % (thr, thresholdMin[thr], ptMin[thr]))
459 else:
460 raise RuntimeError("checkPtMinToTopo: for threshold type %s the minimum threshold is %i and no ptMinToTopo value is found" % (thr, thresholdMin[thr]))
461
463 from ..Menu.L1TopoParams import L1TopoParams as params
464
465 algo_param_mismatch = []
466 # No need to check multiplicity algs
467 for algtype in [AlgType.SORT, AlgType.DEC]:
468 # Only check Phase-I Topo algs
469 for algname,algo in self.topoAlgos.topoAlgos[AlgCategory.TOPO][algtype].items():
470 log.debug(f'Checking variable parameter ordering for {algname} ({algo.classtype})')
471 pars_for_algo = params[algo.classtype]
472 generics_map = {g.name:g.value for g in algo.generics}
473 # No conditional parameters
474 common_params = None # Common parameters at the beginning, not repeated on multiple algo instances
475 ordered_params = None # Parameters that can be repeated if configuring multiple algo instances
476 if 'common_parameters' in pars_for_algo:
477 common_params = pars_for_algo['common_parameters']
478 if 'parameters' in pars_for_algo:
479 ordered_params = pars_for_algo['parameters']
480 # If all of the param lists are None, we have conditionals
481 if common_params is None and ordered_params is None:
482 for cond in pars_for_algo.keys():
483 if cond == 'comment': continue
484
485 # Check that the condition is valid
486 pass_condition = True
487 for c in cond.split(' and '):
488 condname, condval = c.split(' = ')
489 if condname in generics_map:
490 if int(condval) == generics_map[condname]:
491 continue
492 else:
493 pass_condition = False
494 break
495 elif int(condval) == 0: # If the generic is not defined, assume that false is ok
496 continue
497 else:
498 pass_condition = False
499 break
500
501 if pass_condition:
502 if 'common_parameters' in pars_for_algo[cond]:
503 common_params = pars_for_algo[cond]['common_parameters']
504 if 'parameters' in pars_for_algo[cond]:
505 ordered_params = pars_for_algo[cond]['parameters']
506 break
507
508 if common_params is None and ordered_params is None and common_params is None:
509 raise RuntimeError(f'checkL1TopoParams: Did not find ordered parameter list for L1Topo algorithm type {algo.classtype}')
510
511 menu_params = [p.name for p in algo.variables]
512 log.debug(f'Menu contains parameter list: {menu_params}')
513
514 if common_params is None: common_params = []
515 if ordered_params is None: ordered_params = []
516 log.debug(f'Expected parameter list: {common_params + ordered_params}')
517
518 # Handle case where parameters are supplied repeatedly to
519 # configure multiple instances
520 non_common_param_count = len(menu_params) - len(common_params)
521 if non_common_param_count > len(ordered_params):
522 log.debug(f'Can repeat the parameters: {ordered_params}')
523 if non_common_param_count % len(ordered_params) == 0:
524 ordered_params = int(non_common_param_count/len(ordered_params)) * ordered_params
525 else:
526 log.error("Mismatch in number of parameters")
527
528 total_params = common_params + ordered_params
529 if menu_params != total_params:
530 log.error(f'checkL1TopoParams: Parameter list for {algo.name}/{algo.classtype} does not match specification')
531 log.error(f' Menu contains parameter list {menu_params}')
532 log.error(f' Expected parameter list {total_params}')
533 algo_param_mismatch.append(algo)
534
535 if algo_param_mismatch:
536 log.error('checkL1TopoParams: Following L1Topo algorithms have incorrect parameter ordering in L1Menu:')
537 for algo in algo_param_mismatch:
538 log.error(f' {algo.name} ({algo.classtype})')
539 raise RuntimeError('checkL1TopoParams: L1Topo algorithm parameters do not match specification')
540
542 all_ctpin = []
543 connected_boards = []
544 for layout,connectors in self.ctp.inputConnectors.items():
545 for connector, contents in connectors.items():
546 if layout=='ctpin':
547 # Ignore empty
548 connected_boards += [board for board in contents.values() if board]
549 else:
550 connected_boards.append(contents)
551
552 for conn_name in connected_boards:
553 conn = self.connectors[conn_name]
554 if conn.ctype != CType.ELEC:
555 for tl in conn.triggerLines:
556 thrName = tl.name
557 if thrName[:3]=='ZB_':
558 thrName = thrName[3:]
559 all_ctpin.append(thrName)
560 else:
561 for fpga in conn.triggerLines:
562 for clock in conn.triggerLines[fpga]:
563 for tl in conn.triggerLines[fpga][clock]:
564 thrName = tl.name
565 if thrName[:3]=='ZB_':
566 thrName = thrName[3:]
567 all_ctpin.append(thrName)
568
569 for item in self.items:
570 for thrName in item.thresholdNames():
571 if thrName[:3]=='ZB_':
572 thrName = thrName[3:]
573 if thrName not in all_ctpin:
574 raise RuntimeError(
575 f'checkItemsHaveInputs: Threshold {thrName} used by {item.name} is not on a board connected to CTP')
576
578 requiredItems = [
579 "L1_BCM_2A_FIRSTINTRAIN",
580 "L1_BCM_2C_FIRSTINTRAIN"
581 ]
582 missingItems = [item for item in requiredItems if self.items.items[item].monitorsHF == 0]
583 if missingItems:
584 raise RuntimeError(
585 f'The HF monitoring flags for {", ".join(missingItems)} are missing')
addThreshold(self, threshold)
Definition L1Menu.py:67
addBoard(self, boardDef)
Definition L1Menu.py:76
checkBoardInputs(self, algo, connDefName, fpgaName)
Definition L1Menu.py:143
__init__(self, menuName, flags)
Definition L1Menu.py:23
checkL1CaloThresholds(self, thresholds, boardName, connName)
Definition L1Menu.py:171
setBunchGroupSplitting(self, v=True)
Definition L1Menu.py:55
addTopoAlgo(self, algo, category)
Definition L1Menu.py:71
addConnector(self, connDef)
Definition L1Menu.py:80
STL class.