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
50 self.
items.menuName = smk_psk_Name[
"smkName"]
51 self.
items.pssName = smk_psk_Name[
"pskName"]
55 first = L1MenuFlags.MenuPartitioning()
56 last = first[1:] + [ Limits.MaxTrigItems ]
57 partitioning = dict( zip([1,2,3],zip(first,last)) )
61 MenuItemsCollection.splitBunchGroups = v
69 return self.
items.findItemByName(name)
93 log.info(
"Doing L1 Menu checks")
94 from collections
import defaultdict
as dd
97 allUsedThresholds =
set()
98 for item
in self.
items:
99 for thrName
in item.thresholdNames():
100 if 'SPARE' in thrName:
101 raise RuntimeError(
"CTP input %s is used by %s but SPARE thresholds are not to be used!" %(thrName, item) )
102 if thrName
not in allThresholds:
103 missing[thrName].
append(item.name)
105 allUsedThresholds.add(thrName)
107 for thrName
in sorted(missing.keys()):
108 log.warning(
"Threshold %s (used by %s) is not defined in the menu", thrName,
",".
join(missing[thrName]))
110 if len(allThresholds)-len(allUsedThresholds)>0:
111 unusedThresholds = allThresholds.difference(allUsedThresholds)
112 log.debug(
"The following thresholds are unused")
113 log.debug(
"MU: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"MU")]))
114 log.debug(
"EM: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"EM")]))
115 log.debug(
"HA: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"HA")]))
116 log.debug(
"J: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"J")]))
117 log.debug(
"eFEX: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"e")]))
118 log.debug(
"jFEX: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"j")]))
119 log.debug(
"cTAU: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"cTAU")]))
120 log.debug(
"gFEX: %s",
", ".
join([thr
for thr
in unusedThresholds
if thr.startswith(
"g")]))
123 from collections
import defaultdict
as dd
124 from ..Menu.LegacyMenuThresholds
import legacyThresholds
125 extraThresholds =
dd(list)
126 for item
in self.
items:
127 for thrName
in item.thresholdNames():
128 if thrName[:3]==
'ZB_':
129 thrName = thrName[3:]
130 if thrName[0]
not in (
'e',
'j',
'g',
'c')
and thrName[:2]
not in [
"MU"]
and "TOPO" not in thrName[:4]:
131 if thrName
not in legacyThresholds:
132 extraThresholds[thrName].
append(item.name)
134 for thrName
in sorted(extraThresholds.keys()):
135 log.warning(
"Threshold %s (used by %s) should not be used!", thrName,
",".
join(extraThresholds[thrName]))
139 from collections
import defaultdict
as dd
140 perfThresholds =
dd(list)
141 for item
in self.
items:
142 for thrName
in item.thresholdNames():
143 if 'Perf' in thrName:
144 perfThresholds[thrName].
append(item.name)
145 for thrName
in sorted(perfThresholds.keys()):
146 raise RuntimeError(
"Threshold %s (used by %s) should not be used!", thrName,
",".
join(perfThresholds[thrName]))
149 if 'MuCTPi' in connDefName
or 'Legacy' in connDefName:
152 boardName = connDefName+fpgaName
154 allowedInputs = odict()
155 allowedInputs[
'Topo1Opt0'] = [
'MU',
'eEM',
'eTAU',
'gJ',
'gLJ',
'ZeroBiasA']
156 allowedInputs[
'Topo1Opt1'] = [
'MU',
'eEM',
'eTAU',
'gJ',
'gLJ', ]
157 allowedInputs[
'Topo1Opt2'] = [
'MU',
'eTAU',
'cTAU',
'j',
'gXE',
'gTE',
'gMHT']
158 allowedInputs[
'Topo1Opt3'] = [
'MU',
'eTAU',
'cTAU',
'j',
'gXE',
'gTE',
'gMHT',
'LArSaturation',
'ZeroBiasB']
159 allowedInputs[
'Topo2El0'] = [
'MU',
'eTAU',
'j', ]
160 allowedInputs[
'Topo2El1'] = [
'eEM',
'j', ]
161 allowedInputs[
'Topo3El0'] = [
'eEM',
'eTAU',
'j', ]
162 allowedInputs[
'Topo3El1'] = [
'MU',
'eEM',
'eTAU',
'g', ]
164 if boardName
not in allowedInputs.keys():
165 raise RuntimeError(
"Connector name %s not found" % boardName )
167 if 'Mult_' in algo.name:
168 if not (any(x
in algo.threshold
for x
in allowedInputs[boardName])):
169 raise RuntimeError(
"Algorithm %s in board %s with threshold %s not allowed" % (algo.name, boardName, algo.threshold ))
171 if 'Mult_' not in algo.name:
172 for algoInput
in algo.inputs:
173 if not (any(x
in algoInput
for x
in allowedInputs[boardName])):
174 raise RuntimeError(
"Algorithm %s in board %s with input %s not allowed" % (algo.name, boardName, algoInput ))
177 fullName = boardName + connName
179 allowedInputs = odict()
180 allowedInputs[
'Ctpin7EM1'] = 8*[
'EM']
181 allowedInputs[
'Ctpin7EM2'] = 8*[
'EM']
182 allowedInputs[
'Ctpin7TAU1'] = 8*[
'HA']
183 allowedInputs[
'Ctpin7TAU2'] = 8*[
'HA']
185 allowedInputs[
'Ctpin8JET1'] = 10*[
'J']
186 allowedInputs[
'Ctpin8JET2'] = 15*[
'J']
187 allowedInputs[
'Ctpin8EN1'] = 8*[
'TE'] + 8*[
'XE'] + 8*[
'XS']
188 allowedInputs[
'Ctpin8EN2'] = 8*[
'TE'] + 8*[
'XE']
190 invalidThresholds =
False
191 for ithr,thr
in enumerate(thresholds):
193 allowedThr = allowedInputs[fullName][ithr]
194 if thr[:len(allowedThr)] != allowedThr:
195 log.error(f
"Threshold {thr} does not match expected type {allowedThr} at position {ithr} in connector {fullName}")
196 invalidThresholds =
True
198 log.error(f
"Too many thresholds ({len(thresholds)}) provided for connector {fullName}, which only supports {len(allowedInputs[fullName])} thresholds")
199 invalidThresholds =
True
200 if invalidThresholds:
201 raise RuntimeError(
"Incorrect specification of legacy L1Calo thresholds")
205 if conn.ctype == CType.CTPIN:
206 if len(conn.triggerLines)>31:
207 raise RuntimeError(
"Too many CTP inputs in %s: %i but a max of 31 are allowed" %(conn.name,len(conn.triggerLines)))
210 from collections
import namedtuple
211 ctpInput = namedtuple(
'ctpInput',
"name, conn, nbit")
216 ctpInputBitSets = dict()
217 ctpInputNameSets = dict()
218 ctpUnusedInputBitSets = dict()
219 ctpUnusedInputNameSets = dict()
220 for item
in self.
items:
221 ctpOutputs.append(item.name)
222 for thrName
in item.thresholdNames():
223 if thrName[:3]==
'ZB_':
224 thrName = thrName[3:]
225 if thrName
not in thrNames:
226 thrNames.append(thrName)
227 thrNames_notFound = []
228 for thrName
in thrNames:
229 thrName_found =
False
231 if conn.ctype != CType.ELEC:
232 for tl
in conn.triggerLines:
233 if thrName == tl.name:
234 ctpInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
237 for fpga
in conn.triggerLines:
238 for clock
in conn.triggerLines[fpga]:
239 for tl
in conn.triggerLines[fpga][clock]:
240 if thrName == tl.name:
241 ctpInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
243 if not thrName_found:
244 thrNames_notFound.append(thrName)
247 if conn.ctype != CType.ELEC:
248 for tl
in conn.triggerLines:
250 if thrName[:3]==
'ZB_':
251 thrName = thrName[3:]
253 for ctpIn
in ctpInputs:
254 if thrName == ctpIn.name:
257 ctpUnusedInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
259 for fpga
in conn.triggerLines:
260 for clock
in conn.triggerLines[fpga]:
261 for tl
in conn.triggerLines[fpga][clock]:
263 if thrName[:3]==
'ZB_':
264 thrName = thrName[3:]
266 for ctpIn
in ctpInputs:
267 if thrName == ctpIn.name:
270 ctpUnusedInputs.append(ctpInput(name=thrName,conn=conn.name,nbit=tl.nbits))
272 if len(thrNames_notFound)>0:
273 log.error(
"Thresholds [%s] are not found",
",".
join(thrNames_notFound))
274 log.error(
"Input thresholds are [%s]",
",".
join([ input.name
for input
in ctpInputs]))
275 raise RuntimeError(
"Not all input thresholds found!")
277 for ctpIn
in ctpInputs:
280 if thrName[:2]
in [
'EM',
'HA',
'XE',
'TE',
'XS']:
281 thrset =
'legacyCalo'
282 elif thrName[:1]==
'J':
283 thrset =
'legacyCalo'
284 elif thrName[:2]==
'MU':
286 elif thrName[:3]
in [
'MBT',
'AFP',
'BCM',
'CAL',
'NIM',
'ZDC',
'BPT',
'LUC',
'BMA']:
288 elif thrName[:6]==
'R2TOPO':
289 thrset =
'legacyTopo'
290 elif thrName[:1]
in [
'e',
'j',
'c',
'g']:
292 elif thrName[:4]==
'TOPO':
293 if 'Topo2' in ctpIn.conn:
295 elif 'Topo3' in ctpIn.conn:
298 if thrset
not in ctpInputBitSets:
299 ctpInputBitSets[thrset] = 0
300 ctpInputNameSets[thrset] = []
301 if thrName
not in ctpInputNameSets[thrset]:
302 ctpInputNameSets[thrset].
append(thrName)
303 ctpInputBitSets[thrset] += ctpIn.nbit
305 for ctpIn
in ctpUnusedInputs:
308 if thrName[:2]
in [
'EM',
'HA',
'XE',
'TE',
'XS']:
309 thrset =
'legacyCalo'
310 elif thrName[:1]==
'J':
311 thrset =
'legacyCalo'
312 elif thrName[:2]==
'MU':
314 elif thrName[:3]
in [
'MBT',
'AFP',
'BCM',
'CAL',
'NIM',
'ZDC',
'BPT',
'LUC']:
316 elif thrName[:6]==
'R2TOPO':
317 thrset =
'legacyTopo'
318 elif thrName[:1]
in [
'e',
'j',
'c',
'g']:
320 elif thrName[:4]==
'TOPO':
321 if 'Topo2' in ctpIn.conn:
323 elif 'Topo3' in ctpIn.conn:
326 if thrset
not in ctpUnusedInputBitSets:
327 ctpUnusedInputBitSets[thrset] = 0
328 ctpUnusedInputNameSets[thrset] = []
329 if thrName
not in ctpUnusedInputNameSets[thrset]:
330 ctpUnusedInputNameSets[thrset].
append(thrName)
331 ctpUnusedInputBitSets[thrset] += ctpIn.nbit
334 log.info(
"Check total number of CTP input and output bits:")
335 log.info(
"Number of output bits: %i", len(ctpOutputs) )
336 for thrset
in ctpInputBitSets:
337 log.info(
"Used inputs in %s: %i thresholds and %i bits", thrset, len(ctpInputNameSets[thrset]), ctpInputBitSets[thrset] )
338 if thrset
is not None:
339 log.debug(
"Threshold set %s: %s", thrset,
",".
join(ctpInputNameSets[thrset]) )
341 log.info(
"Unrecognised CTP input bits: %s",
",".
join(ctpInputNameSets[thrset]) )
342 totalInputs += ctpInputBitSets[thrset]
343 log.info(
"Number of used inputs bits: %i" , totalInputs )
344 totalUnusedInputs = 0
345 for thrset
in ctpUnusedInputBitSets:
346 log.debug(
"Unused thresholds in %s: %i thresholds and %i bits", thrset, len(ctpUnusedInputNameSets[thrset]), ctpUnusedInputBitSets[thrset] )
347 if thrset
is not None:
348 log.debug(
"Unused threshold set %s: %s", thrset,
",".
join(ctpUnusedInputNameSets[thrset]) )
350 log.debug(
"Unrecognised CTP input bits: %s",
",".
join(ctpUnusedInputNameSets[thrset]) )
351 totalUnusedInputs += ctpUnusedInputBitSets[thrset]
352 log.debug(
"Number of un-used inputs bits: %i" , totalUnusedInputs )
355 if ( totalInputs > Limits.MaxTrigItems
or len(ctpOutputs) > Limits.MaxTrigItems):
357 log.warning(f
"Input or output bits limit of {Limits.MaxTrigItems} exceeded in the dummy CTP menu -- OK")
359 raise RuntimeError(
"Both the numbers of inputs and outputs need to be not greater than %i in a physics menu!" % Limits.MaxTrigItems)
363 for item
in self.
items:
364 if len(item.bunchGroups)==1
and item.bunchGroups[0]==
'BGRP0':
365 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)
366 if 'BGRP2' in item.bunchGroups:
367 thrtype = item.logic.content[
'threshold'].ttype
368 if thrtype
in ThrType.CaloTypes():
371 raise RuntimeError(f
"L1 item {item.name} with threshold type {thrtype} is in CALREQ BGRP2. This is not allowed!")
379 for thrtype
in ThrType.Run3Types():
381 inputtype = thrtype.name
382 if inputtype ==
'cTAU':
384 for key, value
in ttconfig.items():
385 if "ptMinToTopo" in key:
386 if inputtype
in ptMin:
387 if ptMin[inputtype] > value:
388 ptMin[inputtype] = value
390 ptMin[inputtype] = value
394 for algo
in self.
topoAlgos.topoAlgos[AlgCategory.MULTI][AlgType.MULT]:
395 alg = self.
topoAlgos.topoAlgos[AlgCategory.MULTI][AlgType.MULT][algo]
396 threshold = alg.threshold
397 inputtype = alg.input
398 if 'cTAU' in inputtype:
400 elif any(substring
in inputtype
for substring
in [
'XE',
'TE',
'MHT',
'LArSaturation',
'ZeroBias']):
404 if hasattr(thr,
'thresholdValues'):
405 etvalues = thr.thresholdValues
406 for etvalue
in etvalues:
410 if hasattr(thr,
'et'):
413 if inputtype
in thresholdMin:
414 if minEt < thresholdMin[inputtype]:
415 thresholdMin[inputtype] = minEt
417 thresholdMin[inputtype] = minEt
420 for algo
in self.
topoAlgos.topoAlgos[AlgCategory.TOPO][AlgType.SORT]:
421 alg = self.
topoAlgos.topoAlgos[AlgCategory.TOPO][AlgType.SORT][algo]
422 if alg.inputvalue ==
'MuonTobs':
424 for (pos, variable)
in enumerate(alg.variables):
425 if variable.name ==
"MinET":
426 value = variable.value/10
428 if alg.inputvalue ==
'eEmTobs':
430 elif alg.inputvalue ==
'eTauTobs':
432 elif alg.inputvalue ==
'jJetTobs':
435 raise RuntimeError(
"checkPtMinToTopo: input type %s in sorting algo not recognised" % alg.inputvalue)
436 if inputtype
in thresholdMin:
437 if value < thresholdMin[inputtype]:
438 thresholdMin[inputtype] = value
440 thresholdMin[inputtype] = value
441 for thr
in thresholdMin:
443 if thresholdMin[thr] < ptMin[thr]:
444 raise RuntimeError(
"checkPtMinToTopo: for threshold type %s the minimum threshold %i is less than ptMinToTopo %i" % (thr, thresholdMin[thr], ptMin[thr]))
446 raise RuntimeError(
"checkPtMinToTopo: for threshold type %s the minimum threshold is %i and no ptMinToTopo value is found" % (thr, thresholdMin[thr]))
449 from ..Menu.L1TopoParams
import L1TopoParams
as params
451 algo_param_mismatch = []
453 for algtype
in [AlgType.SORT, AlgType.DEC]:
455 for algname,algo
in self.
topoAlgos.topoAlgos[AlgCategory.TOPO][algtype].
items():
456 log.debug(f
'Checking variable parameter ordering for {algname} ({algo.classtype})')
457 pars_for_algo = params[algo.classtype]
458 generics_map = {g.name:g.value
for g
in algo.generics}
461 ordered_params =
None
462 if 'common_parameters' in pars_for_algo:
463 common_params = pars_for_algo[
'common_parameters']
464 if 'parameters' in pars_for_algo:
465 ordered_params = pars_for_algo[
'parameters']
467 if common_params
is None and ordered_params
is None:
468 for cond
in pars_for_algo.keys():
469 if cond ==
'comment':
continue
472 pass_condition =
True
473 for c
in cond.split(
' and '):
474 condname, condval = c.split(
' = ')
475 if condname
in generics_map:
476 if int(condval) == generics_map[condname]:
479 pass_condition =
False
481 elif int(condval) == 0:
484 pass_condition =
False
488 if 'common_parameters' in pars_for_algo[cond]:
489 common_params = pars_for_algo[cond][
'common_parameters']
490 if 'parameters' in pars_for_algo[cond]:
491 ordered_params = pars_for_algo[cond][
'parameters']
494 if common_params
is None and ordered_params
is None and common_params
is None:
495 raise RuntimeError(f
'checkL1TopoParams: Did not find ordered parameter list for L1Topo algorithm type {algo.classtype}')
497 menu_params = [p.name
for p
in algo.variables]
498 log.debug(f
'Menu contains parameter list: {menu_params}')
500 if common_params
is None: common_params = []
501 if ordered_params
is None: ordered_params = []
502 log.debug(f
'Expected parameter list: {common_params + ordered_params}')
506 non_common_param_count = len(menu_params) - len(common_params)
507 if non_common_param_count > len(ordered_params):
508 log.debug(f
'Can repeat the parameters: {ordered_params}')
509 if non_common_param_count % len(ordered_params) == 0:
510 ordered_params =
int(non_common_param_count/len(ordered_params)) * ordered_params
512 log.error(
"Mismatch in number of parameters")
514 total_params = common_params + ordered_params
515 if menu_params != total_params:
516 log.error(f
'checkL1TopoParams: Parameter list for {algo.name}/{algo.classtype} does not match specification')
517 log.error(f
' Menu contains parameter list {menu_params}')
518 log.error(f
' Expected parameter list {total_params}')
519 algo_param_mismatch.append(algo)
521 if algo_param_mismatch:
522 log.error(
'checkL1TopoParams: Following L1Topo algorithms have incorrect parameter ordering in L1Menu:')
523 for algo
in algo_param_mismatch:
524 log.error(f
' {algo.name} ({algo.classtype})')
525 raise RuntimeError(
'checkL1TopoParams: L1Topo algorithm parameters do not match specification')
529 connected_boards = []
530 for layout,connectors
in self.
ctp.inputConnectors.items():
531 for connector, contents
in connectors.items():
534 connected_boards += [board
for board
in contents.values()
if board]
536 connected_boards.append(contents)
538 for conn_name
in connected_boards:
540 if conn.ctype != CType.ELEC:
541 for tl
in conn.triggerLines:
543 if thrName[:3]==
'ZB_':
544 thrName = thrName[3:]
545 all_ctpin.append(thrName)
547 for fpga
in conn.triggerLines:
548 for clock
in conn.triggerLines[fpga]:
549 for tl
in conn.triggerLines[fpga][clock]:
551 if thrName[:3]==
'ZB_':
552 thrName = thrName[3:]
553 all_ctpin.append(thrName)
555 for item
in self.
items:
556 for thrName
in item.thresholdNames():
557 if thrName[:3]==
'ZB_':
558 thrName = thrName[3:]
559 if thrName
not in all_ctpin:
561 f
'checkItemsHaveInputs: Threshold {thrName} used by {item.name} is not on a board connected to CTP')