ATLAS Offline Software
Loading...
Searching...
No Matches
Items.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3from __future__ import annotations
4from typing import Iterator
5
6from AthenaCommon.Logging import logging
7
8from ..Config.MonitorDef import MonitorDef
9from .PrescaleHelper import getCutFromPrescale, getPrescaleFromCut
10from .MenuUtils import binstr
11
12
13log = logging.getLogger(__name__)
14
15
17
18 splitBunchGroups = True
19
20 def __init__(self):
21 self.menuName: str = ''
22 self.pssName: str = ''
23 self.pssType = 'Physics'
24 self.items: dict[str, MenuItem] = {}
25
26 def __iter__(self) -> Iterator[MenuItem]:
27 return iter(self.items.values())
28
29 def __getitem__(self, name: str) -> MenuItem:
30 return self.items[name]
31
32 def __setitem__(self, name: str, item: MenuItem):
33 if item is None:
34 return self
35 if name in self.items:
36 log.warning("LVL1 item %s is already in the menu, will not add it again", name)
37 return self
38 if (existingItem := self.itemById(item.ctpid)) is not None:
39 log.warning("LVL1 item %s with CTP ID %i is already in the menu, will not add %s", existingItem.name, item.ctpid, name)
40 return self
41 self.items[name] = item
42 return self
43
44 def __iadd__(self, item: MenuItem | None):
45 if item is None:
46 return self
47 if item.name in self.items:
48 msg = "LVL1 item %s is already in the menu, will not add it again" % item.name
49 log.error(msg)
50 raise RuntimeError(msg)
51 if (existingItem := self.itemById(item.ctpid)) is not None:
52 msg = (
53 f"LVL1 item {existingItem.name} with CTP ID {existingItem.ctpid} is already in the menu,"
54 f" will not add {item.name} with the same CTP ID {item.ctpid}"
55 )
56 log.error(msg)
57 raise RuntimeError(msg)
58 self.items[item.name] = item
59 return self
60
61 def __contains__(self, itemname):
62 return itemname in self.items
63
64 def __len__(self):
65 return len(self.items)
66
67 def itemById(self, ctpid: int) -> MenuItem | None:
68 """Returns the MenuItem with given CTP ID
69
70 Args:
71 ctpid (int): CTP ID
72
73 Returns:
74 MenuItem | None: The MenuItem with the given CTP ID, or None if not found.
75 """
76 itemById = {it.ctpid:it for it in self.items.values()}
77 return itemById.get(ctpid)
78
79 def itemNames(self):
80 return self.items.keys()
81
82 def json(self):
83 confObj = {item.name: item.json() for item in self}
84 return confObj
85
86
88
89 # global variable for item registration, if set, new items will be registered with l1configForRegistration (type TriggerConfigL1)
90 l1configForRegistration = None
91
92 @staticmethod
94 MenuItem.l1configForRegistration = mc
95
96 # New items will be assigned to this partition
97 currentPartition = 0
98
99 __slots__ = ['name', 'group', 'ctpid', 'psCut', 'trigger_type', 'partition', 'logic', 'bunchGroups', 'legacy', 'monitorsLF', 'monitorsHF', 'verbose']
100 def __init__(self, name: str, ctpid=-1, group='1', prescale=1, psCut=None, verbose=False):
101 self.name: str = name
102 self.group = group
103 self.ctpid: int = int(ctpid)
104 self.psCut = psCut if psCut is not None else getCutFromPrescale(prescale)
106 self.partition = MenuItem.currentPartition
107 self.logic = None
108 self.monitorsLF = 0
109 self.monitorsHF = 0
110 self.verbose: bool = verbose
111 self.bunchGroups: list[str] = []
112 self.legacy: bool = False
113
114 if MenuItem.l1configForRegistration:
115 MenuItem.l1configForRegistration.registerItem(self.name, self)
116
117 def __str__(self):
118 s = "Item %s (ctp id=%i) [%s]" % (self.name, self.ctpid, self.logic)
119 return s
120
121 @property
122 def prescale(self):
123 return getPrescaleFromCut(self.psCut)
124
125 @prescale.setter
126 def prescale(self, prescale):
127 self.psCut = getCutFromPrescale(prescale)
128 return self
129
130 def addMonitor(self, flag, frequency):
131 if frequency == MonitorDef.LOW_FREQ:
132 self.monitorsLF |= flag
133 if frequency == MonitorDef.HIGH_FREQ:
134 self.monitorsHF |= flag
135
136 def setLogic(self, logic):
137 if MenuItemsCollection.splitBunchGroups:
138 (self.logic, self.bunchGroups) = logic.stripBunchGroups(logic)
139 else:
140 self.logic = logic
141 return self
142
143 def setCtpid(self, x):
144 self.ctpid = int(x)
145 return self
146
147 def thresholdNames(self, include_bgrp=False):
148 if self.logic is not None:
149 return self.logic.thresholdNames(include_bgrp)
150 else:
151 return []
152
153 def conditions(self, include_internal=False):
154 if self.logic is not None:
155 return self.logic.conditions(include_internal)
156 else:
157 return []
158
159 def setTriggerType(self, ttype):
160 self.trigger_type = int(ttype) & 0xff
161 return self
162
163 def markLegacy(self,legacyThresholdsSet):
164 self.legacy = bool ( legacyThresholdsSet.intersection(self.thresholdNames()) )
165
166 def binary_trigger_type(self, width=8):
167 """Turns integer triggertype in a binary string of given width"""
168 return binstr(self.trigger_type, width=width)
169
170 def json(self):
171 confObj = {}
172 confObj["name"] = self.name
173 if self.legacy:
174 confObj["legacy"] = self.legacy
175 confObj["ctpid"] = self.ctpid
176 confObj["definition"] = str(self.logic)
177 if self.bunchGroups:
178 confObj["bunchgroups"] = self.bunchGroups
179 confObj["triggerType"] = self.binary_trigger_type(8 if self.partition==1 else 4)
180 confObj["partition"] = self.partition
181 confObj["monitor"] = 'LF:{0:03b}|HF:{1:03b}'.format(self.monitorsLF,self.monitorsHF)
182 return confObj
183
184
185
186
187class PrescaleHandler(object):
188 def __init__(self, name, psType, menuitems):
189 self.name = name
190 self.psType = psType
191 self.items = menuitems
193
194 for item in menuitems:
195 self.itemsByPartition.setdefault(item.partition,[]).append(item)
196
197 for itemList in self.itemsByPartition.values():
198 itemList.sort(key = lambda x: x.ctpid)
199
200
202 def __getattr__(cls, attr):
203 import traceback
204 isTopo = any(filter(lambda x: attr.startswith(x), ["R2TOPO_", "TOPO_", "MUTOPO_", "MULTTOPO_"]))
205 fs = traceback.extract_stack()[-2]
206 expProdFile = "L1/Config/"
207 if isTopo:
208 if attr.startswith("R2TOPO_"):
209 expProdFile += "TopoAlgoDefLegacy.py"
210 elif attr.startswith("TOPO_"):
211 expProdFile += "TopoAlgoDef.py"
212 elif attr.startswith("MUTOPO_"):
213 expProdFile += "TopoAlgoDefMuctpi.py"
214 elif attr.startswith("MULTTOPO_"):
215 expProdFile += "TopoMultiplicityAlgoDef.py"
216 else:
217 isLegacyThr = any(filter(lambda x: attr.startswith(x), ["EM", "TAU", "J", "XE", "TE", "XS"]))
218 if isLegacyThr:
219 expProdFile += "ThresholdDefLegacy.py"
220 else:
221 expProdFile += "ThresholdDef.py"
222
223 msg = "Item definition issue in file %s, line %i. Threshold %s has not been defined in %s" % ('/'.join(fs.filename.rsplit('/',4)[1:]),fs.lineno, attr, expProdFile)
224 log.error(msg)
225 raise RuntimeError(msg)
nlohmann::json json
binary_trigger_type(self, width=8)
Definition Items.py:166
addMonitor(self, flag, frequency)
Definition Items.py:130
thresholdNames(self, include_bgrp=False)
Definition Items.py:147
conditions(self, include_internal=False)
Definition Items.py:153
__init__(self, str name, ctpid=-1, group='1', prescale=1, psCut=None, verbose=False)
Definition Items.py:100
setTriggerType(self, ttype)
Definition Items.py:159
markLegacy(self, legacyThresholdsSet)
Definition Items.py:163
MenuItem __getitem__(self, str name)
Definition Items.py:29
__setitem__(self, str name, MenuItem item)
Definition Items.py:32
__iadd__(self, MenuItem|None item)
Definition Items.py:44
MenuItem|None itemById(self, int ctpid)
Definition Items.py:67
Iterator[MenuItem] __iter__(self)
Definition Items.py:26
__init__(self, name, psType, menuitems)
Definition Items.py:188