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 collections
import OrderedDict
as odict
16 from AthenaCommon.Logging
import logging
17 log = logging.getLogger(__name__)
21 This class holds everything that is needed to define the menu
52 self.
items.menuName = smk_psk_Name[
"smkName"]
53 self.
items.pssName = smk_psk_Name[
"pskName"]
57 MenuItemsCollection.splitBunchGroups = v
65 return self.
items.findItemByName(name)
89 log.info(
"Doing L1 Menu checks")
90 from collections
import defaultdict
as dd
93 allUsedThresholds =
set()
94 for item
in self.
items:
95 for thrName
in item.thresholdNames():
96 if 'SPARE' in thrName:
97 raise RuntimeError(
"CTP input %s is used by %s but SPARE thresholds are not to be used!" %(thrName, item) )
98 if thrName
not in allThresholds:
99 missing[thrName].
append(item.name)
101 allUsedThresholds.add(thrName)
103 for thrName
in sorted(missing.keys()):
104 log.warning(
"Threshold %s (used by %s) is not defined in the menu", thrName,
",".
join(missing[thrName]))
106 if len(allThresholds)-len(allUsedThresholds)>0:
107 unusedThresholds = allThresholds.difference(allUsedThresholds)
108 log.debug(
"The following thresholds are unused")
109 log.debug(
"MU: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"MU")]))
110 log.debug(
"EM: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"EM")]))
111 log.debug(
"HA: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"HA")]))
112 log.debug(
"J: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"J")]))
113 log.debug(
"eFEX: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"e")]))
114 log.debug(
"jFEX: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"j")]))
115 log.debug(
"cTAU: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"cTAU")]))
116 log.debug(
"gFEX: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"g")]))
119 from collections
import defaultdict
as dd
120 from ..Menu.LegacyMenuThresholds
import legacyThresholds
121 extraThresholds =
dd(list)
122 for item
in self.
items:
123 for thrName
in item.thresholdNames():
124 if thrName[:3]==
'ZB_':
125 thrName = thrName[3:]
126 if thrName[0]
not in (
'e',
'j',
'g',
'c')
and thrName[:2]
not in [
"MU"]
and "TOPO" not in thrName[:4]:
127 if thrName
not in legacyThresholds:
128 extraThresholds[thrName].
append(item.name)
130 for thrName
in sorted(extraThresholds.keys()):
131 log.warning(
"Threshold %s (used by %s) should not be used!", thrName,
",".
join(extraThresholds[thrName]))
135 from collections
import defaultdict
as dd
136 perfThresholds =
dd(list)
137 for item
in self.
items:
138 for thrName
in item.thresholdNames():
139 if 'Perf' in thrName:
140 perfThresholds[thrName].
append(item.name)
141 for thrName
in sorted(perfThresholds.keys()):
142 raise RuntimeError(
"Threshold %s (used by %s) should not be used!", thrName,
",".
join(perfThresholds[thrName]))
145 if 'MuCTPi' in connDefName
or 'Legacy' in connDefName:
148 boardName = connDefName+fpgaName
150 allowedInputs = odict()
151 allowedInputs[
'Topo1Opt0'] = [
'MU',
'eEM',
'eTAU',
'gJ',
'gLJ',
'ZeroBiasA']
152 allowedInputs[
'Topo1Opt1'] = [
'MU',
'eEM',
'eTAU',
'gJ',
'gLJ', ]
153 allowedInputs[
'Topo1Opt2'] = [
'MU',
'eTAU',
'cTAU',
'j',
'gXE',
'gTE',
'gMHT']
154 allowedInputs[
'Topo1Opt3'] = [
'MU',
'eTAU',
'cTAU',
'j',
'gXE',
'gTE',
'gMHT',
'LArSaturation',
'ZeroBiasB']
155 allowedInputs[
'Topo2El0'] = [
'MU',
'eTAU',
'j', ]
156 allowedInputs[
'Topo2El1'] = [
'eEM',
'j', ]
157 allowedInputs[
'Topo3El0'] = [
'eEM',
'eTAU',
'j', ]
158 allowedInputs[
'Topo3El1'] = [
'MU',
'eEM',
'eTAU',
'g', ]
160 if boardName
not in allowedInputs.keys():
161 raise RuntimeError(
"Connector name %s not found" % boardName )
163 if 'Mult_' in algo.name:
164 if not (any(x
in algo.threshold
for x
in allowedInputs[boardName])):
165 raise RuntimeError(
"Algorithm %s in board %s with threshold %s not allowed" % (algo.name, boardName, algo.threshold ))
167 if 'Mult_' not in algo.name:
168 for algoInput
in algo.inputs:
169 if not (any(x
in algoInput
for x
in allowedInputs[boardName])):
170 raise RuntimeError(
"Algorithm %s in board %s with input %s not allowed" % (algo.name, boardName, algoInput ))
173 fullName = boardName + connName
175 allowedInputs = odict()
176 allowedInputs[
'Ctpin7EM1'] = 8*[
'EM']
177 allowedInputs[
'Ctpin7EM2'] = 8*[
'EM']
178 allowedInputs[
'Ctpin7TAU1'] = 8*[
'HA']
179 allowedInputs[
'Ctpin7TAU2'] = 8*[
'HA']
181 allowedInputs[
'Ctpin8JET1'] = 10*[
'J']
182 allowedInputs[
'Ctpin8JET2'] = 15*[
'J']
183 allowedInputs[
'Ctpin8EN1'] = 8*[
'TE'] + 8*[
'XE'] + 8*[
'XS']
184 allowedInputs[
'Ctpin8EN2'] = 8*[
'TE'] + 8*[
'XE']
186 invalidThresholds =
False
187 for ithr,thr
in enumerate(thresholds):
189 allowedThr = allowedInputs[fullName][ithr]
190 if thr[:len(allowedThr)] != allowedThr:
191 log.error(f
"Threshold {thr} does not match expected type {allowedThr} at position {ithr} in connector {fullName}")
192 invalidThresholds =
True
194 log.error(f
"Too many thresholds ({len(thresholds)}) provided for connector {fullName}, which only supports {len(allowedInputs[fullName])} thresholds")
195 invalidThresholds =
True
196 if invalidThresholds:
197 raise RuntimeError(
"Incorrect specification of legacy L1Calo thresholds")
201 if conn.ctype == CType.CTPIN:
202 if len(conn.triggerLines)>31:
203 raise RuntimeError(
"Too many CTP inputs in %s: %i but a max of 31 are allowed" %(conn.name,len(conn.triggerLines)))
207 pattern=
r"topo[1-3](e|$)"
210 if re.search(pattern, conn.name.lower()):
211 for tl
in conn.triggerLines:
212 for thr
in conn.triggerLines[tl]:
213 for thrname
in conn.triggerLines[tl][thr]:
214 if thrname.flatindex
not in flatindexs:
215 flatindexs.append(thrname.flatindex)
217 log.error(
"TOPO connector %s has duplicate flatindex %i", conn.name, thrname.flatindex)
218 raise RuntimeError(
"Duplicate flatindex found in TOPO algorithm")
222 from collections
import namedtuple
223 ctpInput = namedtuple(
'ctpInput',
"name, conn, nbit")
228 ctpInputBitSets = dict()
229 ctpInputNameSets = dict()
230 ctpUnusedInputBitSets = dict()
231 ctpUnusedInputNameSets = dict()
232 for item
in self.
items:
233 ctpOutputs.append(item.name)
234 for thrName
in item.thresholdNames():
235 if thrName[:3]==
'ZB_':
236 thrName = thrName[3:]
237 if thrName
not in thrNames:
238 thrNames.append(thrName)
239 thrNames_notFound = []
240 for thrName
in thrNames:
241 thrName_found =
False
243 if conn.ctype != CType.ELEC:
244 for tl
in conn.triggerLines:
245 if thrName == tl.name:
246 ctpInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
249 for fpga
in conn.triggerLines:
250 for clock
in conn.triggerLines[fpga]:
251 for tl
in conn.triggerLines[fpga][clock]:
252 if thrName == tl.name:
253 ctpInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
255 if not thrName_found:
256 thrNames_notFound.append(thrName)
259 if conn.ctype != CType.ELEC:
260 for tl
in conn.triggerLines:
262 if thrName[:3]==
'ZB_':
263 thrName = thrName[3:]
265 for ctpIn
in ctpInputs:
266 if thrName == ctpIn.name:
269 ctpUnusedInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
271 for fpga
in conn.triggerLines:
272 for clock
in conn.triggerLines[fpga]:
273 for tl
in conn.triggerLines[fpga][clock]:
275 if thrName[:3]==
'ZB_':
276 thrName = thrName[3:]
278 for ctpIn
in ctpInputs:
279 if thrName == ctpIn.name:
282 ctpUnusedInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
284 if len(thrNames_notFound)>0:
285 log.error(
"Thresholds [%s] are not found",
",".
join(thrNames_notFound))
286 log.error(
"Input thresholds are [%s]",
",".
join([ input.name
for input
in ctpInputs]))
287 raise RuntimeError(
"Not all input thresholds found!")
289 for ctpIn
in ctpInputs:
292 if thrName[:2]
in [
'EM',
'HA',
'XE',
'TE',
'XS']:
293 thrset =
'legacyCalo'
294 elif thrName[:1]==
'J':
295 thrset =
'legacyCalo'
296 elif thrName[:2]==
'MU':
298 elif thrName[:3]
in [
'MBT',
'AFP',
'BCM',
'CAL',
'NIM',
'ZDC',
'BPT',
'LUC',
'BMA']:
300 elif thrName[:6]==
'R2TOPO':
301 thrset =
'legacyTopo'
302 elif thrName[:1]
in [
'e',
'j',
'c',
'g']:
304 elif thrName[:4]==
'TOPO':
305 if 'Topo2' in ctpIn.conn:
307 elif 'Topo3' in ctpIn.conn:
310 if thrset
not in ctpInputBitSets:
311 ctpInputBitSets[thrset] = 0
312 ctpInputNameSets[thrset] = []
313 if thrName
not in ctpInputNameSets[thrset]:
314 ctpInputNameSets[thrset].
append(thrName)
315 ctpInputBitSets[thrset] += ctpIn.nbit
317 for ctpIn
in ctpUnusedInputs:
320 if thrName[:2]
in [
'EM',
'HA',
'XE',
'TE',
'XS']:
321 thrset =
'legacyCalo'
322 elif thrName[:1]==
'J':
323 thrset =
'legacyCalo'
324 elif thrName[:2]==
'MU':
326 elif thrName[:3]
in [
'MBT',
'AFP',
'BCM',
'CAL',
'NIM',
'ZDC',
'BPT',
'LUC']:
328 elif thrName[:6]==
'R2TOPO':
329 thrset =
'legacyTopo'
330 elif thrName[:1]
in [
'e',
'j',
'c',
'g']:
332 elif thrName[:4]==
'TOPO':
333 if 'Topo2' in ctpIn.conn:
335 elif 'Topo3' in ctpIn.conn:
338 if thrset
not in ctpUnusedInputBitSets:
339 ctpUnusedInputBitSets[thrset] = 0
340 ctpUnusedInputNameSets[thrset] = []
341 if thrName
not in ctpUnusedInputNameSets[thrset]:
342 ctpUnusedInputNameSets[thrset].
append(thrName)
343 ctpUnusedInputBitSets[thrset] += ctpIn.nbit
346 log.info(
"Check total number of CTP input and output bits:")
347 log.info(
"Number of output bits: %i", len(ctpOutputs) )
348 for thrset
in ctpInputBitSets:
349 log.info(
"Used inputs in %s: %i thresholds and %i bits", thrset, len(ctpInputNameSets[thrset]), ctpInputBitSets[thrset] )
350 if thrset
is not None:
351 log.debug(
"Threshold set %s: %s", thrset,
",".
join(ctpInputNameSets[thrset]) )
353 log.info(
"Unrecognised CTP input bits: %s",
",".
join(ctpInputNameSets[thrset]) )
354 totalInputs += ctpInputBitSets[thrset]
355 log.info(
"Number of used inputs bits: %i" , totalInputs )
356 totalUnusedInputs = 0
357 for thrset
in ctpUnusedInputBitSets:
358 log.debug(
"Unused thresholds in %s: %i thresholds and %i bits", thrset, len(ctpUnusedInputNameSets[thrset]), ctpUnusedInputBitSets[thrset] )
359 if thrset
is not None:
360 log.debug(
"Unused threshold set %s: %s", thrset,
",".
join(ctpUnusedInputNameSets[thrset]) )
362 log.debug(
"Unrecognised CTP input bits: %s",
",".
join(ctpUnusedInputNameSets[thrset]) )
363 totalUnusedInputs += ctpUnusedInputBitSets[thrset]
364 log.debug(
"Number of un-used inputs bits: %i" , totalUnusedInputs )
367 if ( totalInputs > Limits.MaxTrigItems
or len(ctpOutputs) > Limits.MaxTrigItems):
369 log.warning(f
"Input or output bits limit of {Limits.MaxTrigItems} exceeded in the dummy CTP menu -- OK")
371 raise RuntimeError(
"Both the numbers of inputs and outputs need to be not greater than %i in a physics menu!" % Limits.MaxTrigItems)
375 for item
in self.
items:
376 if len(item.bunchGroups)==1
and item.bunchGroups[0]==
'BGRP0':
377 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)
378 if 'BGRP2' in item.bunchGroups:
379 thrtype = item.logic.content[
'threshold'].ttype
380 if thrtype
in ThrType.CaloTypes():
383 raise RuntimeError(f
"L1 item {item.name} with threshold type {thrtype} is in CALREQ BGRP2. This is not allowed!")
391 for thrtype
in ThrType.Run3Types():
393 inputtype = thrtype.name
394 if inputtype ==
'cTAU':
396 for key, value
in ttconfig.items():
397 if "ptMinToTopo" in key:
398 if inputtype
in ptMin:
399 if ptMin[inputtype] > value:
400 ptMin[inputtype] = value
402 ptMin[inputtype] = value
406 for algo
in self.
topoAlgos.topoAlgos[AlgCategory.MULTI][AlgType.MULT]:
407 alg = self.
topoAlgos.topoAlgos[AlgCategory.MULTI][AlgType.MULT][algo]
408 threshold = alg.threshold
409 inputtype = alg.input
410 if 'cTAU' in inputtype:
412 elif any(substring
in inputtype
for substring
in [
'XE',
'TE',
'MHT',
'LArSaturation',
'ZeroBias']):
416 if hasattr(thr,
'thresholdValues'):
417 etvalues = thr.thresholdValues
418 for etvalue
in etvalues:
422 if hasattr(thr,
'et'):
425 if inputtype
in thresholdMin:
426 if minEt < thresholdMin[inputtype]:
427 thresholdMin[inputtype] = minEt
429 thresholdMin[inputtype] = minEt
432 for algo
in self.
topoAlgos.topoAlgos[AlgCategory.TOPO][AlgType.SORT]:
433 alg = self.
topoAlgos.topoAlgos[AlgCategory.TOPO][AlgType.SORT][algo]
434 if alg.inputvalue ==
'MuonTobs':
436 for (pos, variable)
in enumerate(alg.variables):
437 if variable.name ==
"MinET":
438 value = variable.value/10
440 if alg.inputvalue ==
'eEmTobs':
442 elif alg.inputvalue ==
'eTauTobs':
444 elif alg.inputvalue ==
'jJetTobs':
447 raise RuntimeError(
"checkPtMinToTopo: input type %s in sorting algo not recognised" % alg.inputvalue)
448 if inputtype
in thresholdMin:
449 if value < thresholdMin[inputtype]:
450 thresholdMin[inputtype] = value
452 thresholdMin[inputtype] = value
453 for thr
in thresholdMin:
455 if thresholdMin[thr] < ptMin[thr]:
456 raise RuntimeError(
"checkPtMinToTopo: for threshold type %s the minimum threshold %i is less than ptMinToTopo %i" % (thr, thresholdMin[thr], ptMin[thr]))
458 raise RuntimeError(
"checkPtMinToTopo: for threshold type %s the minimum threshold is %i and no ptMinToTopo value is found" % (thr, thresholdMin[thr]))
461 from ..Menu.L1TopoParams
import L1TopoParams
as params
463 algo_param_mismatch = []
465 for algtype
in [AlgType.SORT, AlgType.DEC]:
467 for algname,algo
in self.
topoAlgos.topoAlgos[AlgCategory.TOPO][algtype].
items():
468 log.debug(f
'Checking variable parameter ordering for {algname} ({algo.classtype})')
469 pars_for_algo = params[algo.classtype]
470 generics_map = {g.name:g.value
for g
in algo.generics}
473 ordered_params =
None
474 if 'common_parameters' in pars_for_algo:
475 common_params = pars_for_algo[
'common_parameters']
476 if 'parameters' in pars_for_algo:
477 ordered_params = pars_for_algo[
'parameters']
479 if common_params
is None and ordered_params
is None:
480 for cond
in pars_for_algo.keys():
481 if cond ==
'comment':
continue
484 pass_condition =
True
485 for c
in cond.split(
' and '):
486 condname, condval = c.split(
' = ')
487 if condname
in generics_map:
488 if int(condval) == generics_map[condname]:
491 pass_condition =
False
493 elif int(condval) == 0:
496 pass_condition =
False
500 if 'common_parameters' in pars_for_algo[cond]:
501 common_params = pars_for_algo[cond][
'common_parameters']
502 if 'parameters' in pars_for_algo[cond]:
503 ordered_params = pars_for_algo[cond][
'parameters']
506 if common_params
is None and ordered_params
is None and common_params
is None:
507 raise RuntimeError(f
'checkL1TopoParams: Did not find ordered parameter list for L1Topo algorithm type {algo.classtype}')
509 menu_params = [p.name
for p
in algo.variables]
510 log.debug(f
'Menu contains parameter list: {menu_params}')
512 if common_params
is None: common_params = []
513 if ordered_params
is None: ordered_params = []
514 log.debug(f
'Expected parameter list: {common_params + ordered_params}')
518 non_common_param_count = len(menu_params) - len(common_params)
519 if non_common_param_count > len(ordered_params):
520 log.debug(f
'Can repeat the parameters: {ordered_params}')
521 if non_common_param_count % len(ordered_params) == 0:
522 ordered_params =
int(non_common_param_count/len(ordered_params)) * ordered_params
524 log.error(
"Mismatch in number of parameters")
526 total_params = common_params + ordered_params
527 if menu_params != total_params:
528 log.error(f
'checkL1TopoParams: Parameter list for {algo.name}/{algo.classtype} does not match specification')
529 log.error(f
' Menu contains parameter list {menu_params}')
530 log.error(f
' Expected parameter list {total_params}')
531 algo_param_mismatch.append(algo)
533 if algo_param_mismatch:
534 log.error(
'checkL1TopoParams: Following L1Topo algorithms have incorrect parameter ordering in L1Menu:')
535 for algo
in algo_param_mismatch:
536 log.error(f
' {algo.name} ({algo.classtype})')
537 raise RuntimeError(
'checkL1TopoParams: L1Topo algorithm parameters do not match specification')
541 connected_boards = []
542 for layout,connectors
in self.
ctp.inputConnectors.items():
543 for connector, contents
in connectors.items():
546 connected_boards += [board
for board
in contents.values()
if board]
548 connected_boards.append(contents)
550 for conn_name
in connected_boards:
552 if conn.ctype != CType.ELEC:
553 for tl
in conn.triggerLines:
555 if thrName[:3]==
'ZB_':
556 thrName = thrName[3:]
557 all_ctpin.append(thrName)
559 for fpga
in conn.triggerLines:
560 for clock
in conn.triggerLines[fpga]:
561 for tl
in conn.triggerLines[fpga][clock]:
563 if thrName[:3]==
'ZB_':
564 thrName = thrName[3:]
565 all_ctpin.append(thrName)
567 for item
in self.
items:
568 for thrName
in item.thresholdNames():
569 if thrName[:3]==
'ZB_':
570 thrName = thrName[3:]
571 if thrName
not in all_ctpin:
573 f
'checkItemsHaveInputs: Threshold {thrName} used by {item.name} is not on a board connected to CTP')
577 "L1_BCM_2A_FIRSTINTRAIN",
578 "L1_BCM_2C_FIRSTINTRAIN"
580 missingItems = [item
for item
in requiredItems
if self.
items.items[item].monitorsHF == 0]
583 f
'The HF monitoring flags for {", ".join(missingItems)} are missing')