ATLAS Offline Software
Loading...
Searching...
No Matches
TileCalibCrest.py
Go to the documentation of this file.
1#!/bin/env python
2
3# Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
4# TileCalibCrest.py
5# Sanya Solodkov <Sanya.Solodkov@cern.ch>, 2025-02-04
6# Laura Sargsyan <Laura.Sargsyan@cern.ch>, 2025-09-16
7# Siarhei Harkusha <Siarhei.Harkusha@cern.ch>, 2025-05-19
8
9"""
10Python helper module for managing CREST DB connections and TileCalibBlobs.
11"""
12
13import os, re, cppyy, base64, json, time, datetime
14
15from PyCool import cool # noqa: F401
16Blob = cppyy.gbl.coral.Blob
17
18from pycrest.api.crest_api import CrestApi
19
20from TileCalibBlobObjs.Classes import TileCalibUtils, TileCalibDrawerCmt, \
21 TileCalibDrawerInt, TileCalibDrawerOfc, TileCalibDrawerBch, \
22 TileCalibDrawerFlt, TileCalibType
23from TileCalibBlobPython import TileCalibTools
24
25#=== get a logger
26from TileCalibBlobPython.TileCalibLogger import TileCalibLogger, getLogger
27log = getLogger("TileCalibCrest")
28
29
30#======================================================================
31#===
32#=== Global helper functions
33#===
34#======================================================================
35
36#
37#______________________________________________________________________
38#=== useful constants
39MINRUN = 0
40MINLBK = 0
41MAXRUN = (1<<31)-1
42MAXLBK = (1<<32)-1
43MAXRUNLUMI = (MAXRUN<<32)+MAXLBK
44# empty Tile channel for storing laser partition variation. DO NOT CHANGE.
45LASPARTCHAN = 43
46
47
48class TileBlobReaderCrest(TileCalibLogger):
49 """
50 TileCalibBlobReader is a helper class, managing the details of CREST interactions for
51 the user of TileCalibBlobs.
52 """
53
54 #____________________________________________________________________
55 def __init__(self, db, folder='', tag='', run=None, lumi=0, modmin=0, modmax=275, copyBlob=False):
56 """
57 Input:
58 - db : server connection string or file name
59 - folder: full folder path
60 - tag : The folder tag, e.g. \"UPD4-24\" or full tag
61 - run : Run number (if known)
62 - lumi : Lumi block number
63 - modmin: Minimal module (COOL channel number)
64 - modmax: Maximal module (COOL channel number)
65 - copyBlob: save payload from CREST (Default:False, True to copy payload to json file)
66 """
67 #=== initialize base class
68 TileCalibLogger.__init__(self,"TileBlobReader")
69 self.payload = {}
70 self.__db = db
71 self.__folder = folder
72 self.__tag = tag
73 self.__copyBlob = copyBlob
74
75 self.__iovList = []
76 self.__iov = (-1,0)
77 self.__commentBlob = None
78 self.__drawerBlob = [None]*276
79 self.__comment = None
80 self.__drawer = [None]*276
81 self.__modmin = modmin
82 self.__modmax = modmax+1
83
84 #=== try to open db
85 self.__remote = (("http://" in db) or ("https://" in db) or ("CREST" in db))
86 if self.__remote:
87 if 'http' not in self.__db:
88 self.__db = os.getenv(db,os.getenv('CREST_HOST',os.getenv('CREST_SERVER_PATH','https://atlas-crest-dev-mgr.cern.ch:443/api-v6.0')))
89 self.log().info('Host %s' , (self.__db))
90 self.__api_instance = CrestApi(host=self.__db)
91 socks = os.getenv('CREST_SOCKS', 'False')
92 if socks == 'True': self.__api_instance.socks()
93 self.__tag = self.getFolderTag(folder,None,tag)
94 if run is not None and lumi is not None:
95 log.info("Initializing for run %d, lumiblock %d", run,lumi)
96 self.__getIov((run,lumi),True)
97 else:
98 self.log().info('File %s' , (self.__db))
99 self.__api_instance = None
100 self.__tag = 'unknown'
101 self.__iovList.append(((MINRUN,MINLBK),(MAXRUN, MAXLBK)))
102 self.__iov = self.__runlumi2iov(self.__iovList[-1])
103 with open(self.__db, 'r') as the_file:
104 jdata = json.load(the_file)
105 if self.__copyBlob:
106 self.payload = jdata
107 return
108 for chan in range(self.__modmin,self.__modmax):
109 try:
110 blob=jdata[str(chan)][0]
111 except Exception:
112 blob=None
113 self.__create_drawer(blob,chan)
114 try:
115 blob=jdata['1000'][0]
116 except Exception:
117 blob=None
118 self.__create_comment(blob)
119
120 #____________________________________________________________________
121 def getTag(self):
122 return self.__tag
123
124 #____________________________________________________________________
125 def getFolderTag(self, folder, prefix, globalTag, api=None):
126 if globalTag=='CURRENT' or globalTag=='UPD4' or globalTag=='' or globalTag=='HEAD':
127 globalTag=TileCalibTools.getAliasFromFile('Current')
128 log.info("Resolved CURRENT globalTag to \'%s\'", globalTag)
129 elif globalTag=='CURRENTES' or globalTag=='UPD1':
130 globalTag=TileCalibTools.getAliasFromFile('CurrentES')
131 log.info("Resolved CURRENT ES globalTag to \'%s\'", globalTag)
132 elif globalTag=='NEXT':
133 globalTag=TileCalibTools.getAliasFromFile('Next')
134 log.info("Resolved NEXT globalTag to \'%s\'", globalTag)
135 elif globalTag=='NEXTES':
136 globalTag=TileCalibTools.getAliasFromFile('NextES')
137 log.info("Resolved NEXT ES globalTag to \'%s\'", globalTag)
138 globalTag=globalTag.replace('*','')
139 if prefix is None:
140 prefix = ''
141 for f in folder.split('/'):
142 if re.findall('[a-z]+',f) != [] and f!='CellNoise':
143 prefix+=f
144 else:
145 prefix+=f.capitalize()
146 else:
147 prefix=prefix.strip('-').split('-')[0]
148 if prefix.startswith('Calo') and 'NoiseCell' not in prefix:
149 prefix='CALO'+prefix[4:]
150 prefix=prefix.replace('Pileupnoiselumi','PileUpNoiseLumi')
151 if 'UPD1' in globalTag or 'UPD4' in globalTag or ('COND' not in globalTag and 'CREST' not in globalTag):
152 if prefix != '':
153 if prefix in globalTag or prefix.upper() in globalTag:
154 tag=globalTag
155 else:
156 tag=prefix+'-'+globalTag
157 self.log().info("Resolved localTag \'%s\' to folderTag \'%s\'", globalTag,tag)
158 elif folder!='' and not (globalTag.upper().startswith('TILE') or globalTag.upper().startswith('CALO')):
159 tag = TileCalibUtils.getFullTag(folder, globalTag)
160 if tag.startswith('Calo') and 'NoiseCell' not in tag:
161 tag='CALO'+tag[4:]
162 tag=tag.replace('Pileupnoiselumi','PileUpNoiseLumi')
163 self.log().info("Resolved localTag \'%s\' to folderTag \'%s\'", globalTag,tag)
164 else:
165 tag=globalTag
166 self.log().info("Use localTag \'%s\' as is", tag)
167 else:
168 tag=None
169 if api:
170 tags=api.find_global_tag_map(globalTag)
171 elif self.__api_instance:
172 tags=self.__api_instance.find_global_tag_map(globalTag)
173 else:
174 return globalTag
175 if tags.size==0:
176 raise Exception( "globalTag %s not found" % (globalTag) )
177 else:
178 for i in range(tags.size):
179 t=tags.resources[i].tag_name
180 l=tags.resources[i].label
181 if (prefix!='' and t.startswith(prefix)) or l==folder:
182 tag=t
183 self.log().info("Resolved globalTag \'%s\' to folderTag \'%s\'", globalTag,tag)
184 #taginfo = self.__api_instance.find_tag(name=tag)
185 #print(taginfo)
186 return tag
187
188 #____________________________________________________________________
189 def getIovs(self,since=(MINRUN,MINLBK),until=(MAXRUN,MAXLBK)):
190 if self.__api_instance is None:
191 return [self.__iovList[0][0]]
192 else:
193 run_lumi1=str((since[0]<<32)+since[1]+1)
194 run_lumi2=str((until[0]<<32)+until[1]+1)
195 MAXRUNLUMI1=str(MAXRUNLUMI+1)
196 iovs1=self.__api_instance.select_iovs(self.__tag,"0",run_lumi1,sort='id.since:DESC,id.insertionTime:DESC',size=1,snapshot=0)
197 iovs2=self.__api_instance.select_iovs(self.__tag,run_lumi2,MAXRUNLUMI1,sort='id.since:ASC,id.insertionTime:DESC',size=1,snapshot=0)
198 since1=0 if iovs1.size==0 else iovs1.resources[0].since
199 until1=MAXRUNLUMI if iovs2.size==0 else iovs2.resources[0].since
200 iovs=self.__api_instance.select_iovs(self.__tag,str(since1),str(until1),sort='id.since:ASC,id.insertionTime:DESC',size=999999,snapshot=0)
201 iovList=[]
202 if iovs.size==0:
203 raise Exception( "IOV for tag %s IOV [%s,%s] - (%s,%s) not found" % (self.__tag,since[0],since[1],until[0],until[1]) )
204 else:
205 for i in range(iovs.size):
206 iov=iovs.resources[i]
207 since=int(iov.since)
208 runS=since>>32
209 lumiS=since&0xFFFFFFFF
210 if (runS,lumiS) not in iovList:
211 iovList.append((runS,lumiS))
212 return iovList
213
214 #____________________________________________________________________
215 def getIov(self, option=0):
216 if option!=0:
217 return self.__iov
218 else:
219 return self.__iovList[-1]
220
221 #____________________________________________________________________
222 def __getIov(self,runlumi,dbg=False):
223 if self.__api_instance is None:
224 pass
225 else:
226 run_lumi1=str((runlumi[0]<<32)+runlumi[1]+1)
227 MAXRUNLUMI1=str(MAXRUNLUMI+1)
228 iovs1=self.__api_instance.select_iovs(self.__tag,"0",run_lumi1,sort='id.since:DESC,id.insertionTime:DESC',size=1,snapshot=0)
229 iovs2=self.__api_instance.select_iovs(self.__tag,run_lumi1,MAXRUNLUMI1,sort='id.since:ASC,id.insertionTime:DESC',size=1,snapshot=0)
230 if iovs1.size==0:
231 raise Exception( "IOV for tag %s run,lumi (%s,%s) not found" % (self.__tag,runlumi[0],runlumi[1]) )
232 else:
233 iov=iovs1.resources[0]
234 since=int(iov.since)
235 runS=since>>32
236 lumiS=since&0xFFFFFFFF
237 until=MAXRUNLUMI if iovs2.size==0 else iovs2.resources[0].since
238 runU=until>>32
239 lumiU=until&0xFFFFFFFF
240 hash=iov.payload_hash
241 if dbg:
242 #self.log().info('Run,Lumi (%d,%d)' , runlumi)
243 self.log().info('IOV [%d,%d] - (%d,%d)' , runS,lumiS,runU,lumiU)
244 self.log().info('Insertion time %s' , iov.insertion_time)
245 self.log().info('Hash %s' , hash)
246 payload = self.__api_instance.get_payload(hash=hash).decode('utf-8')
247 jdata=json.loads(payload)
248 #with open("payload.json", 'w') as the_file:
249 # the_file.write(payload)
250 # the_file.write('\n')
251 self.__iovList.append(((runS,lumiS),(runU, lumiU)))
252 self.__iov = self.__runlumi2iov(self.__iovList[-1])
253 if self.__copyBlob:
254 self.payload = jdata
255 return
256 for chan in range(self.__modmin,self.__modmax):
257 try:
258 blob=jdata[str(chan)][0]
259 except Exception:
260 blob=None
261 self.__create_drawer(blob,chan)
262 try:
263 blob=jdata['1000'][0]
264 except Exception:
265 blob=None
266 self.__create_comment(blob)
267 return
268
269 #____________________________________________________________________
270 def __runlumi2iov(self,runlumi):
271 since = (runlumi[0][0]<<32) + runlumi[0][1]
272 until = (runlumi[1][0]<<32) + runlumi[1][1]
273 return (since,until)
274
275 #____________________________________________________________________
276 def __checkIov(self,runlumi):
277 point = (runlumi[0]<<32) + runlumi[1]
278 inrange = point>=self.__iov[0] and point<self.__iov[1]
279 return inrange
280
281 #____________________________________________________________________
282 def __make_blob(self,string):
283 b = Blob()
284 b.write(string)
285 b.seek(0)
286 return b
287
288 #____________________________________________________________________
289 def __create_comment(self,b64string):
290 if b64string is None or len(b64string)==0:
291 if b64string is None:
292 self.__commentBlob = None
293 else:
294 self.__commentBlob = 0
295 self.__comment = None
296 else:
297 blob1 = base64.decodebytes(bytes(b64string,'ascii'))
298 self.__commentBlob = self.__make_blob(blob1)
300 return
301
302 #____________________________________________________________________
303 def __create_drawer(self,b64string,chan):
304 if b64string is None or isinstance(b64string, (int, float)) or len(b64string)==0:
305 if b64string is None:
306 self.__drawerBlob[chan] = None
307 else:
308 self.__drawerBlob[chan] = 0
309 self.__drawer[chan] = None
310 return
311 blob1 = base64.decodebytes(bytes(b64string,'ascii'))
312 self.__drawerBlob[chan] = self.__make_blob(blob1)
314 typeName = TileCalibType.getClassName(cmt.getObjType())
315 del cmt
316 #=== create calibDrawer depending on type
317 if typeName=='TileCalibDrawerFlt':
319 self.log().debug( "typeName = Flt " )
320 elif typeName=='TileCalibDrawerInt':
322 self.log().debug( "typeName = Int " )
323 elif typeName=='TileCalibDrawerBch':
325 self.log().debug( "typeName = Bch " )
326 elif typeName=='TileCalibDrawerOfc':
328 self.log().debug( "typeName = Ofc " )
329 elif typeName=='TileCalibDrawerCmt':
330 self.__drawer[chan] = cppyy.gbl.CaloCondBlobFlt.getInstance(self.__drawerBlob[chan])
331 self.log().debug( "typeName = CaloFlt " )
332 else:
333 self.__drawer[chan] = None
334 self.log().warn("Unknown blob type for chan %d - ignoring", chan)
335 return
336
337 #____________________________________________________________________
338 def getPayload(self, runlumi=None, dbg=False):
339
340 if self.__remote and runlumi is not None and not self.__checkIov(runlumi):
341 self.__getIov(runlumi,dbg)
342
343 return self.payload
344
345 #____________________________________________________________________
346 def getBlob(self,ros, mod, runlumi=None, dbg=False):
347
348 if self.__remote and runlumi is not None and not self.__checkIov(runlumi):
349 self.__getIov(runlumi,dbg)
350
351 chanNum = getDrawerIdx(ros,mod)
352
353 if (chanNum>=0 and chanNum<len(self.__drawer)):
354 return self.__drawerBlob[chanNum]
355 else:
356 raise Exception( "Invalid drawer requested: %s %s" % (ros,mod) )
357
358 #____________________________________________________________________
359 def getDrawer(self,ros, mod, runlumi=None, dbg=False, useDefault=True):
360
361 if self.__remote and runlumi is not None and not self.__checkIov(runlumi):
362 self.__getIov(runlumi,dbg)
363
364 chanNum = getDrawerIdx(ros,mod)
365
366 if (chanNum>=0 and chanNum<len(self.__drawer)):
367 drawer=self.__drawer[chanNum]
368 if not useDefault and drawer is None:
369 if self.__drawerBlob[chanNum] is None:
370 return None
371 else:
372 return 0
373 while drawer is None:
374 #=== no default at all?
375 if ros==0 and drawer==0:
376 raise Exception('No default available')
377 #=== follow default policy
378 ros,mod = self.getDefault(ros,mod)
379 chanNum = getDrawerIdx(ros,mod)
380 drawer=self.__drawer[chanNum]
381 return drawer
382 elif (chanNum == 1000):
383 return self.__comment
384 else:
385 raise Exception( "Invalid drawer requested: %s %s" % (ros,mod) )
386
387 #____________________________________________________________________
388 def getComment(self,runlumi=None,split=False):
389
390 if self.__remote and runlumi is not None and not self.__checkIov(runlumi):
391 self.__getIov(runlumi)
392 if self.__comment is not None:
393 if split:
394 return (self.__comment.getAuthor(),self.__comment.getComment(),self.__comment.getDate())
395 else:
396 return self.__comment.getFullComment()
397 else:
398 return "<no comment found>"
399
400 #____________________________________________________________________
401 def getDefault(self, ros, drawer):
402 """
403 Returns a default drawer number (among first 20 COOL channels) for any drawer in any partition
404 """
405 if ros==0:
406 if drawer<=4 or drawer==12 or drawer>=20:
407 drawer1=0
408 elif drawer<12:
409 drawer1=4
410 else:
411 drawer1=12
412 elif ros==1 or ros==2:
413 drawer1=4
414 elif ros==3:
415 OffsetEBA = [ 0, 0, 0, 0, 0, 0, 3, 2, #// Merged E+1: EBA07; Outer MBTS: EBA08
416 0, 0, 0, 0, 7, 6, 5, 7, #// D+4: EBA13, EBA16; Special D+4: EBA14; Special D+40: EBA15
417 7, 6, 6, 7, 0, 0, 0, 2, #// D+4: EBA17, EBA20; Special D+4: EBA18, EBA19; Outer MBTS: EBA24
418 3, 0, 0, 0, 0, 0, 0, 0, #// Merged E+1: EBA25
419 0, 0, 0, 0, 0, 0, 1, 1, #// Inner MBTS + special C+10: EBA39, EBA40
420 1, 1, 2, 3, 0, 0, 0, 0, #// Inner MBTS + special C+10: EBA41, EBA42; Outer MBTS: EBA43; Merged E+1: EBA44
421 0, 0, 0, 0, 3, 2, 1, 1, #// Merged E+1: EBA53; Outer MBTS: EBA54; Inner MBTS + special C+10: EBA55, EBA56
422 1, 1, 0, 0, 0, 0, 0, 0] #// Inner MBTS + special C+10: EBA57, EBA58
423 drawer1 = 12 + OffsetEBA[drawer]
424 elif ros==4:
425 OffsetEBC = [ 0, 0, 0, 0, 0, 0, 3, 2, #// Merged E-1: EBC07; Outer MBTS: EBC08
426 0, 0, 0, 0, 7, 6, 6, 7, # // D-4: EBC13, EBC16; Special D-4: EBC14, EBC15;
427 7, 5, 6, 7, 0, 0, 0, 2, #// D-4: EBC17, EBC20; Special D-40 EBC18; Special D-4: EBC19; Outer MBTS: EBC24
428 3, 0, 0, 3, 4, 0, 3, 4, #// Merged E-1: EBC25, EBC28, EBC31; E-4': EBC29, EBC32
429 0, 4, 3, 0, 4, 3, 1, 1, #// E-4': EBC34, EBC37; Merged E-1: EBC35, EBC38; Inner MBTS + special C-10: EBC39, EBC40
430 1, 1, 2, 3, 0, 0, 0, 0, #// Inner MBTS + special C-10: EBC41, EBC42; Outer MBTS: EBC43; Merged E-1: EBC44
431 0, 0, 0, 0, 3, 2, 1, 1, #// Merged E-1: EBC53; Outer MBTS: EBC54; Inner MBTS + special C-10: EBC55, EBC56
432 1, 1, 0, 0, 0, 0, 0, 0] #// Inner MBTS + special C-10: EBC57, EBC58
433 drawer1 = 12 + OffsetEBC[drawer]
434 else:
435 drawer1=0
436
437 return (0,drawer1)
438
439 #____________________________________________________________________
440 def dumpIovs(self, iovList, rosmin, rosmax, drawermin, drawermax, option=1, comment=False, usenames=True):
441 """
442 Dumps statistics - how many non-empty modules exists in different IOVs
443 """
444
445 if len(iovList)>0:
446 alliovs={}
447 allmods={}
448 zeroiovs={}
449 nmod=0
450 rosrange=list(range(rosmin,rosmax))
451 if comment:
452 rosrange+=[9999]
453 for since in iovList:
454 iov="(%s,%s)" % since
455 allmod=""
456 missmod=""
457 zeromod=""
458 zero=0
459 miss=0
460 for ros in rosrange:
461 if ros<0:
462 (dmin,dmax) = (drawermin,drawermax)
463 elif ros>4:
465 else:
466 (dmin,dmax) = (drawermin,min(drawermax,TileCalibUtils.getMaxDrawer(ros)))
467 for drawer in range(dmin,dmax):
468 flt = self.getDrawer(ros, drawer, since, False, False)
469 if ros<0 or ros>4:
471 mod = "Comment"
472 else:
473 mod = "CH_"+str(getDrawerIdx(ros,drawer))
474 elif usenames:
475 mod = TileCalibUtils.getDrawerString(ros,drawer)
476 else:
477 mod = str(getDrawerIdx(ros,drawer))
478 if mod not in allmods:
479 allmods[mod] = ""
480 nmod += 1
481 if flt is not None:
482 if flt==0:
483 zero += 1
484 zeromod += " " + mod
485 allmod += " " + mod + "_zero"
486 allmods[mod] += " " + iov + "_zero"
487 else:
488 allmod += " " + mod
489 allmods[mod] += " " + iov
490 else:
491 miss+=1
492 missmod += " " + mod
493 word = 'module' if usenames else 'COOL channel'
494 if miss==0 and nmod>1:
495 alliovs[iov] = " All %s" % plural(nmod,word)
496 elif miss>0 and miss<10:
497 alliovs[iov] = " %s present, %s missing:%s" % (plural(nmod-miss,word),plural(miss,word),missmod)
498 else:
499 alliovs[iov] = "%s ; %s present, %s missing" % (allmod,plural(nmod-miss,word),plural(miss,word))
500 zeroiovs[iov] = (zero,zeromod)
501
502 if (option&1)==1:
503 print("")
504 for key,value in allmods.items():
505 if value=="":
506 value=" None"
507 print("%s\t%s" % (key,value))
508 if (option&2)==2:
509 print("")
510 for key,value in alliovs.items():
511 if value=="":
512 value=" None"
513 if zeroiovs[key] and zeroiovs[key][0]>0:
514 if "_zero" not in value:
515 print("%s\t%s ; zero-sized blobs for %d modules:%s" % (key,value,zeroiovs[key][0],zeroiovs[key][1]))
516 else:
517 print("%s\t%s ; zero-sized blobs for %d modules" % (key,value,zeroiovs[key][0]))
518 else:
519 print("%s\t%s" % (key,value))
520 else:
521 print("\nNo IOVs found")
522
523
524class TileBlobWriterCrest(TileCalibLogger):
525 """
526 TileBlobWriterCrest is a helper class, managing the details of
527 CREST interactions for the user of TileCalibBlobs.
528 """
529
530 #____________________________________________________________________
531 def __init__(self, db, folderPath, calibDrawerType, payload=None):
532 """
533 Input:
534 - db : db should be a database connection
535 - folderPath: full folder path to create or update
536 """
537
538 #=== initialize base class
539 TileCalibLogger.__init__(self, "TileBlobWriter")
540
541 #=== store db
542 self.__db = db
543 self.__folderPath = folderPath
544 self.__payload = payload
545 if payload is not None:
546 return
547
548 #=== create default vectors based on calibDrawerType
549 self.__calibDrawerType = calibDrawerType
550 if calibDrawerType in ['TileCalibDrawerFlt', 'Flt']:
551 self.__TileCalibDrawer = TileCalibDrawerFlt
552 self.__defVec = cppyy.gbl.std.vector('std::vector<float>')()
553 elif calibDrawerType in ['TileCalibDrawerBch', 'Bch']:
554 self.__TileCalibDrawer = TileCalibDrawerBch
555 self.__defVec = cppyy.gbl.std.vector('std::vector<unsigned int>')()
556 elif calibDrawerType in ['TileCalibDrawerInt', 'Int']:
557 self.__TileCalibDrawer = TileCalibDrawerInt
558 self.__defVec = cppyy.gbl.std.vector('std::vector<unsigned int>')()
559 elif calibDrawerType in ['CaloCondBlobFlt', 'CaloFlt']:
560 self.__TileCalibDrawer = cppyy.gbl.CaloCondBlobFlt
561 self.__defVec = cppyy.gbl.std.vector('std::vector<float>')()
562 else:
563 raise Exception("Unknown calibDrawerType: %s" % calibDrawerType)
564
565 # Always all drawers should be written
566 self.__drawerBlob = {drawerIdx:Blob() for drawerIdx in range(0, TileCalibUtils.max_draweridx())}
567 self.__drawer = {}
568 #____________________________________________________________________
569 def register(self, since=(MINRUN,MINLBK), tag="", chan=-1, payload=None):
570 """
571 Registers the folder in the database.
572 - since: lower limit of IOV
573 - tag : The tag to write to
574 - chan : COOL channel to write, if negative - all COOL channels are written
575 Comment channel is always written
576
577 The interpretation of the 'since' inputs depends on their type:
578 - tuple(int,int) : run and lbk number
579 """
580
581 if self.__payload is None and payload is None:
582 jdata = {}
583 for drawerIdx,blob in self.__drawerBlob.items():
584 if chan<0 or drawerIdx==chan or drawerIdx==1000:
585 if blob is None or blob==0:
586 b64string = ''
587 else:
588 blob.seek(0)
589 b64string = str(base64.b64encode(blob.read()), 'ascii')
590 jdata[drawerIdx] = [b64string]
591 else:
592 if payload is not None:
593 self.__payload = payload
594 jdata = self.__payload
595
596 (sinceRun, sinceLumi) = since
597
598 if not self.__db or (self.__db and self.__db.endswith('.json')):
599 # Writting into the json file
600 fullTag = tag
601 if self.__folderPath and not (tag.upper().startswith('TILE') or tag.upper().startswith('CALO')):
602 fullTag = TileCalibUtils.getFullTag(self.__folderPath, tag)
603 fileName = f"{fullTag}.{sinceRun}.{sinceLumi}.json"
604 if self.__db:
605 fileName = f'{self.__db[:-5]}.{fileName}'
606
607 with open(fileName, 'w') as the_file:
608 json.dump(jdata, the_file, separators=(',', ':'), sort_keys=True)
609
610 #=== print info
611 self.log().info( 'Writting tag "%s"', fullTag)
612 self.log().info( '... since : [%s,%s]' , sinceRun, sinceLumi)
613 if self.__payload is None:
614 self.log().info( '... with comment field: "%s"', self.getComment())
615 self.log().info( '... into file : %s' , fileName)
616
617 #____________________________________________________________________
618 def setComment(self, author, comment=None):
619 """
620 Sets a general comment in the comment channel.
621 """
623 commentBlob = self.__drawerBlob.get(drawerIdx, None)
624 if commentBlob:
625 commentBlob.resize(0)
626 else:
627 commentBlob = Blob()
628 self.__drawerBlob[drawerIdx] = commentBlob
629
630 if isinstance(author, tuple) and len(author) == 3:
631 tm = time.mktime(datetime.datetime.strptime(author[2], "%a %b %d %H:%M:%S %Y").timetuple())
632 self.__drawer[drawerIdx] = TileCalibDrawerCmt.getInstance(commentBlob, author[0], author[1], int(tm))
633 else:
634 self.__drawer[drawerIdx] = TileCalibDrawerCmt.getInstance(commentBlob, author, comment)
635
636 #____________________________________________________________________
637 def getComment(self, split=False):
638 """
639 Returns the general comment (default if none is set)
640 """
642 comment = self.__drawer.get(drawerIdx, None)
643 if comment:
644 if split:
645 return (comment.getAuthor(), self.__comment.getComment(), self.__comment.getDate())
646 else:
647 return comment.getFullComment()
648 else:
649 return "<no comment found>"
650
651 #____________________________________________________________________
652 def getDrawer(self, ros, drawer, calibDrawerTemplate=None):
653 """
654 Returns a TileCalibDrawer object of requested type
655 for the given ROS and drawer.
656 """
657
658 try:
659 drawerIdx = getDrawerIdx(ros, drawer)
660 calibDrawer = self.__drawer.get(drawerIdx, None)
661
662 if not calibDrawer:
663 if self.__calibDrawerType in ['CaloCondBlobFlt', 'CaloFlt']:
664 calibDrawer = self.__TileCalibDrawer.getInstance(self.__drawerBlob[drawerIdx])
665 else:
666 calibDrawer = self.__TileCalibDrawer.getInstance(self.__drawerBlob[drawerIdx], self.__defVec,0,0)
667 self.__drawer[drawerIdx] = calibDrawer
668
669 #=== clone if requested
670 if calibDrawerTemplate:
671 calibDrawer.clone(calibDrawerTemplate)
672
673 return calibDrawer
674
675 except Exception as e:
676 self.log().critical( e )
677 return None
678
679 #____________________________________________________________________
680 def zeroBlob(self, ros, drawer):
681 """
682 Resets blob size to zero
683 """
684 try:
685 drawerIdx = getDrawerIdx(ros, drawer)
686 blob = self.__drawerBlob[drawerIdx]
687 blob.resize(0)
688 except Exception as e:
689 self.log().critical( e )
690 return None
691
692
693#____________________________________________________________________
694def getDrawerIdx(ros, drawer):
695 """
696 Calculates TileCalibDrawer index
697 from ros number and drawer number
698 """
699
700 if ros<0 or ros>4:
701 drawerIdx = drawer
702 else:
703 drawerIdx = TileCalibUtils.getDrawerIdx(ros, drawer)
704
705 return drawerIdx
706
707#____________________________________________________________________
708def plural(n, txt):
709 """
710 merges integer number and text
711 and adds 's' at the end of text
712 if n is not equal 1
713 """
714
715 text = f'{n} {txt}'
716 if n!=1:
717 text += 's'
718 return text
const bool debug
void print(char *figname, TCanvas *c1)
#define min(a, b)
Definition cfImp.cxx:40
static const TileCalibDrawerBch * getInstance(const coral::Blob &blob)
Returns a pointer to a const TileCalibDrawerBch.
static const TileCalibDrawerCmt * getInstance(const coral::Blob &blob)
Returns a pointer to a const TileCalibDrawerCmt.
static const TileCalibDrawerFlt * getInstance(const coral::Blob &blob)
Returns a pointer to a const TileCalibDrawerFlt.
static const TileCalibDrawerInt * getInstance(const coral::Blob &blob)
Returns a pointer to a const TileCalibDrawerBch.
static TileCalibDrawerOfc * getInstance(coral::Blob &blob, uint16_t objVersion, uint32_t nSamples, int32_t nPhases, uint16_t nChans, uint16_t nGains, std::string_view author="", std::string_view comment="", uint64_t timeStamp=0)
Returns a pointer to a non-const TileCalibDrawerOfc.
static std::string getClassName(TileCalibType::TYPE type)
Returns the class name.
static std::string getDrawerString(unsigned int ros, unsigned int drawer)
Return the drawer name, e.g.
static unsigned int max_draweridx()
Python compatibility function.
static unsigned int getDrawerIdx(unsigned int ros, unsigned int drawer)
Returns a drawer hash.
static unsigned int getMaxDrawer(unsigned int ros)
Returns the maximal channel number for a given drawer.
static std::string getFullTag(const std::string &folder, const std::string &tag)
Returns the full tag string, composed of camelized folder name and tag part.
static unsigned int getCommentChannel()
Returns the COOL channel number for the comment channel.
getIovs(self, since=(MINRUN, MINLBK), until=(MAXRUN, MAXLBK))
getFolderTag(self, folder, prefix, globalTag, api=None)
getPayload(self, runlumi=None, dbg=False)
__init__(self, db, folder='', tag='', run=None, lumi=0, modmin=0, modmax=275, copyBlob=False)
getDrawer(self, ros, mod, runlumi=None, dbg=False, useDefault=True)
dumpIovs(self, iovList, rosmin, rosmax, drawermin, drawermax, option=1, comment=False, usenames=True)
getComment(self, runlumi=None, split=False)
getBlob(self, ros, mod, runlumi=None, dbg=False)
getDrawer(self, ros, drawer, calibDrawerTemplate=None)
register(self, since=(MINRUN, MINLBK), tag="", chan=-1, payload=None)
setComment(self, author, comment=None)
__init__(self, db, folderPath, calibDrawerType, payload=None)
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:132
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179