ATLAS Offline Software
ids.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
2 
3 from logging import getLogger; log = getLogger("DQDefects.defect_ids")
4 
5 from ctypes import Structure, c_uint, Union as cUnion
6 
7 from DQUtils.channel_mapping import get_channel_ids_names
8 
9 from .exceptions import (DefectUnknownError,
10  InvalidLogicTagError)
11 
12 from typing import Set, Iterable, Tuple, Union, List
13 from collections.abc import Mapping, MutableMapping
14 
15 
16 class 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 
26 class 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 
47 def 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
80  self._virtual_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 
100  def _populate_virtual_defect_ids(self) -> None:
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. ?
116  self._virtual_defect_names = set()
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:
146  self._populate_defect_ids()
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:
156  self._populate_defect_ids()
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:
168  self._populate_defect_ids()
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
DerivationFramework::TriggerMatchingUtils::sorted
std::vector< typename R::value_type > sorted(const R &r, PROJ proj={})
Helper function to create a sorted vector from an unsorted range.
python.ids.DefectsDBIDsNamesMixin._defect_ids
_defect_ids
Definition: ids.py:96
python.ids.DefectsDBIDsNamesMixin.virtual_defect_id_map
MutableMapping[Union[str, int], Union[str, int]] virtual_defect_id_map(self)
Definition: ids.py:193
python.ids.DefectsDBIDsNamesMixin.virtual_defect_ids
Set[int] virtual_defect_ids(self)
Definition: ids.py:173
python.ids.DefectsDBIDsNamesMixin.defect_ids
Set[int] defect_ids(self)
Definition: ids.py:141
python.ids.DefectsDBIDsNamesMixin._virtual_initialized
_virtual_initialized
Definition: ids.py:80
python.ids.DefectsDBIDsNamesMixin._virtual_defect_map
_virtual_defect_map
Definition: ids.py:118
python.ids.DefectsDBIDsNamesMixin._new_defect
None _new_defect(self, int did, str dname)
Definition: ids.py:120
python.ids.DefectsDBIDsNamesMixin._virtual_defect_logics
_virtual_defect_logics
Definition: ids.py:138
python.channel_mapping.get_channel_ids_names
def get_channel_ids_names(folder)
Definition: channel_mapping.py:99
python.ids.DefectsDBIDsNamesMixin.defect_names_as_ids
List[int] defect_names_as_ids(self, Iterable[Union[str, int]] channels)
Definition: ids.py:227
python.ids.DefectsDBIDsNamesMixin._virtual_defect_ids
_virtual_defect_ids
Definition: ids.py:109
python.ids.DefectsDBIDsNamesMixin._populate_virtual_defect_ids
None _populate_virtual_defect_ids(self)
Definition: ids.py:100
python.ids.DefectsDBIDsNamesMixin._defect_id_map
_defect_id_map
Definition: ids.py:98
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
python.ids.DefectIDBitfield.__repr__
def __repr__(self)
Definition: ids.py:21
python.ids.DefectsDBIDsNamesMixin._initialized
_initialized
Definition: ids.py:79
python.ids.DefectsDBIDsNamesMixin.all_defect_descriptions
Mapping[Union[str, int], str] all_defect_descriptions(self)
Definition: ids.py:264
python.exceptions.DefectUnknownError
Definition: exceptions.py:6
python.ids.DefectsDBIDsNamesMixin.__init__
None __init__(self)
Definition: ids.py:78
python.ids.DefectsDBIDsNamesMixin.defect_chan_as_id
int defect_chan_as_id(self, Union[str, int] channel, bool primary_only=False)
Definition: ids.py:202
python.ids.DefectID.__setattr__
def __setattr__(self, what, value)
Definition: ids.py:38
python.ids.DefectsDBIDsNamesMixin.virtual_defect_names
Set[str] virtual_defect_names(self)
Definition: ids.py:183
python.ids.DefectsDBIDsNamesMixin.get_channel_descriptions
MutableMapping[Union[str, int], str] get_channel_descriptions(self, Iterable[Union[str, int]] channels)
Definition: ids.py:245
python.ids.DefectsDBIDsNamesMixin.normalize_defect_names
Union[str, List[str]] normalize_defect_names(self, Union[str, Iterable[str]] defect_id)
Definition: ids.py:307
add
bool add(const std::string &hname, TKey *tobj)
Definition: fastadd.cxx:55
python.ids.DefectsDBIDsNamesMixin._defect_names
_defect_names
Definition: ids.py:97
python.ids.DefectsDBIDsNamesMixin.defect_names
Set[str] defect_names(self)
Definition: ids.py:151
python.ids.DefectsDBIDsNamesMixin.defect_id_map
MutableMapping[Union[str, int], Union[str, int]] defect_id_map(self)
Definition: ids.py:162
python.ids.DefectsDBIDsNamesMixin._virtual_defect_names
_virtual_defect_names
Definition: ids.py:108
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
python.ids.DefectID.__repr__
def __repr__(self)
Definition: ids.py:43
python.ids.DefectsDBIDsNamesMixin.get_virtual_channel_descriptions
MutableMapping[Union[str, int], str] get_virtual_channel_descriptions(self, Iterable[Union[str, int]] channels)
Definition: ids.py:254
python.ids.DefectsDBIDsNamesMixin._virtual_defect_id_map
_virtual_defect_id_map
Definition: ids.py:111
python.ids.DefectID
Definition: ids.py:26
python.ids.DefectsDBIDsNamesMixin._populate_defect_ids
None _populate_defect_ids(self)
Definition: ids.py:89
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
python.ids.DefectsDBIDsNamesMixin.get_virtual_channels
Tuple[Set[int], Set[str], Mapping[Union[str, int], Union[str, int]]] get_virtual_channels(self)
Definition: ids.py:239
python.ids.DefectsDBIDsNamesMixin.defect_is_virtual
bool defect_is_virtual(self, Union[str, int] defect_id)
Definition: ids.py:284
python.ids.choose_new_defect_id
int choose_new_defect_id(Mapping[Union[str, int], Union[str, int]] existing_map, str defect_name, bool virtual=False)
Definition: ids.py:47
python.ids.DefectsDBIDsNamesMixin
Definition: ids.py:73
python.ids.DefectsDBIDsNamesMixin.set_channel_description
None set_channel_description(self, Union[str, int] channel, str description)
Definition: ids.py:273
python.ids.DefectsDBIDsNamesMixin.get_channels
Tuple[Set[int], Set[str], Mapping[Union[str, int], Union[str, int]]] get_channels(self)
Definition: ids.py:233
pickleTool.object
object
Definition: pickleTool.py:29
python.ids.DefectsDBIDsNamesMixin._new_virtual_defect
None _new_virtual_defect(self, int did, str dname)
Definition: ids.py:129
python.Bindings.keys
keys
Definition: Control/AthenaPython/python/Bindings.py:801
python.ids.DefectIDBitfield
Definition: ids.py:16
xAOD::bool
setBGCode setTAP setLVL2ErrorBits bool
Definition: TrigDecision_v1.cxx:60
python.ids.DefectID.__getattr__
def __getattr__(self, what)
Definition: ids.py:33
python.CaloCondLogger.getLogger
def getLogger(name="CaloCond")
Definition: CaloCondLogger.py:16
python.ids.DefectID.__int__
def __int__(self)
Definition: ids.py:30