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