ATLAS Offline Software
Loading...
Searching...
No Matches
DQUtilities.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3import os
4from DQDefects import DefectsDB
5from DQUtils.sugar import IOVSet, RunLumiType, RunLumi, define_iov_type
6from DQUtils import fetch_iovs, process_iovs
7
8
9# Exception classes
10class DefectError(Exception):
11 """Defect exception class."""
12
13
14@define_iov_type
15def DEFECTIOV_VAL(defect, present):
16 "IOV type to solidify upon with an extra present element"
17 pass
18
19class IDBSDefectWriter:
20 """
21 Class for writing BS defects to an sqlite file
22 """
23
24 def __init__(self,fileName, forceNew=False, dbName='IDBSDQ', tag='nominal', user='sys:dqBeamSpot'):
25 """
26 Initialise database connection
27 """
28 self.defect = None
29 self.iovs = IOVSet()
30 self.user = user
31
32 #self.allowedDefects = DefectsDB('').defect_names
33
34 if not fileName: fileName = 'tmp.'+str(os.getpid())+'.db'
35
36 self.connect(fileName, forceNew, dbName, tag)
37
38 pass
39
40 def __del__(self):
41 """
42 Delete db to clear connection
43 """
44
45 os.system('[[ -f tmp.%s.db ]] && rm tmp.%s.db' %(os.getpid(), os.getpid()))
46 del self.db
47 pass
48
49
50 def connect(self, fileName, forceNew=False, dbName='IDBSDQ', tag='nominal'):
51 """
52 Open connection to defect DB
53 """
54
55 connString = 'sqlite://;schema=%s;dbname=%s' % (fileName,dbName)
56
57 if forceNew and os.path.exists(fileName):
58 os.remove(fileName)
59
60 self.db = DefectsDB(connString, read_only=False, create=True, tag=(tag, 'HEAD')) # Second tag is for virtual defects, which we are not interested in
61
63
64 return
65
66 def defectType(self,t):
67 """
68 Set defect type
69 """
70 self.defect = t
71
72 def add(self,runMin=0, runMax=(1 << 31)-1, lbMin=0, lbMax=(1 << 32)-1):
73 """
74 Add iovs which are NOT defective to the list
75 Note, lbMax is exclusive here (and inclusive when shown on defect web page).
76 """
77
78 # Make since and until and convert to syntactially nice RunLumiType
79 since = RunLumiType((runMin << 32)+lbMin)
80 until = RunLumiType((runMax << 32)+lbMax)
81
82 # IoVs which are not defective (i.e. beamspot good)
83 self.iovs.add(since, until, self.defect, False)
84 return
85
86
87 def complete(self, runMin, runMax):
88 """
89 Complete a list of IoVs to cover all LBs in a run, treating empty ones as having 'emptyState'
90
91 """
92
93 # Create an IOV set covering the entire run(s)
94 run_lbs = fetch_iovs("EOR", runs=(runMin, runMax), what=[], with_channel=False)
95
96
97 # run_lbs = IOVSet()
98 # lbMin = 1
99 # lbMax = (1 << 32) -1 # Note, lbMax is exclusive
100 # since = RunLumiType((runMin << 32)+lbMin)
101 # until = RunLumiType((runMax << 32)+lbMax)
102 # run_lbs.add(since, until)
103
104 if not len(run_lbs):
105 print ("WARNING: No LBs in run according to EOR_Params - are we running before the run has finished?")
106
107 def lbsStartAtOne(iov):
108 "Change LBs starting at 0 to start at 1"
109 return iov._replace(since=RunLumi(iov.since.run, 1))
110
111 # Start LBs from 1 rather than 0 (at request of P. Onyisi) as long as run has more than one LB (else skip)
112 run_lbs = [lbsStartAtOne(iov) for iov in run_lbs if iov.until.lumi > 1]
113
114 # Empty IOV set for adding full list of LBs too
115 iovs = IOVSet()
116
117 # Ask official DB if an IoV is currently defective so can unset only those if doing reprocessing
118 defectsCurrentlyInDb = self.officialDb.retrieve((runMin, 0), (runMax+1, 0), [self.defect])
119
120 # Order IOVs to avoid since > until
121 self.iovs = IOVSet(sorted(self.iovs))
122
123 #for since, until, (run_lb, iov, dbDefect) in process_iovs(run_lbs.solidify(RANGEIOV_VAL), self.iovs.solidify(DEFECTIOV_VAL), defectsCurrentlyInDb):
124 for since, until, (run_lb, iov, dbDefect) in process_iovs(run_lbs, self.iovs.solidify(DEFECTIOV_VAL), defectsCurrentlyInDb):
125 if not run_lb: continue # Check valid
126
127# # Start LBs from 1 rather than 0 (at request of P. Onyisi)
128# # If this makes since==until, i.e. it was a [0->1) LB range then skip
129# if since.lumi==0:
130# since = RunLumiType((since.run << 32)+since.lumi+1)
131# if since==until: continue
132
133 # Add iovs from self.iovs treating empty ones as defective (i.e. beamspot bad/missing)
134 if iov:
135 # These are not defective
136 if dbDefect and dbDefect.present:
137 # Only store not defective IoVs if they are present on the Db so we can unset them
138 # (don't want to write not present defects to Db unless really chaning an existing defect)
139 iovs.add(since, until, self.defect, False)
140 else:
141 # These are defective
142 iovs.add(since, until, self.defect, True)
143
144 self.iovs = iovs
145 return
146
147 def writeDefects(self, tag='nominal', nonpresent=False):
148 """
149 Write all defects to the database. If 'nonpresent' is True then write the absent ones too
150 """
151
152 with self.db.storage_buffer:
153 for since, until, defect, present in self.iovs:
154 if not present and not nonpresent: continue
155 #print (since, until, present)
156 self._writeDefect(defect, since, until, present = present)
157
158 def _writeDefect(self,defect, since, until, tag='nominal', description='', comment='', present=True, recoverable=False):
159 """
160 Write a single defect to the database
161 """
162
163 if defect not in self.db.defect_names:
164 self.db.create_defect(defect, description)
165
166 self.db.insert(defect, since, until, comment, self.user, present, recoverable)
167
168 return
169
170 def dump(self, filename = None):
171 """
172 Dump defects to a file given by filename or stdout if no filename given
173 """
174
175 from DQUtils.utils import pprint_objects
176
177 if filename is not None:
178 f = open(filename.replace('.db', '.txt'), "w")
179 # If not defects then nothing will be in the database and we write an empty file
180 if len(self.iovs):
181 pprint_objects(self.db.retrieve(primary_only=True, nonpresent=True), f)
182 f.close()
183 else:
184 if len(self.iovs):
185 self.iovs.pprint()
186 else:
187 print ('\nNo DQ defects')
188
189 # with open(filename.replace('.db', '.txt'), "w") as f:
190 # pprint_objects(self.db.retrieve(), f)
191
192
193 return
194
195
197 """
198 Container for beamspot DQ defects from COOL
199 """
200
201 defectBitPos = ['UNKNOWN', 'ID_BS_2010YELLOW', 'ID_BS_RUNAVERAGE', 'ID_BS_PARAMETERSTEP',
202 'ID_BS_NOBEAMSPOT', 'ID_BS_2010RED', 'LUMI_VDM']
203
204
205 def __init__(self, database='COOLOFL_GLOBAL/CONDBR2', tag='HEAD', debug=False):
206 #def __init__(self, database='dqflags.db/IDBSDQ', tag='nominal', debug=False):
207 """
208 Initialise database connection
209 """
210
211 self.database = database
212 self.tag = tag
213 self.lastRun = None
214 self.iovsets = None
215 self.debug = debug
216
217 self.connect()
218
219 pass
220
221 def __del__(self):
222 """
223 Delete db to clear connection
224 """
225
226 del self.db
227 pass
228
229
230 def connect(self):
231 """
232 Open connection to defect DB
233 """
234
235 self.db = DefectsDB(self.database, read_only=True, create=False, tag=self.tag)
236 self.idbsDefects = [d for d in self.db.defect_names if d.startswith('ID_BS_') or d == 'LUMI_VDM']
237
238 if self.debug:
239 print (self.idbsDefects)
240
241 return
242
243 def defectList(self):
244 """
245 List of all possible beamspot defects
246 """
247
248 return self.idbsDefects
249
250 def defect(self, run, lb, channels=None):
251 """
252 Get list of DQ defects for a particular run and lb, caching the result for the latest (succesful) run
253 e.g.
254 from InDetBeamSpotExample.DQUtilities import IDBSDefectData
255 idbs = IDBSDefectData()
256 idbs.defect(167661,372)
257
258 channels is the list of defects to look for (defaults to all ID_BS defects)
259 """
260
261 if channels is None:
262 channels = self.idbsDefects
263
264 # Encode start and end of run
265 lbMin = 0
266 lbMax = (1 << 32)-1
267 since = (run << 32)+lbMin
268 until = (run << 32)+lbMax
269
270 # If the run is the same at the previous one return defects from cache
271 if run == self.lastRun:
272 defects = self._defectForLB(lb)
273 if self.debug:
274 print (run, lb, defects)
275 return defects
276
277 # Retrieve info for entire run
278 iovs = self.db.retrieve(since, until, channels=channels)
279
280 # Check if run exists
281 if not iovs:
282 print ("Unable to access folder with given parameters")
283 return []
284
285 # If found, update last run and get list of IOVSets for each defect/channel
286 self.lastRun = run
287 chans, self.iovsets = iovs.chans_iovsets
288
289 defects = self._defectForLB(lb)
290
291 # Debug
292 if self.debug:
293 iovs.pprint()
294 print (run, lb, defects)
295
296 return defects
297
298 def _defectForLB(self, lb):
299 """
300 Get the DQ defects for the given LB from the full run info
301 """
302
303 defects = []
304 for since, until, states in process_iovs(*self.iovsets):
305 if since.lumi <= lb < until.lumi:
306 # defects is true if set for a given run/LB
307 defects = [state.channel for state in states if state]
308
309 return list(set(defects))
310
311
312 def defectsRange(self, run, lbStart, lbEnd, channels=None):
313 """
314 Return the maximal list of defects for a given range. lbEnd is exclusive
315 """
316
317 defects = []
318 for lb in range(lbStart, lbEnd):
319 defects.extend(self.defect(run, lb, channels=channels))
320
321 return list(set(defects))
322
323 def dumpRun(self, run, channels=None):
324 """
325 Dump DQ info for a particular run (useful in reprocessing to compare new to old)
326 """
327
328 if channels is None:
329 channels = self.idbsDefects
330
331 # Encode start and end of run
332 lbMin = 0
333 lbMax = (1 << 32)-1
334 since = (run << 32)+lbMin
335 until = (run << 32)+lbMax
336
337 # Retrieve info for entire run
338 iovs = self.db.retrieve(since, until, channels=channels, nonpresent=True)
339
340 # Check if run exists
341 if not iovs:
342 print ("Unable to access folder with given parameters")
343 return []
344
345 iovs.pprint()
346
347 return
348
350 """
351 Class to enocode and decode IDBS defects. No instances fo this class can be instanciated
352 and it bascially just acts as a poor man's namespace (should really be a module)
353 """
354
355 defectBitPos = ['UNKNOWN', 'ID_BS_2010YELLOW', 'ID_BS_RUNAVERAGE', 'ID_BS_PARAMETERSTEP',
356 'ID_BS_NOBEAMSPOT', 'ID_BS_2010RED', 'LUMI_VDM']
357
358 @classmethod
359 def defectToInt(cls, defect):
360 """Encode defect as an int. If defect is unknown raise error"""
361
362 if defect not in IDBSDefectEncoding.defectBitPos:
363 raise DefectError ('ERROR: Unknown defect %s encountered' % defect)
364
365 return (1 << IDBSDefectEncoding.defectBitPos.index(defect))
366
367 @classmethod
368 def defectListToInt(cls, defects):
369 """Encode list of defects as an int. If no defect (empty list) returns 0 for bakcward compatibility"""
370 return sum([cls.defectToInt(d) for d in defects])
371
372 @classmethod
373 def intToDefectList(cls, dint):
374 """Decode int as list of defects. Raise error if unkown defect encountered"""
375
376 # Convert int to binary string with correct endianess
377 binStr = bin(dint)[2:][::-1]
378
379 if len(binStr) > len(IDBSDefectEncoding.defectBitPos):
380 raise DefectError ("ERROR: integer %s out of range" % dint)
381
382 # If dint is odd then has the unknown bit set
383 if bool(dint & 1):
384 raise DefectError ('ERROR: Unknown defect encountered')
385
386 return [d[0] for d in zip(IDBSDefectEncoding.defectBitPos,binStr) if d[1]=='1']
dumpRun(self, run, channels=None)
defectsRange(self, run, lbStart, lbEnd, channels=None)
__init__(self, database='COOLOFL_GLOBAL/CONDBR2', tag='HEAD', debug=False)
defect(self, run, lb, channels=None)
writeDefects(self, tag='nominal', nonpresent=False)
__init__(self, fileName, forceNew=False, dbName='IDBSDQ', tag='nominal', user='sys:dqBeamSpot')
connect(self, fileName, forceNew=False, dbName='IDBSDQ', tag='nominal')
add(self, runMin=0, runMax=(1<< 31) -1, lbMin=0, lbMax=(1<< 32) -1)
_writeDefect(self, defect, since, until, tag='nominal', description='', comment='', present=True, recoverable=False)
complete(self, runMin, runMax)
STL class.
-event-from-file
DEFECTIOV_VAL(defect, present)