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
15 from AthenaCommon.Logging
import logging
16 log = logging.getLogger(__name__)
20 This class holds everything that is needed to define the menu
51 self.
items.menuName = smk_psk_Name[
"smkName"]
52 self.
items.pssName = smk_psk_Name[
"pskName"]
56 MenuItemsCollection.splitBunchGroups = v
64 return self.
items.findItemByName(name)
88 log.info(
"Doing L1 Menu checks")
89 from collections
import defaultdict
as dd
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)
100 allUsedThresholds.add(thrName)
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]))
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")]))
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)
129 for thrName
in sorted(extraThresholds.keys()):
130 log.warning(
"Threshold %s (used by %s) should not be used!", thrName,
",".
join(extraThresholds[thrName]))
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]))
144 if 'MuCTPi' in connDefName
or 'Legacy' in connDefName:
147 boardName = connDefName+fpgaName
150 allowedInputs[
'Topo1Opt0'] = [
'MU',
'eEM',
'eTAU',
'gJ',
'gLJ',
'ZeroBiasA']
151 allowedInputs[
'Topo1Opt1'] = [
'MU',
'eEM',
'eTAU',
'gJ',
'gLJ', ]
152 allowedInputs[
'Topo1Opt2'] = [
'MU',
'eTAU',
'cTAU',
'j',
'gXE',
'gTE',
'gMHT']
153 allowedInputs[
'Topo1Opt3'] = [
'MU',
'eTAU',
'cTAU',
'j',
'gXE',
'gTE',
'gMHT',
'LArSaturation',
'ZeroBiasB']
154 allowedInputs[
'Topo2El0'] = [
'MU',
'eTAU',
'j', ]
155 allowedInputs[
'Topo2El1'] = [
'eEM',
'j', ]
156 allowedInputs[
'Topo3El0'] = [
'eEM',
'eTAU',
'j', ]
157 allowedInputs[
'Topo3El1'] = [
'MU',
'eEM',
'eTAU',
'g', ]
159 if boardName
not in allowedInputs.keys():
160 raise RuntimeError(
"Connector name %s not found" % boardName )
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 ))
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 ))
172 fullName = boardName + connName
175 allowedInputs[
'Ctpin7EM1'] = 8*[
'EM']
176 allowedInputs[
'Ctpin7EM2'] = 8*[
'EM']
177 allowedInputs[
'Ctpin7TAU1'] = 8*[
'HA']
178 allowedInputs[
'Ctpin7TAU2'] = 8*[
'HA']
180 allowedInputs[
'Ctpin8JET1'] = 10*[
'J']
181 allowedInputs[
'Ctpin8JET2'] = 15*[
'J']
182 allowedInputs[
'Ctpin8EN1'] = 8*[
'TE'] + 8*[
'XE'] + 8*[
'XS']
183 allowedInputs[
'Ctpin8EN2'] = 8*[
'TE'] + 8*[
'XE']
185 invalidThresholds =
False
186 for ithr,thr
in enumerate(thresholds):
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
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")
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)))
206 pattern=
r"topo[1-3](e|$)"
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)
216 log.error(
"TOPO connector %s has duplicate flatindex %i", conn.name, thrname.flatindex)
217 raise RuntimeError(
"Duplicate flatindex found in TOPO algorithm")
221 from collections
import namedtuple
222 ctpInput = namedtuple(
'ctpInput',
"name, conn, nbit")
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
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))
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))
254 if not thrName_found:
255 thrNames_notFound.append(thrName)
258 if conn.ctype != CType.ELEC:
259 for tl
in conn.triggerLines:
261 if thrName[:3]==
'ZB_':
262 thrName = thrName[3:]
264 for ctpIn
in ctpInputs:
265 if thrName == ctpIn.name:
268 ctpUnusedInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
270 for fpga
in conn.triggerLines:
271 for clock
in conn.triggerLines[fpga]:
272 for tl
in conn.triggerLines[fpga][clock]:
274 if thrName[:3]==
'ZB_':
275 thrName = thrName[3:]
277 for ctpIn
in ctpInputs:
278 if thrName == ctpIn.name:
281 ctpUnusedInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
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!")
288 for ctpIn
in ctpInputs:
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':
297 elif thrName[:3]
in [
'MBT',
'AFP',
'BCM',
'CAL',
'NIM',
'ZDC',
'BPT',
'LUC',
'BMA']:
299 elif thrName[:6]==
'R2TOPO':
300 thrset =
'legacyTopo'
301 elif thrName[:1]
in [
'e',
'j',
'c',
'g']:
303 elif thrName[:4]==
'TOPO':
304 if 'Topo2' in ctpIn.conn:
306 elif 'Topo3' in ctpIn.conn:
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
316 for ctpIn
in ctpUnusedInputs:
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':
325 elif thrName[:3]
in [
'MBT',
'AFP',
'BCM',
'CAL',
'NIM',
'ZDC',
'BPT',
'LUC']:
327 elif thrName[:6]==
'R2TOPO':
328 thrset =
'legacyTopo'
329 elif thrName[:1]
in [
'e',
'j',
'c',
'g']:
331 elif thrName[:4]==
'TOPO':
332 if 'Topo2' in ctpIn.conn:
334 elif 'Topo3' in ctpIn.conn:
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
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]) )
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]) )
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 )
366 if ( totalInputs > Limits.MaxTrigItems
or len(ctpOutputs) > Limits.MaxTrigItems):
368 log.warning(f
"Input or output bits limit of {Limits.MaxTrigItems} exceeded in the dummy CTP menu -- OK")
370 raise RuntimeError(
"Both the numbers of inputs and outputs need to be not greater than %i in a physics menu!" % Limits.MaxTrigItems)
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():
382 raise RuntimeError(f
"L1 item {item.name} with threshold type {thrtype} is in CALREQ BGRP2. This is not allowed!")
390 for thrtype
in ThrType.Run3Types():
392 inputtype = thrtype.name
393 if inputtype ==
'cTAU':
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
401 ptMin[inputtype] = value
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:
411 elif any(substring
in inputtype
for substring
in [
'XE',
'TE',
'MHT',
'LArSaturation',
'ZeroBias']):
415 if hasattr(thr,
'thresholdValues'):
416 etvalues = thr.thresholdValues
417 for etvalue
in etvalues:
421 if hasattr(thr,
'et'):
424 if inputtype
in thresholdMin:
425 if minEt < thresholdMin[inputtype]:
426 thresholdMin[inputtype] = minEt
428 thresholdMin[inputtype] = minEt
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':
435 for (pos, variable)
in enumerate(alg.variables):
436 if variable.name ==
"MinET":
437 value = variable.value/10
439 if alg.inputvalue ==
'eEmTobs':
441 elif alg.inputvalue ==
'eTauTobs':
443 elif alg.inputvalue ==
'jJetTobs':
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
451 thresholdMin[inputtype] = value
452 for thr
in thresholdMin:
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]))
457 raise RuntimeError(
"checkPtMinToTopo: for threshold type %s the minimum threshold is %i and no ptMinToTopo value is found" % (thr, thresholdMin[thr]))
460 from ..Menu.L1TopoParams
import L1TopoParams
as params
462 algo_param_mismatch = []
464 for algtype
in [AlgType.SORT, AlgType.DEC]:
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}
472 ordered_params =
None
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']
478 if common_params
is None and ordered_params
is None:
479 for cond
in pars_for_algo.keys():
480 if cond ==
'comment':
continue
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]:
490 pass_condition =
False
492 elif int(condval) == 0:
495 pass_condition =
False
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']
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}')
508 menu_params = [p.name
for p
in algo.variables]
509 log.debug(f
'Menu contains parameter list: {menu_params}')
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}')
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
523 log.error(
"Mismatch in number of parameters")
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)
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')
540 connected_boards = []
541 for layout,connectors
in self.
ctp.inputConnectors.items():
542 for connector, contents
in connectors.items():
545 connected_boards += [board
for board
in contents.values()
if board]
547 connected_boards.append(contents)
549 for conn_name
in connected_boards:
551 if conn.ctype != CType.ELEC:
552 for tl
in conn.triggerLines:
554 if thrName[:3]==
'ZB_':
555 thrName = thrName[3:]
556 all_ctpin.append(thrName)
558 for fpga
in conn.triggerLines:
559 for clock
in conn.triggerLines[fpga]:
560 for tl
in conn.triggerLines[fpga][clock]:
562 if thrName[:3]==
'ZB_':
563 thrName = thrName[3:]
564 all_ctpin.append(thrName)
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:
572 f
'checkItemsHaveInputs: Threshold {thrName} used by {item.name} is not on a board connected to CTP')
576 "L1_BCM_2A_FIRSTINTRAIN",
577 "L1_BCM_2C_FIRSTINTRAIN"
579 missingItems = [item
for item
in requiredItems
if self.
items.items[item].monitorsHF == 0]
582 f
'The HF monitoring flags for {", ".join(missingItems)} are missing')