ATLAS Offline Software
Loading...
Searching...
No Matches
L1Menu.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 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
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', '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(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', 'ESPRESSO','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
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
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')
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.