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