ATLAS Offline Software
Loading...
Searching...
No Matches
ids.py
Go to the documentation of this file.
1# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
2
3from logging import getLogger; log = getLogger("DQDefects.defect_ids")
4
5from ctypes import Structure, c_uint, Union as cUnion
6
7from DQUtils.channel_mapping import get_channel_ids_names
8
9from .exceptions import (DefectUnknownError,
10 InvalidLogicTagError)
11
12from typing import Set, Iterable, Tuple, Union, List
13from collections.abc import Mapping, MutableMapping
14
15
16class DefectIDBitfield(Structure):
17 _fields_ = [("defect", c_uint, 31),
18 ("is_virtual", c_uint, 1),
19 ]
20
21 def __repr__(self):
22 args = (bool(self.is_virtual), self.defect)
23 return "(is_virtual=%s, defect=%i)" % args
24
25
26class DefectID(cUnion):
27 _fields_ = [("as_int", c_uint),
28 ("as_bitfield", DefectIDBitfield)]
29
30 def __int__(self):
31 return self.as_int
32
33 def __getattr__(self, what):
34 if any(what == field[0] for field in DefectIDBitfield._fields_):
35 return getattr(self.as_bitfield, what)
36 raise AttributeError(what)
37
38 def __setattr__(self, what, value):
39 if any(what == field[0] for field in DefectIDBitfield._fields_):
40 return setattr(self.as_bitfield, what, value)
41 return super(DefectID, self).__setattr__(what, value)
42
43 def __repr__(self):
44 args = self.as_int, self.as_bitfield
45 return '<DefectID value=0x%08x fields=%r>' % args
46
47def choose_new_defect_id(existing_map: Mapping[Union[str, int], Union[str,int]],
48 defect_name: str, virtual: bool = False) -> int:
49 """
50 Function to create a new defect ID.
51
52 We're abandoning the mapping of defect names to IDs (Oct 2012).
53 Hence here we just ask for the first open gap in ID numbers.
54 It works for virtual IDs as well, though via a bit of an edge case for
55 when none exist yet.
56 """
57 existing = sorted(_ for _ in existing_map.values() if not isinstance(_, str))
58 if len(existing) == 0:
59 newid = 0
60 else:
61 newid = None
62 for i, v in enumerate(existing[1:]):
63 if v-existing[i] > 1:
64 newid = existing[i]+1
65 break
66 if newid is None:
67 newid = existing[-1] + 1
68 did = DefectID(newid)
69 did.is_virtual=virtual
70 log.debug("Chose new id: %r", did)
71 return int(did)
72
74 """
75 Contains the logic for storing knowledge of which defects exist, and their
76 channel names and IDs
77 """
78 def __init__(self) -> None:
79 self._initialized = False
81 self._defect_id_map: MutableMapping[Union[str,int], Union[str,int]] = {}
82 self._defect_ids: Set[int] = set()
83 self._defect_names: Set[str] = set()
84 self._virtual_defect_id_map: MutableMapping[Union[str,int], Union[str,int]] = {}
85 self._virtual_defect_ids: Set[int] = set()
86 self._virtual_defect_names: Set[str] = set()
87 super(DefectsDBIDsNamesMixin, self).__init__()
88
89 def _populate_defect_ids(self) -> None:
90 """
91 Called the first time any of defect_{ids,names,id_map,etc} is called,
92 and populates internal variables to store the channel ids/names for the
93 life of the DefectsDB instance.
94 """
95 ids, names, mapping = get_channel_ids_names(self.defects_folder)
96 self._defect_ids = set(ids)
97 self._defect_names = set(names)
98 self._defect_id_map = mapping
99
101 """
102 Called the first time any of virtual_defect_{ids,names,id_map,etc} is called,
103 and populates internal variables to store the channel ids/names for the
104 life of the DefectsDB instance.
105 """
106 _, _, mapping = get_channel_ids_names(self.defect_logic_folder)
107 try:
108 self._virtual_defect_names = set(self.virtual_defect_logics.keys())
109 self._virtual_defect_ids = set(mapping[name] for name in self._virtual_defect_names)
110 all_defects = self._virtual_defect_names | self._virtual_defect_ids
111 self._virtual_defect_id_map = dict(item for item in mapping.items()
112 if item[0] in all_defects)
113 except InvalidLogicTagError:
114 # Presumably this tag doesn't exist yet, which is ok if we're about
115 # to create some new virtual defects. ?
117 self._virtual_defect_ids = set()
119
120 def _new_defect(self, did: int, dname: str) -> None:
121 """
122 Internal function used to keep defect IDs/names uptodate.
123 """
124 self.defect_ids.add(did)
125 self.defect_names.add(dname)
126 self.defect_id_map[did] = dname
127 self.defect_id_map[dname] = did
128
129 def _new_virtual_defect(self, did: int, dname: str) -> None:
130 """
131 Internal function used to keep defect IDs/names uptodate.
132 """
133 self.virtual_defect_ids.add(did)
134 self.virtual_defect_names.add(dname)
135 self.virtual_defect_id_map[did] = dname
136 self.virtual_defect_id_map[dname] = did
137 # Reset this so we will reload logic later
139
140 @property
141 def defect_ids(self) -> Set[int]:
142 """
143 Gives the set of defect IDs that exist in COOL
144 """
145 if not self._initialized:
147 self._initialized = True
148 return self._defect_ids
149
150 @property
151 def defect_names(self) -> Set[str]:
152 """
153 Gives the set of defect names that exist in COOL
154 """
155 if not self._initialized:
157 self._initialized = True
158 assert self._defect_names is not None, self._initialized
159 return self._defect_names
160
161 @property
162 def defect_id_map(self) -> MutableMapping[Union[str,int], Union[str,int]]:
163 """
164 Gives the dictionary relating COOL channel ids to defect names and vice
165 versa, retrieving them from the database if necessary.
166 """
167 if not self._initialized:
169 self._initialized = True
170 return self._defect_id_map
171
172 @property
173 def virtual_defect_ids(self) -> Set[int]:
174 """
175 Returns the set of existing virtual defect IDs
176 """
177 if not self._virtual_initialized:
179 self._virtual_initialized = True
180 return self._virtual_defect_ids
181
182 @property
183 def virtual_defect_names(self) -> Set[str]:
184 """
185 Returns the set of existing virtual defect names
186 """
187 if not self._virtual_initialized:
189 self._virtual_initialized = True
190 return self._virtual_defect_names
191
192 @property
193 def virtual_defect_id_map(self) -> MutableMapping[Union[str,int], Union[str,int]]:
194 """
195 Returns a dict() mapping virtual defect names to IDs and vice-versa.
196 """
197 if not self._virtual_initialized:
199 self._virtual_initialized = True
200 return self._virtual_defect_id_map
201
202 def defect_chan_as_id(self, channel: Union[str, int], primary_only: bool = False) -> int:
203 """
204 Returns the defect ID for a virtual defect.
205 Accepts a `channel` as an integer/string and returns it as an integer.
206
207 Will raise DefectUnknownError if `channel` is an unknown ID or string.
208
209 This function first checks against non-virtual defects, then virutal
210 defects. Thus virtual-defects are lazily loaded.
211 """
212 from builtins import int
213 if isinstance(channel, int):
214 if (channel not in self.defect_ids and
215 (not primary_only and channel not in self.virtual_defect_ids)):
216 raise DefectUnknownError(channel)
217 return channel
218 elif isinstance(channel, str):
219 if channel in self.defect_names:
220 return self.defect_id_map[channel]
221 if not primary_only and channel in self.virtual_defect_names:
222 return self.virtual_defect_id_map[channel]
223 raise DefectUnknownError(channel)
224 raise RuntimeError("Invalid `channel` type, got %s, expected integer"
225 " or string" % type(channel))
226
227 def defect_names_as_ids(self, channels: Iterable[Union[str, int]]) -> List[int]:
228 """
229 Returns a list of channels as IDs
230 """
231 return [self.defect_chan_as_id(chan) for chan in channels]
232
233 def get_channels(self) -> Tuple[Set[int], Set[str], Mapping[Union[str, int], Union[str, int]]]:
234 """
235 Return channel IDs, names, and dict relating the two
236 """
237 return self.defect_ids, self.defect_names, self.defect_id_map
238
239 def get_virtual_channels(self) -> Tuple[Set[int], Set[str], Mapping[Union[str, int], Union[str, int]]]:
240 """
241 Return channel IDs, names, and dict relating the two
242 """
244
245 def get_channel_descriptions(self, channels: Iterable[Union[str, int]]) -> MutableMapping[Union[str, int], str]:
246 """
247 For the list of channel IDs "channels", return dict mapping ID to
248 description
249 """
250 get_desc = self.defects_folder.channelDescription
251 return {channel: get_desc(self.defect_chan_as_id(channel))
252 for channel in channels}
253
254 def get_virtual_channel_descriptions(self, channels: Iterable[Union[str, int]]) -> MutableMapping[Union[str, int], str]:
255 """
256 For the list of channel IDs "channels", return dict mapping ID to
257 descriptiondefect_id
258 """
259 get_desc = self.defect_logic_folder.channelDescription
260 return {channel: get_desc(self.defect_chan_as_id(channel))
261 for channel in channels}
262
263 @property
264 def all_defect_descriptions(self) -> Mapping[Union[str, int], str]:
265 """
266 A dictionary of all (virtual and primary) defect descriptions
267 """
268 result = self.get_channel_descriptions(self.defect_names)
270 result.update(gvcd(self.virtual_defect_names))
271 return result
272
273 def set_channel_description(self, channel: Union[str, int], description: str) -> None:
274 """
275 Set a defect description
276 """
277 chan_id = self.defect_chan_as_id(channel)
278 if self.defect_is_virtual(chan_id):
279 folder = self.defect_logic_folder
280 else:
281 folder = self.defects_folder
282 folder.setChannelDescription(chan_id, description.encode('utf-8'))
283
284 def defect_is_virtual(self, defect_id: Union[str, int]) -> bool:
285 """
286 Returns True if the `defect_id` represents a virtual defect, False if it
287 is not and raises if it doesn't exist
288
289 Parameters:
290 `defect_id` : defect channel id or name
291 """
292 from builtins import int
293 if isinstance(defect_id, int):
294 return DefectID(defect_id).is_virtual
295
296 if not isinstance(defect_id, str):
297 raise RuntimeError("Invalid defect_id, expected int or string")
298
299 if defect_id in self.defect_names:
300 return False
301
302 if defect_id in self.virtual_defect_names:
303 return True
304
305 raise DefectUnknownError(defect_id)
306
307 def normalize_defect_names(self, defect_id: Union[str, Iterable[str]]) -> Union[str, List[str]]:
308 """
309 Returns correct name(s) of defects, given name(s) that possibly differ
310 from the correct ones by case. Raises if an input name doesn't map to
311 any existing defect. You can pass either a string or an iterable
312 object as `defect_id`.
313 """
314 wasstring = False
315 if isinstance(defect_id, str):
316 defect_id = [defect_id]
317 wasstring = True
318 if any(not isinstance(i, str) for i in defect_id):
319 raise ValueError('All input values must be strings')
320
321 uppered_defects = dict((i.upper(), i) for i in self.defect_names)
322 uppered_defects.update(dict((i.upper(), i) for i in self.virtual_defect_names))
323
324 rv = []
325 for i in defect_id:
326 up = i.upper()
327 if up in uppered_defects:
328 rv.append(uppered_defects[up])
329 else:
330 raise DefectUnknownError(i)
331
332 if wasstring:
333 return rv[0]
334 else:
335 return rv
__int__(self)
Definition ids.py:30
__repr__(self)
Definition ids.py:43
__getattr__(self, what)
Definition ids.py:33
__setattr__(self, what, value)
Definition ids.py:38
None _new_defect(self, int did, str dname)
Definition ids.py:120
MutableMapping[Union[str, int], str] get_channel_descriptions(self, Iterable[Union[str, int]] channels)
Definition ids.py:245
None set_channel_description(self, Union[str, int] channel, str description)
Definition ids.py:273
MutableMapping[Union[str, int], Union[str, int]] defect_id_map(self)
Definition ids.py:162
Tuple[Set[int], Set[str], Mapping[Union[str, int], Union[str, int]]] get_virtual_channels(self)
Definition ids.py:239
None _populate_virtual_defect_ids(self)
Definition ids.py:100
Tuple[Set[int], Set[str], Mapping[Union[str, int], Union[str, int]]] get_channels(self)
Definition ids.py:233
MutableMapping[Union[str, int], Union[str, int]] virtual_defect_id_map(self)
Definition ids.py:193
None _new_virtual_defect(self, int did, str dname)
Definition ids.py:129
Union[str, List[str]] normalize_defect_names(self, Union[str, Iterable[str]] defect_id)
Definition ids.py:307
bool defect_is_virtual(self, Union[str, int] defect_id)
Definition ids.py:284
Mapping[Union[str, int], str] all_defect_descriptions(self)
Definition ids.py:264
int defect_chan_as_id(self, Union[str, int] channel, bool primary_only=False)
Definition ids.py:202
None _populate_defect_ids(self)
Definition ids.py:89
List[int] defect_names_as_ids(self, Iterable[Union[str, int]] channels)
Definition ids.py:227
MutableMapping[Union[str, int], str] get_virtual_channel_descriptions(self, Iterable[Union[str, int]] channels)
Definition ids.py:254
STL class.
bool add(const std::string &hname, TKey *tobj)
Definition fastadd.cxx:55
int choose_new_defect_id(Mapping[Union[str, int], Union[str, int]] existing_map, str defect_name, bool virtual=False)
Definition ids.py:48