ATLAS Offline Software
Loading...
Searching...
No Matches
Connectors.py
Go to the documentation of this file.
1# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2
3from enum import Enum
4
5from AthenaCommon.Logging import logging
6
7from .TopoAlgorithms import AlgCategory
8
9log = logging.getLogger(__name__)
10
11class CType(Enum):
12 CTPIN = (1, 'ctpin')
13 ELEC = (2, 'electrical')
14 OPT = (3, 'optical')
15 GLOBAL = (4, 'global')
16 def __init__(self, _, ctype ):
17 self.ctype = ctype
18
19 def __str__(self):
20 return self.ctype
21
22 @staticmethod
23 def from_str(label):
24 if label == 'ctpin':
25 return CType.CTPIN
26 elif label == 'electrical':
27 return CType.ELEC
28 elif label == 'optical':
29 return CType.OPT
30 elif label.lower() == 'global':
31 return CType.GLOBAL
32 else:
33 raise NotImplementedError("Connector of type %s does't exist" % label)
34
35
36class CFormat(Enum):
37 MULT = (1, 'multiplicity')
38 TOPO = (2, 'topological')
39 SIMPLE = (3, 'simple')
40 def __init__(self, _, cformat ):
41 self.cformat = cformat
42
43 @staticmethod
44 def from_str(label):
45 if label == 'multiplicity':
46 return CFormat.MULT
47 elif label == 'topological':
48 return CFormat.TOPO
49 elif label == 'simple':
50 return CFormat.SIMPLE
51 else:
52 raise NotImplementedError
53
54
55
57 def __init__(self):
58 self.connectors = {}
59
60 def __iter__(self):
61 return iter(self.connectors.values())
62
63 def __contains__(self, name):
64 return name in self.connectors
65
66 def __getitem__(self, name):
67 return self.connectors[name]
68
69 def addConnector(self, connDef):
70 name, cformat, ctype = map(connDef.__getitem__,["name", "format", "type"])
71 legacy = connDef.get("legacy", False)
72
73 if name in self.connectors:
74 raise RuntimeError("Connector %s has already been defined" % name)
75
76 log.debug("Adding connector %s, format %s, legacy set to %s, and connType %s", name, cformat, legacy, ctype)
77 if CType.from_str(ctype) is CType.ELEC:
78 newConnector = ElectricalConnector(name, cformat, legacy, connDef)
79 elif CType.from_str(ctype) is CType.CTPIN:
80 newConnector = CtpinConnector(name, legacy, connDef)
81 elif CType.from_str(ctype) is CType.OPT:
82 newConnector = OpticalConnector(name, cformat, ctype, legacy, connDef)
83 else:
84 newConnector = GlobalConnector(name, connDef)
85 self.connectors[name] = newConnector
86
87 def json(self):
88 confObj = {}
89 for conn in self.connectors.values():
90 confObj[conn.name] = conn.json()
91 return confObj
92
93
94
95
97 __slots__ = ['name', 'cformat', 'ctype', 'legacy', 'boardName', 'triggerLines', 'emptyTriggerLines']
98 def __init__(self, connDef):
99 """
100 @param name name of the connector
101 @param cformat can be 'topological' or 'multiplicity'
102 @param ctype can be 'ctpin', 'electrical', or 'optical'
103 """
104 name, cformat, ctype, boardName = map(connDef.__getitem__,["name", "format", "type", "board"])
105 legacy = connDef.get("legacy", False)
106 self.name = name
107 self.cformat = CFormat.from_str(cformat)
108 self.ctype = CType.from_str(ctype)
109 self.legacy = bool(legacy)
110 self.boardName = boardName
111 self.triggerLines = []
112 self.emptyTriggerLines = [] # Empty placeholders in the output fibers/cables, to ensure correst alignment of the triggerLines bits
113
114 def addTriggerLine(self, tl: 'TriggerLine'):
115 self.triggerLines.append(tl)
116
117 def addEmptyTriggerLine(self, tl):
118 self.emptyTriggerLines.append(tl)
119
120 def isLegacy(self):
121 return self.legacy
122
124 return [x.name for x in self.triggerLines]
125
126 def json(self):
127 confObj = {}
128 confObj["type"] = str(self.ctype)
129 if self.legacy:
130 confObj["legacy"] = self.legacy
131 confObj["triggerlines"] = [tl.json() for tl in self.triggerLines]
132 return confObj
133
134
136 __slots__ = ['name', 'cformat', 'ctype', 'triggerLines', 'emptyTriggerLines']
137 def __init__(self, name, connDef):
138 """
139 @param name name of the connector
140 """
141 super(GlobalConnector,self).__init__(connDef = connDef)
142
143 # treat differently depending on the "format", which can be: 'topological' or 'multiplicity'
144 if self.cformat == CFormat.MULT:
145 # multiplicity connectors contain all the triggerlines in a flat "thresholds" list
146 startbit = 0
147 nbits = connDef.get("nbitsDefault",1)
148 for thrName in connDef["thresholds"]:
149 if type(thrName)==tuple:
150 (thrName, nbits) = thrName
151
152 if thrName is None:
153 self.addEmptyTriggerLine(EmptyTriggerLine(startbit, nbits))
154 else:
155 self.addTriggerLine(TriggerLine(name=thrName, startbit=startbit, flatindex=startbit, nbits=nbits))
156
157 startbit += nbits
158
159 else:
160 raise RuntimeError("Property 'format' of connector %s is '%s' but must be 'multiplicity'" % (name,connDef["format"]))
161
162
164 __slots__ = ['name', 'legacy', 'triggerLines', 'emptyTriggerLines']
165 def __init__(self, name, legacy, connDef):
166 """
167 @param name name of the connector
168 @param legacy is 'true' for legacy L1Calo connectors
169 """
170 super(CtpinConnector,self).__init__(connDef = connDef)
171
172 # connectors contain all the triggerlines in a flat "thresholds" list
173 startbit = 0
174 for thrName in connDef["thresholds"]:
175 nbits = connDef["nbitsDefault"]
176 if type(thrName)==tuple:
177 (thrName, nbits) = thrName
178
179 if thrName is None:
180 self.addEmptyTriggerLine(EmptyTriggerLine(startbit, nbits))
181 else:
182 self.addTriggerLine(TriggerLine(name=thrName, startbit=startbit, flatindex=startbit, nbits=nbits))
183
184 startbit += nbits
185
186
188 __slots__ = ['name', 'cformat', 'ctype', 'legacy', 'triggerLines', 'emptyTriggerLines']
189 def __init__(self, name, cformat, ctype, legacy, connDef):
190 """
191 @param name name of the connector
192 @param cformat can be 'topological' or 'multiplicity'
193 @param ctype can be 'ctpin', 'electrical', or 'optical'
194 """
195 super(OpticalConnector,self).__init__(connDef = connDef)
196
197 # treat differently depending on the "format", which can be: 'topological' or 'multiplicity'
198 if self.cformat == CFormat.MULT:
199 # multiplicity connectors contain all the triggerlines in a flat "thresholds" list
200 startbit = 0
201 for thrName in connDef["thresholds"]:
202 nbits = connDef["nbitsDefault"]
203 if type(thrName)==tuple:
204 (thrName, nbits) = thrName
205
206 if thrName is None:
207 self.addEmptyTriggerLine(EmptyTriggerLine(startbit, nbits))
208 else:
209 self.addTriggerLine(TriggerLine(name=thrName, startbit=startbit, flatindex=startbit, nbits=nbits))
210
211 startbit += nbits
212
213 else:
214 raise RuntimeError("Property 'format' of connector %s is '%s' but must be either 'multiplicity' or 'topological', however 'topological' is not yet implemented" % (name,connDef["format"]))
215
216
218 def __init__(self, name, cformat, legacy, connDef):
219 """
220 @param name name of the connector
221 @param cformat can be 'topological' or 'simple'
222 """
223 super(ElectricalConnector,self).__init__(connDef = connDef)
224 self.triggerLines = { 0 : {0:[],1:[]}, 1 : {0:[],1:[]} }
225
226 if self.cformat == CFormat.TOPO:
227 # topological connectors when they are electrical
228 # connectors contain the triggerlines in up to four
229 # algorithm groups, each corresponding to a different (fpga,clock) setting
230 currentTopoCategory = AlgCategory.getCategoryFromBoardName(self.boardName)
231 for thrG in connDef["algorithmGroups"]:
232 fpga,clock = map(thrG.__getitem__,["fpga","clock"])
233 for topo in thrG["algorithms"]:
234 bit = topo.outputbits[0] if isinstance(topo.outputbits, tuple) else topo.outputbits
235 for (i, tl) in enumerate(topo.outputlines):
236 # for topological triggerlines the names have to be prefixed as they are in the item definitions
237 tlname = currentTopoCategory.prefix + tl
238 startbit = bit+i
239 flatindex = 32*fpga + 2*startbit + clock
240 self._addTriggerLineByFpgaClock( TriggerLine( name = tlname, startbit = startbit, flatindex = flatindex, nbits = 1, fpga = fpga, clock = clock ), fpga, clock )
241 elif self.cformat == CFormat.SIMPLE:
242 for sigG in connDef["signalGroups"]:
243 clock = sigG["clock"]
244 startbit = 0
245 for signal in sigG["signals"]:
246 nbits = connDef["nbitsDefault"]
247 if type(signal)==tuple:
248 (signal,nbits) = signal
249 if signal is None:
250 startbit += nbits
251 continue
252 # use a single flatindex value for the Topo legacy boards
253 flatindex = 2*startbit + clock
254 tl = TriggerLine( name = signal, startbit = startbit, flatindex = flatindex, nbits = nbits, fpga = None, clock = clock)
255 startbit += nbits
256 self._addTriggerLineByFpgaClock(tl, 0, clock)
257 else:
258 raise RuntimeError("Property 'format' of connector %s is '%s' but must be either 'simple' or 'topological'" % (name,connDef["format"]))
259
260
261 def _addTriggerLineByFpgaClock(self, tl, fpga, clock):
262 self.triggerLines[fpga][clock].append( tl )
263
265 thr = self.triggerLines[0][0] + self.triggerLines[0][1] + self.triggerLines[1][0] + self.triggerLines[1][1]
266 return [x.name for x in thr]
267
268 def json(self):
269 confObj = {}
270 confObj["type"] = str(self.ctype)
271 if self.legacy:
272 confObj["legacy"] = self.legacy
273 confObj["triggerlines"] = {}
274 if self.cformat == CFormat.TOPO:
275 _triggerLines = []
276 for fpga in [0,1]:
277 for clock in [0,1]:
278 _triggerLines += [tl.json() for tl in self.triggerLines[fpga][clock]]
279 confObj["triggerlines"] = _triggerLines
280 elif self.cformat == CFormat.SIMPLE:
281 _triggerLines = []
282 for clock in [0,1]:
283 _triggerLines += [tl.json() for tl in self.triggerLines[0][clock]]
284 confObj["triggerlines"] = _triggerLines
285 return confObj
286
287
289 def __init__(self, name, startbit, nbits, flatindex=None, fpga=None, clock=None):
290 self.name = name
291 self.startbit = startbit
292 self.flatindex = flatindex # for electrical cables
293 self.nbits = nbits
294 self.fpga = fpga
295 self.clock = clock
296
297 def json(self):
298 confObj = {}
299 confObj["name"] = self.name
300 confObj["startbit"] = self.startbit
301 if self.flatindex is not None:
302 confObj["flatindex"] = self.flatindex
303 confObj["nbits"] = self.nbits
304 if self.fpga is not None:
305 confObj["fpga"] = self.fpga
306 if self.clock is not None:
307 confObj["clock"] = self.clock
308 return confObj
309
310 @property
311 def endbit(self) -> int:
312 return self.startbit + self.nbits - 1
313
314
315
317 def __init__(self, startbit: int, nbits: int):
318 self.startbit = startbit
319 self.nbits = nbits
320
321 @property
322 def endbit(self) -> int:
323 return self.startbit + self.nbits - 1
nlohmann::json json
STL class.
addTriggerLine(self, 'TriggerLine' tl)
__init__(self, name, legacy, connDef)
_addTriggerLineByFpgaClock(self, tl, fpga, clock)
__init__(self, name, cformat, legacy, connDef)
__init__(self, int startbit, int nbits)
__init__(self, name, cformat, ctype, legacy, connDef)
__init__(self, name, startbit, nbits, flatindex=None, fpga=None, clock=None)