ATLAS Offline Software
Loading...
Searching...
No Matches
TileCalibTools.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# TileCalibTools.py
5# Nils Gollub <nils.gollub@cern.ch>, 2007-11-23
6#
7# Carlos Solans <carlos.solans@cern.ch>, 2012-10-19
8# Andrey Kamenshchikov <akamensh@cern.ch>, 2013-10-23
9# Yuri Smirnov <iouri.smirnov@cern.ch>, 2014-12-24
10
11"""
12Python helper module for managing COOL DB connections and TileCalibBlobs.
13"""
14
15import cx_Oracle # noqa: F401
16from PyCool import cool
17import datetime, time, re, os, json
18from urllib.request import urlopen
19import cppyy
20
21from TileCalibBlobObjs.Classes import TileCalibUtils, TileCalibDrawerCmt, \
22 TileCalibDrawerInt, TileCalibDrawerOfc, TileCalibDrawerBch, \
23 TileCalibDrawerFlt, TileCalibType
24
25#=== get a logger
26from TileCalibBlobPython.TileCalibLogger import TileCalibLogger, getLogger
27log = getLogger("TileCalibTools")
28
29
30#======================================================================
31#===
32#=== Global helper functions
33#===
34#======================================================================
35
36#
37#______________________________________________________________________
38#=== useful constants
39MINRUN = 0
40MINLBK = 0
41MAXRUN = cool.Int32Max
42MAXLBK = cool.UInt32Max
43UNIX2COOL = 1000000000
44UNIXTMAX = cool.Int32Max
45# empty Tile channel for storing laser partition variation. DO NOT CHANGE.
46LASPARTCHAN = 43
47
48#
49#______________________________________________________________________
51 """
52 Return the run number of next run to be taken in the pit
53 Keep this function temporary for backward compatibility
54 """
55 return getNextRunNumber()
56
57#
58#______________________________________________________________________
60 """
61 Return the run number of next run to be taken in the pit
62 """
63
64 urls = ["http://atlas-run-info-api.web.cern.ch/api/runs?sort=runnumber:DESC&size=1",
65 "http://pcata007.cern.ch/cgi-bin/getLastRunNumber.py",
66 "http://pcata007.cern.ch/latestRun"]
67
68 run=0
69 for url in urls:
70 try:
71 for line in urlopen(url).readlines():
72 r=line.strip()
73 if r.isdigit():
74 run=int(r)
75 break
76 else:
77 jdata=json.loads(r)
78 run=int(jdata['resources'][0]['runnumber'])
79 break
80 if run>0:
81 break
82 except Exception:
83 continue
84
85 return max(run+1,222222)
86
87#
88#______________________________________________________________________
90 """
91 Return the minimal run number of runs in prompt calibration loop
92 """
93
94 promptCalibRuns = []
95
96 try:
97 aliascalibrun = os.getenv(
98 'TILE_ALIAS_CALIBRUN',
99 '/afs/cern.ch/user/a/atlcond/scratch0/nemo/prod/web/calibruns.txt'
100 )
101 if not aliascalibrun or not os.path.exists(aliascalibrun):
102 log.warning("Prompt calib run file not found: %s", aliascalibrun)
103 raise FileNotFoundError(aliascalibrun)
104 fin = open(aliascalibrun, 'r').read().split()
105 for line in fin:
106 try:
107 if line:
108 promptCalibRuns.append( int(line) )
109 except ValueError:
110 pass
111 except Exception:
112 promptCalibRuns=[]
113
114 if len(promptCalibRuns)==0:
115
116 urls = ["http://pcata007.cern.ch/cgi-bin/getBulkRunNumber.py",
117 "http://pcata007.cern.ch/latestRun"]
118
119 run=0
120 for url in urls:
121 try:
122 for line in urlopen(url).readlines():
123 r=line.strip()
124 if r.isdigit():
125 run=int(r)
126 break
127 if run>0:
128 promptCalibRuns=[run]
129 break
130 except Exception:
131 continue
132
133 if len(promptCalibRuns) >= 1:
134 promptCalibRuns.sort()
135 return promptCalibRuns[0]
136 else:
137 return getNextRunNumber()
138
139#
140#______________________________________________________________________
141def getAliasFromFile(aliastype='Current'):
142 """
143 Return name of top-level tag for 'Current' or 'CurrentES' or 'Next' or 'NextES' aliases
144 """
145
146 try:
147 aliasfolder = os.getenv(
148 'TILE_ALIAS_FOLDER',
149 '/afs/cern.ch/atlas/conditions/poolcond/buffer/BestKnowledge'
150 )
151 if not aliasfolder or not os.path.isdir(aliasfolder):
152 log.warning("Alias folder not found: %s", aliasfolder)
153 raise FileNotFoundError(aliasfolder)
154 falias = open('%s/%s' % (aliasfolder, aliastype))
155 alias = falias.readline()
156 falias.close()
157 return alias.replace('\n','').replace('*','')
158 except Exception:
159 aliasfolder = os.getcwd()+'/BestKnowledge'
160 print("Looking for %s in %s" % (aliastype,aliasfolder))
161 try:
162 falias = open('%s/%s' % (aliasfolder, aliastype))
163 alias = falias.readline()
164 falias.close()
165 return alias.replace('\n','').replace('*','')
166 except Exception:
167 return aliastype.upper()
168
169#
170#______________________________________________________________________
171def getTilePrefix(ofl=True,splitOnlInOflSchema=True):
172 """
173 Returns the common Tile prefix used for all COOL folders.
174 ofl = False ... single version folders
175 ofl = True ... multiversion folders
176 splitOnlInOflSchema = False ... offline only folders or
177 splitOnline folders in Online schema
178 splitOnlInOflSchema = True ... splitOnlineFolders in
179 offline schema
180 """
181 if ofl:
182 if splitOnlInOflSchema:
183 return "/TILE/OFL02/"
184 else:
185 return "/TILE/OFL01/"
186 else:
187 return "/TILE/ONL01/"
188
189#
190#______________________________________________________________________
192 """
193 Returns a list of all TILE folder prefixes
194 """
195 return ["/TILE/ONL01/","/TILE/OFL01/","/TILE/OFL02/"]
196
197#
198#______________________________________________________________________
199def getAthenaFolderDescr(type="run-lumi"):
200 """
201 Returns the run-lumi type folder description needed to read back the folder content
202 as a CondAttrListCollection in Athena.
203 """
204 desc ='<timeStamp>'+type+'</timeStamp>'
205 desc+='<addrHeader><address_header service_type="71" clid="1238547719" /></addrHeader>'
206 desc+='<typeName>CondAttrListCollection</typeName>'
207 return desc
208
209#
210#______________________________________________________________________
211def getAthenaFolderType(folderDescr):
212 type = re.compile(".*<timeStamp>(.*)</timeStamp>.*").search(folderDescr)
213 if not type:
214 raise Exception("No folder type info found in \'%s\'" % folderDescr)
215 return type.groups()[0]
216
217#
218#______________________________________________________________________
219def openDb(db, instance, mode="READONLY", schema="COOLOFL_TILE", sqlfn="tileSqlite.db"):
220 """
221 Opens a COOL db connection.
222 - db: The DB type. The following names are recognized:
223 * SQLITE: Opens file mentioned in sqlfn parameter
224 * ORACLE or FRONTIER: Opens ORACLE DB, forces READONLY
225 - instance: One of valid instances - CONDBR2 OFLP200 COMP200 CMCP200
226 - mode: Can be READONLY (default), RECREATE or UPDATE
227 - schema: One of valid schemas - COOLONL_CALO COOLOFL_CALO COOLONL_LAR COOLOFL_LAR COOLONL_TILE COOLOFL_TILE
228 - sqlfn: Name of sqlite file if db is SQLITE
229 """
230 #=== check for valid db names
231 if db is not None:
232 validDb = ["SQLITE", "ORACLE", "FRONTIER"]
233 if db not in validDb:
234 raise Exception( "DB not valid: %s, valid DBs are: %s" % (db,validDb) )
235 elif db == "ORACLE" or db == "FRONTIER":
236 mode = "READONLY"
237
238 #=== check for valid instance names
239 validInstance = ["COMP200", "CONDBR2", "CMCP200", "OFLP200"]
240 if instance not in validInstance:
241 raise Exception( "Instance not valid: %s, valid instance are: %s" % (instance,validInstance) )
242
243 #=== check for valid schema names
244 validSchema = ["COOLONL_TILE","COOLOFL_TILE"]
245 if schema not in validSchema:
246 raise Exception( "Schema not valid: %s, valid schemas are: %s" % (schema,validSchema) )
247
248 #=== construct connection string
249 connStr = ""
250 if db=='SQLITE':
251 if mode=="READONLY" and not os.path.exists(sqlfn):
252 raise Exception( "Sqlite file %s does not exist" % (sqlfn) )
253 if (mode=="RECREATE" or mode=="UPDATE") and not os.path.exists(os.path.dirname(sqlfn)):
254 dirn=os.path.dirname(sqlfn)
255 if dirn:
256 os.makedirs(dirn)
257 connStr="sqlite://X;schema=%s;dbname=%s" % (sqlfn,instance)
258 elif db=='FRONTIER':
259 connStr='frontier://ATLF/()/;schema=ATLAS_%s;dbname=%s' % (schema,instance)
260 elif db=='ORACLE':
261 connStr='oracle://%s;schema=ATLAS_%s;dbname=%s' % ('ATLAS_COOLPROD',schema,instance)
262 else:
263 connStr=schema+'/'+instance
264
265 return openDbConn(connStr, mode)
266
267#
268#______________________________________________________________________
269def openDbOracle(db, schema, folder):
270 """
271 Opens a COOL db connection.
272 - db: The DB type. The following names are recognized:
273 * ORACLE or FRONTIER: Opens ORACLE DB, forces READONLY
274 - schema: Full schema string for sqlite file, dbname will be extracted from this string
275 - folder: Fill folder path, schema string will be construced using folder name
276 """
277
278 connStr = 'COOL'
279 if '/OFL' in folder.upper():
280 connStr += 'OFL_'
281 else:
282 connStr += 'ONL_'
283 connStr += folder.strip('/').split('/')[0].upper()
284 dbn=schema.split('dbname=')
285 if len(dbn)==2:
286 dbname=dbn[1].split(';')[0]
287 else:
288 dbname='CONDBR2'
289 connStr += '/' + dbname
290
291 return openDbConn(connStr,db)
292
293#
294#______________________________________________________________________
295def openDbConn(connStr, mode="READONLY"):
296 """
297 Opens a COOL db connection.
298 - connStr: The DB connection string
299 - mode: Can be READONLY (default), RECREATE or UPDATE
300 or ORACLE or FRONTIER if connStr is only short name of the database
301 """
302
303 #=== split the name into schema and dbinstance
304 splitname=connStr.split('/')
305 if (len(splitname)!=2): # string connection ready to be used as it is
306 connStr_new=connStr
307 else: # construct connection string
308 schema=splitname[0]
309 instance=splitname[1]
310 if mode=="ORACLE":
311 connStr_new='oracle://%s;schema=ATLAS_%s;dbname=%s' % ('ATLAS_COOLPROD',schema,instance)
312 else:
313 connStr_new='frontier://ATLF/()/;schema=ATLAS_%s;dbname=%s' % (schema,instance)
314
315 #=== get dbSvc and print header info
316 dbSvc = cool.DatabaseSvcFactory.databaseService()
317 log.info( "---------------------------------------------------------------------------------" )
318 log.info( "-------------------------- TileCalibTools.openDbConn ----------------------------" )
319 log.info( "- using COOL version %s", dbSvc.serviceVersion() )
320 log.info( "- opening TileDb: %s",connStr_new )
321 log.info( "- mode: %s", mode )
322 log.info( "---------------------------------------------------------------------------------" )
323
324 #=== action depends on mode
325 if mode in ["READONLY","ORACLE","FRONTIER","",None]:
326 #=== open read only
327 try:
328 db=dbSvc.openDatabase(connStr_new,True)
329 except Exception as e:
330 log.debug( e )
331 log.critical("Could not connect to %s" % connStr_new )
332 return None
333 return db
334 elif mode=="RECREATE":
335 #=== recreating database
336 dbSvc.dropDatabase(connStr_new)
337 try:
338 db = dbSvc.createDatabase(connStr_new)
339 except Exception as e:
340 log.debug( e )
341 log.critical( "Could not create database, giving up..." )
342 return None
343 return db
344 elif mode=="UPDATE":
345 #=== update database
346 try:
347 db=dbSvc.openDatabase(connStr_new,False)
348 except Exception as e:
349 log.debug( e )
350 log.warning( "Could not connect to \'%s\', trying to create it....", connStr_new )
351 try:
352 db=dbSvc.createDatabase(connStr_new)
353 except Exception as e:
354 log.debug( e )
355 log.critical( "Could not create database, giving up..." )
356 return None
357 return db
358 else:
359 log.error("Mode \"%s\" not recognized", mode )
360 return None
361
362#
363#______________________________________________________________________
364def coolTimeFromRunLumi(runNum, lbkNum):
365 """
366 Returns COOL timeStamp build from run and lumi block numbers
367 """
368 return (int(runNum)<<32) + int(lbkNum)
369
370#
371#______________________________________________________________________
372def decodeTimeString(timeString):
373 """
374 Retruns UNIX time stamp given an input time string
375 """
376 return int(time.mktime(time.strptime(timeString,"%Y-%m-%d %H:%M:%S")))
377
378#
379#______________________________________________________________________
380def getCoolValidityKey(pointInTime, isSince=True):
381 """
382 The interpretation of pointInTime depends on their type:
383 - tuple(int,int) : run and lbk number
384 - integer : Values are interpreted as unix time stamps
385 - string : time stamp of format 'yyyy-mm-dd hh:mm:ss'
386 """
387
388 validityKey = None
389
390 #=== string: convert to unix time and treat as latter
391 if isinstance(pointInTime, str):
392 pointInTime = decodeTimeString(pointInTime)
393
394 #=== integer: unix time stamp
395 if isinstance(pointInTime, int):
396 if pointInTime >=0:
397 validityKey = pointInTime * UNIX2COOL
398 else:
399 if isSince:
400 validityKey = int(time.time()) * UNIX2COOL
401 else :
402 validityKey = cool.ValidityKeyMax
403 #=== run-lumi tuple
404 elif isinstance(pointInTime, tuple):
405 validityKey = coolTimeFromRunLumi(pointInTime[0],pointInTime[1])
406 #=== catch other types
407 else:
408 raise Exception("Unrecognized pointInTime type=%s" % type(pointInTime))
409 return cool.ValidityKey(validityKey)
410
411
412#
413#____________________________________________________________________
414def getFolderTag(db, folderPath, globalTag):
415
416 tag=""
417 gTAG = globalTag.upper()
418 findTAG = (gTAG == "ANY" or gTAG == "FIRST" or gTAG == "LAST")
419 if globalTag.startswith("/") or globalTag.startswith("TileO") or globalTag.upper().startswith("CALO"):
420 tag = globalTag
421 log.warning("Using tag as-is for folder %s", folderPath)
422 elif '/TILE/ONL01' in folderPath:
423 log.info("Using empty tag for single-version folder %s", folderPath)
424 elif globalTag.startswith(" "):
425 log.warning("Using empty tag for folder %s", folderPath)
426 elif globalTag=="":
427 tag = TileCalibUtils.getFullTag(folderPath, globalTag)
428 log.warning("Using tag with empty suffix for folder %s", folderPath)
429 else:
430 if folderPath.startswith('/CALO'):
431 dbname = 'COOLOFL_CALO' if folderPath.startswith('/CALO/Ofl') else 'COOLONL_CALO'
432 else:
433 dbname ='COOLOFL_TILE'
434 schema=dbname+'/CONDBR2'
435 if isinstance(db, str):
436 if 'OFLP200' in db or 'MC' in db:
437 schema=dbname+'/OFLP200'
438 if not globalTag.startswith("OFLCOND"):
439 if globalTag.startswith("RUN"):
440 globalTag='OFLCOND-'+globalTag
441 log.info("Using Simulation global tag \'%s\'", globalTag)
442 elif 'COMP200' in db or 'RUN1' in db:
443 schema=dbname+'/COMP200'
444 if globalTag!='UPD1' and globalTag!='UPD4' and ('UPD1' in globalTag or 'UPD4' in globalTag or 'COND' not in globalTag):
445 if not findTAG:
446 log.info("Using suffix \'%s\' as it is", globalTag)
447 else:
448 findTAG = False
449 globalTag='COMCOND-BLKPA-RUN1-06'
450 log.info("Using RUN1 global tag \'%s\'", globalTag)
451 if schema == dbname+'/CONDBR2':
452 if globalTag=='CURRENT' or globalTag=='UPD4' or globalTag=='':
453 globalTag=getAliasFromFile('Current')
454 log.info("Resolved CURRENT globalTag to \'%s\'", globalTag)
455 elif globalTag=='CURRENTES' or globalTag=='UPD1':
456 globalTag=getAliasFromFile('CurrentES')
457 log.info("Resolved CURRENT ES globalTag to \'%s\'", globalTag)
458 elif globalTag=='NEXT':
459 globalTag=getAliasFromFile('Next')
460 log.info("Resolved NEXT globalTag to \'%s\'", globalTag)
461 elif globalTag=='NEXTES':
462 globalTag=getAliasFromFile('NextES')
463 log.info("Resolved NEXT ES globalTag to \'%s\'", globalTag)
464 globalTag=globalTag.replace('*','')
465 if not findTAG and ('UPD1' in globalTag or 'UPD4' in globalTag or 'COND' not in globalTag):
466 tag = TileCalibUtils.getFullTag(folderPath, globalTag)
467 if tag.startswith('Calo') and 'NoiseCell' not in tag:
468 tag='CALO'+tag[4:]
469 tag=tag.replace('Pileupnoiselumi','PileUpNoiseLumi')
470 log.info("Resolved localTag \'%s\' to folderTag \'%s\'", globalTag,tag)
471 else:
472 if not isinstance(db, str):
473 try:
474 folder = db.getFolder(folderPath)
475 if findTAG:
476 tag = findTag(folder,gTAG)
477 else:
478 tag = folder.resolveTag(globalTag)
479 log.info("Resolved globalTag \'%s\' to folderTag \'%s\'", globalTag,tag)
480 schema=""
481 except Exception as e:
482 log.warning(e)
483 log.warning("Using %s to resolve globalTag",schema)
484 if len(schema):
485 dbr = openDbConn(schema,'READONLY')
486 folder = dbr.getFolder(folderPath)
487 if findTAG:
488 tag = findTag(folder,gTAG)
489 else:
490 tag = folder.resolveTag(globalTag)
491 dbr.closeDatabase()
492 log.info("Resolved globalTag \'%s\' to folderTag \'%s\'", globalTag,tag)
493
494 return tag
495
496#
497#____________________________________________________________________
498def findTag(folder,tag):
499 taglist=folder.listTags()
500 if len(taglist):
501 if tag=='FIRST':
502 return taglist[0]
503 else:
504 return taglist[-1]
505 else:
506 return 'tag-not-found'
507
508#
509#____________________________________________________________________
511 return (int(iov >> 32), int(iov & 0xFFFFFFFF))
512
513#
514#____________________________________________________________________
515def copyFolder(dbr, dbw, folder, tagr, tagw, chanNum, pointInTime1, pointInTime2):
516
517 log.info("Copy channel %i", chanNum)
518
519 folderR = dbr.getFolder(folder)
520 folderW = dbw.getFolder(folder)
521
522 chansel = cool.ChannelSelection(chanNum)
523
524 iov1 = getCoolValidityKey(pointInTime1,False)
525 iov2 = getCoolValidityKey(pointInTime2,False)
526
527 if tagr=='':
528 multiVersion = False
529 objs = folderR.browseObjects(iov1,iov2,chansel)
530 else:
531 multiVersion = True
532 objs = folderR.browseObjects(iov1,iov2,chansel,tagr)
533 while objs.goToNext():
534 obj=objs.currentRef()
535 sinceCool=obj.since()
536 if sinceCool < iov1:
537 sinceCool = iov1
538 untilCool=obj.until()
539 data=obj.payload()
540 sinceTup = runLumiFromCoolTime(sinceCool)
541 untilTup = runLumiFromCoolTime(untilCool)
542 log.debug("Copy entry: [%i,%i] - [%i,%i]: %s", sinceTup[0],sinceTup[1],untilTup[0],untilTup[1], data)
543 folderW.storeObject(sinceCool, untilCool, data, chanNum, tagw, multiVersion)
544
545#
546#____________________________________________________________________
547def moduleListToString(modules, checkAUX=True, checkMOD=True, checkComment=True, shortLength=15, exceptLength=15):
548
549 fulllist = "@".join(modules)
550 mlist = []
551
552 if checkAUX:
553 list1=re.findall("AUX..",fulllist)
554 if len(list1)==20:
555 mlist += ["ALL 20 AUX modules"]
556 elif list1:
557 mlist += [" ".join(list1)]
558 else:
559 mlist += ["NO AUX modules"]
560
561 if checkMOD:
562 list2=re.findall("[LE]B[AC]..",fulllist)
563 if len(list2)==256:
564 mlist += ["ALL 256 modules"]
565 elif 256-len(list2)<=exceptLength:
566 list3 = []
567 for p in ["LBA","LBC","EBA","EBC"]:
568 for n in range(1,65):
569 m = "%s%02d" % (p,n)
570 if m not in list2:
571 list3 += [m]
572 mlist += ["%d modules: all except %s" % (len(list2)," ".join(list3))]
573 elif list2:
574 if len(list2)<=shortLength:
575 mlist += [" ".join(list2)]
576 else:
577 for p in ["LBA","LBC","EBA","EBC"]:
578 list2=re.findall(p+"..",fulllist)
579 if len(list2)==64:
580 mlist += ["64 %s modules" % p]
581 elif 64-len(list2)<=exceptLength:
582 list3 = []
583 for n in range(1,65):
584 m = "%s%02d" % (p,n)
585 if m not in list2:
586 list3 += [m]
587 mlist += ["%d %s modules: all except %s" % (len(list2),p," ".join(list3))]
588 elif list2:
589 mlist += [" ".join(list2)]
590 else:
591 mlist += ["NO %s modules" % p]
592 else:
593 mlist += ["NO modules"]
594
595 if checkComment:
596 list4=re.findall("Comment[^@]*",fulllist)
597 if list4:
598 mlist += [" ".join(list4)]
599 else:
600 mlist += ["NO COMMENT"]
601
602 all = ", ".join(mlist)
603 return all
604
605
606
607#======================================================================
608#===
609#=== TileBlobWriter
610#===
611#======================================================================
612
613#
614#______________________________________________________________________
615class TileBlobWriter(TileCalibLogger):
616 """
617 TileCalibBlobWriterBase is a helper class, managing the details of
618 COOL interactions for the user of TileCalibBlobs.
619 """
620
621 #____________________________________________________________________
622 def __init__(self, db, folderPath, calibDrawerType,
623 isMultiVersionFolder=True, isRunLumiTimeStamp=True):
624 """
625 Input:
626 - db : db should be an open database connection
627 - folderPath: full folder path to create or update
628 """
629
630 #=== initialize base class
631 TileCalibLogger.__init__(self,"TileBlobWriter")
632
633 #=== store db
634 self.__db = db
635
636 #=== determine folder mode
637 folderMode = cool.FolderVersioning.MULTI_VERSION
638 if not isMultiVersionFolder:
639 folderMode = cool.FolderVersioning.SINGLE_VERSION
640
641 #=== determine folder description
642 folderDescr = getAthenaFolderDescr("run-lumi")
643 if not isRunLumiTimeStamp:
644 folderDescr = getAthenaFolderDescr("time")
645
646 #=== access folder in db
647 try:
648 #=== create folder if it does not exist
649 if self.__db.existsFolder(folderPath):
650 self.__folder = self.__db.getFolder(folderPath)
651 #=== check folder mode
652 modeInCool = self.__folder.versioningMode()
653 if modeInCool!=folderMode:
654 str = "Incompatible folder mode detected, COOL folder has type "
655 if modeInCool==cool.FolderVersioning.MULTI_VERSION:
656 str += "MULTI"
657 else:
658 str += "SINGLE"
659 raise Exception(str)
660 else:
661 #=== create folder if it does not exist
662 payloadSpec = cool.RecordSpecification()
663 payloadSpec.extend( 'TileCalibBlob', cool.StorageType.Blob64k )
664 folderSpec = cool.FolderSpecification(folderMode, payloadSpec)
665 self.__folder = db.createFolder(folderPath, folderSpec, folderDescr, True)
666 except Exception as e:
667 self.log().critical( e )
668 raise
669
670 #=== initialize channel dictionaries
671 self.__chanDictRecord = {} # <int, cool.Record >
672 self.__chanDictDrawer = {} # <int, TileCalibDrawer>
673
674 #=== create default vectors based on calibDrawerType
675 self.__calibDrawerType = calibDrawerType
676 if calibDrawerType=='Flt':
677 self.__defVec = cppyy.gbl.std.vector('std::vector<float>')()
678 elif calibDrawerType=='Bch' or calibDrawerType=='Int':
679 self.__defVec = cppyy.gbl.std.vector('std::vector<unsigned int>')()
680 else:
681 raise Exception("Unknown calibDrawerType: %s" % calibDrawerType)
682
683
684 #____________________________________________________________________
685 def register(self, since=(MINRUN,MINLBK), until=(MAXRUN,MAXLBK), tag="", option=0):
686 """
687 Registers the folder in the database.
688 - since: lower limit of IOV
689 - until: upper limit of IOV
690 - tag : The cool folder tag to write to
691
692 The interpretation of the 'since' and 'until' inputs depends on their type:
693 - tuple(int,int) : run and lbk number
694 - integer : Values are interpreted as unix time stamps
695 If since<0, current time is assumed
696 If until<0, infinity is assumed
697 - string : time stamp of format 'yyyy-mm-dd hh:mm:ss'
698 """
699
700 #=== check for inconsistent input
701 if type(since)!=type(until):
702 raise Exception("Inconsistent types: since=%s, until=%s" % (type(since),type(until)))
703
704 #=== write to user tag only if multiversion mode
705 userTagOnly = True
706 if self.__folder.versioningMode()==cool.FolderVersioning.SINGLE_VERSION:
707 userTagOnly = False
708 #=== no folder Tag allowed for singleversion
709 if tag!="":
710 self.log().warning( "Trying to store with tag \"%s\" to SINGLE_VERSION folder", tag )
711 self.log().warning( "... resetting tag to \"\"!" )
712 tag=""
713
714 #=== get IOV limits
715 sinceCool = getCoolValidityKey(since, True )
716 untilCool = getCoolValidityKey(until, False)
717 if untilCool <= sinceCool:
718 raise Exception("Until(%i) <= Since(%i)" % (untilCool,sinceCool))
719
720 #=== build IOV string
721 iovString = ""
722 if isinstance(since, tuple):
723 iovString = "[%i,%i] - [%i,%i]" % (since[0],since[1],until[0],until[1])
724 else:
725 sinceInfo = time.localtime( sinceCool//UNIX2COOL )
726 untilInfo = time.localtime(min(UNIXTMAX, (untilCool//UNIX2COOL)))
727 untilStr = "<infinity>"
728 if untilCool<cool.ValidityKeyMax:
729 untilStr = time.asctime(untilInfo)
730 if (untilCool//UNIX2COOL)>UNIXTMAX:
731 untilStr = " > "+untilStr
732 iovString = "[%s] - [%s]" % (time.asctime(sinceInfo), untilStr)
733
734 #=== build tag
735 folderTag=tag
736
737 #=== print info
738 comment=self.getComment()
739 onlyComment = (option<0)
740 noComment = (comment is None) or (comment == "None") or (comment.startswith("None") and comment.endswith("None")) or (option>0)
741 self.log().info( "Registering folder %s with tag \"%s\"", self.__folder.fullPath(),folderTag)
742 self.log().info( "... with IOV : %s" , iovString )
743 if noComment:
744 if (option<=0):
745 self.log().info( "... WITHOUT comment field" )
746 else:
747 self.log().info( "... with comment field: \"%s\"", self.getComment() )
748
749 #=== register all channels by increasing channel number
750 if onlyComment:
751 chanList = [1000]
752 else:
753 chanList = sorted(self.__chanDictRecord.keys())
754 cnt=0
755 for chanNum in chanList:
756 if chanNum==1000 and noComment:
757 continue
758 data = self.__chanDictRecord[chanNum]
759 strout = "cool channel=%4i" % chanNum
760 self.log().debug("Registering %s %s", strout, data)
761 channelId = cool.ChannelId(chanNum)
762 self.__folder.storeObject(sinceCool, untilCool, data, channelId, folderTag, userTagOnly)
763 cnt+=1
764 if noComment:
765 self.log().info( "... %d cool channels have been written in total", cnt )
766 elif onlyComment:
767 self.log().info( "... 1 cool channel with comment field has been written" )
768 else:
769 self.log().info( "... %d cool channels have been written in total (including comment field)", cnt )
770
771 #____________________________________________________________________
772 def setComment(self, author, comment=None):
773 """
774 Sets a general comment in the comment channel.
775 """
776 try:
778 data = self.__chanDictRecord.get(chanNum)
779 if not data:
780 spec = self.__folder.payloadSpecification()
781 data = cool.Record( spec )
782 self.__chanDictRecord[chanNum] = data
783 blob = data['TileCalibBlob']
784 if isinstance(author,tuple) and len(author)==3:
785 tm=time.mktime(datetime.datetime.strptime(author[2], "%a %b %d %H:%M:%S %Y").timetuple())
786 TileCalibDrawerCmt.getInstance(blob,author[0],author[1],int(tm))
787 else:
788 TileCalibDrawerCmt.getInstance(blob,author,comment)
789 except Exception as e:
790 self.log().critical( e )
791
792 #____________________________________________________________________
793 def getComment(self, split=False):
794 """
795 Returns the general comment (default if none is set)
796 """
797 try:
799 data = self.__chanDictRecord.get(chanNum)
800 if not data:
801 return "<No general comment!>"
802 blob = data['TileCalibBlob']
804 if split:
805 return (cmt.getAuthor(),cmt.getComment(),cmt.getDate())
806 else:
807 return cmt.getFullComment()
808 except Exception as e:
809 self.log().critical( e )
810
811 #____________________________________________________________________
812 def getDrawer(self, ros, drawer, calibDrawerTemplate=None):
813 """
814 Returns a TileCalibDrawer object of requested type
815 for the given ROS and drawer.
816 """
817 try:
818
819 #=== check for already initialized calibDrawers
820 chanNum = TileCalibUtils.getDrawerIdx(ros,drawer)
821 calibDrawer = self.__chanDictDrawer.get(chanNum,None)
822
823 #=== initialize new calibDrawer if needed
824 if not calibDrawer:
825
826 #=== create new blob
827 spec = self.__folder.payloadSpecification()
828 data = cool.Record( spec )
829 self.__chanDictRecord[chanNum] = data
830 blob = data['TileCalibBlob']
831
832 #=== Create calibDrawer based on requested calibDrawerType
833 if self.__calibDrawerType=='Flt':
834 calibDrawer = TileCalibDrawerFlt.getInstance(blob,self.__defVec,0,0)
835 elif self.__calibDrawerType=='Int':
836 calibDrawer = TileCalibDrawerInt.getInstance(blob,self.__defVec,0,0)
837 elif self.__calibDrawerType=='Bch':
838 calibDrawer = TileCalibDrawerBch.getInstance(blob,self.__defVec,0,0)
839 else:
840 raise Exception( "Invalid blob type requested: %s" % type )
841
842 #=== clone if requested
843 if calibDrawerTemplate:
844 calibDrawer.clone(calibDrawerTemplate)
845
846 #=== put updated calibDrawer in dictionary and return
847 self.__chanDictDrawer[chanNum] = calibDrawer
848 return calibDrawer
849
850 except Exception as e:
851 self.log().critical( e )
852 return None
853
854 #____________________________________________________________________
855 def zeroBlob(self, ros, drawer):
856 """
857 Resets blob size to zero
858 """
859 try:
860 chanNum = TileCalibUtils.getDrawerIdx(ros,drawer)
861 data = self.__chanDictRecord.get(chanNum)
862 if not data:
863 spec = self.__folder.payloadSpecification()
864 data = cool.Record( spec )
865 self.__chanDictRecord[chanNum] = data
866 blob = data['TileCalibBlob']
867 blob.resize(0)
868 except Exception as e:
869 self.log().critical( e )
870 return None
871
872
873
874#======================================================================
875#===
876#=== TileBlobReader
877#===
878#======================================================================
879
880#
881#______________________________________________________________________
882class TileBlobReader(TileCalibLogger):
883 """
884 TileCalibBlobReader is a helper class, managing the details of COOL interactions for
885 the user of TileCalibBlobs.
886 """
887
888 #____________________________________________________________________
889 def __init__(self, db, folder, tag=""):
890 """
891 Input:
892 - db : db should be an open database connection
893 - folder: full folder path
894 - tag : The folder tag, e.g. \"000-00\"
895 """
896 #=== initialize base class
897 TileCalibLogger.__init__(self,"TileBlobReader")
898
899 #=== try to open db
900 try:
901 self.__db = db # CoraCoolDatabase
902 self.__folder = self.__db.getFolder(folder) # CoraCoolFolder
903 except Exception as e:
904 self.log().critical( e )
905 raise
906
907 #=== determine if "run-lumi" or "time" folder
908 validFolderTypes = ("run-lumi","time")
909 folderDescr = self.__folder.description()
911 if self.__folderType not in validFolderTypes:
912 raise Exception("Invalid folder type found: \'%s\'" % self.__folderType)
913
914 #=== use camelized full folder path only if tag is given
915 self.__tag = tag
916
917 #=== initialize dictionary to keep reference to DB object of given ros/drawer
918 #=== and timestamp, so they do not go out of scope
919 self.__objDict = {}
920
921 #____________________________________________________________________
922 def getComment(self, pointInTime, split=False):
923 """
924 Returns the general comment (default if none is set)
925 """
926 validityKey = getCoolValidityKey(pointInTime)
927 try:
929 obj = self.__folder.findObject(validityKey, chanNum, self.__tag)
930 self.log().debug("getComment:Fetching from DB: %s", obj)
931 blob = obj.payload()[0]
933 if split:
934 return (cmt.getAuthor(),cmt.getComment(),cmt.getDate())
935 else:
936 return cmt.getFullComment()
937 except Exception:
938 return "<no comment found>"
939
940 #____________________________________________________________________
941 def getDefault(self, ros, drawer):
942 """
943 Returns a default drawer number (among first 20 COOL channels) for any drawer in any partition
944 """
945 if ros==0:
946 if drawer<=4 or drawer==12 or drawer>=20:
947 drawer1=0
948 elif drawer<12:
949 drawer1=4
950 else:
951 drawer1=12
952 elif ros==1 or ros==2:
953 drawer1=4
954 elif ros==3:
955 OffsetEBA = [ 0, 0, 0, 0, 0, 0, 3, 2, #// Merged E+1: EBA07; Outer MBTS: EBA08
956 0, 0, 0, 0, 7, 6, 5, 7, #// D+4: EBA13, EBA16; Special D+4: EBA14; Special D+40: EBA15
957 7, 6, 6, 7, 0, 0, 0, 2, #// D+4: EBA17, EBA20; Special D+4: EBA18, EBA19; Outer MBTS: EBA24
958 3, 0, 0, 0, 0, 0, 0, 0, #// Merged E+1: EBA25
959 0, 0, 0, 0, 0, 0, 1, 1, #// Inner MBTS + special C+10: EBA39, EBA40
960 1, 1, 2, 3, 0, 0, 0, 0, #// Inner MBTS + special C+10: EBA41, EBA42; Outer MBTS: EBA43; Merged E+1: EBA44
961 0, 0, 0, 0, 3, 2, 1, 1, #// Merged E+1: EBA53; Outer MBTS: EBA54; Inner MBTS + special C+10: EBA55, EBA56
962 1, 1, 0, 0, 0, 0, 0, 0] #// Inner MBTS + special C+10: EBA57, EBA58
963 drawer1 = 12 + OffsetEBA[drawer]
964 elif ros==4:
965 OffsetEBC = [ 0, 0, 0, 0, 0, 0, 3, 2, #// Merged E-1: EBC07; Outer MBTS: EBC08
966 0, 0, 0, 0, 7, 6, 6, 7, # // D-4: EBC13, EBC16; Special D-4: EBC14, EBC15;
967 7, 5, 6, 7, 0, 0, 0, 2, #// D-4: EBC17, EBC20; Special D-40 EBC18; Special D-4: EBC19; Outer MBTS: EBC24
968 3, 0, 0, 3, 4, 0, 3, 4, #// Merged E-1: EBC25, EBC28, EBC31; E-4': EBC29, EBC32
969 0, 4, 3, 0, 4, 3, 1, 1, #// E-4': EBC34, EBC37; Merged E-1: EBC35, EBC38; Inner MBTS + special C-10: EBC39, EBC40
970 1, 1, 2, 3, 0, 0, 0, 0, #// Inner MBTS + special C-10: EBC41, EBC42; Outer MBTS: EBC43; Merged E-1: EBC44
971 0, 0, 0, 0, 3, 2, 1, 1, #// Merged E-1: EBC53; Outer MBTS: EBC54; Inner MBTS + special C-10: EBC55, EBC56
972 1, 1, 0, 0, 0, 0, 0, 0] #// Inner MBTS + special C-10: EBC57, EBC58
973 drawer1 = 12 + OffsetEBC[drawer]
974 else:
975 drawer1=0
976
977 return (0,drawer1)
978
979 #____________________________________________________________________
980 def getDrawer(self, ros, drawer, pointInTime, printError=True, useDefault=True):
981 """
982 Returns a TileCalibDrawer object for the given ROS and drawer.
983 """
984
985 validityKey = getCoolValidityKey(pointInTime)
986 self.log().debug("Validity key is %s", validityKey)
987 try:
988 calibDrawer = None
989 #=== Have we retrieved data previously?
990 key = (ros,drawer,validityKey)
991 obj = self.__objDict.get(key)
992 #=== ... if not, get it from DB
993 if not obj:
994 chanNum = TileCalibUtils.getDrawerIdx(ros,drawer)
995 obj = self.__folder.findObject(validityKey, chanNum, self.__tag)
996 self.log().debug("Fetching from DB: %s", obj)
997 blob = obj.payload()[0]
998 self.log().debug("blob size: %d", blob.size())
999 #=== default policy
1000 if not useDefault and blob.size()==0:
1001 return 0
1002 while blob.size()==0:
1003 #=== no default at all?
1004 if ros==0 and drawer==0:
1005 raise Exception('No default available')
1006 #=== follow default policy
1007 ros,drawer = self.getDefault(ros,drawer)
1008 chanNum = TileCalibUtils.getDrawerIdx(ros,drawer)
1009 obj = self.__folder.findObject(validityKey, chanNum, self.__tag)
1010 blob = obj.payload()[0]
1011 #=== store object in dictionary
1012 self.__objDict[key] = obj
1013 #=== get blob
1014 blob = obj.payload()[0]
1015 self.log().debug("blob size: %d", blob.size())
1016
1017 #=== create calibDrawer depending on type
1018 calibDrawer = TileCalibDrawerCmt.getInstance(blob)
1019 typeName = TileCalibType.getClassName(calibDrawer.getObjType())
1020 del calibDrawer
1021 if typeName=='TileCalibDrawerFlt':
1022 calibDrawer = TileCalibDrawerFlt.getInstance(blob)
1023 self.log().debug( "typeName = Flt " )
1024 elif typeName=='TileCalibDrawerInt':
1025 calibDrawer = TileCalibDrawerInt.getInstance(blob)
1026 self.log().debug( "typeName = Int " )
1027 elif typeName=='TileCalibDrawerBch':
1028 calibDrawer = TileCalibDrawerBch.getInstance(blob)
1029 self.log().debug( "typeName = Bch " )
1030 elif typeName=='TileCalibDrawerOfc':
1031 calibDrawer = TileCalibDrawerOfc.getInstance(blob)
1032 self.log().debug( "typeName = Ofc " )
1033 else:
1034 raise Exception( "Invalid blob type requested: %s" % typeName )
1035 return calibDrawer
1036 except Exception as e:
1037 if printError:
1038 self.log().error("TileCalibTools.getDrawer(): Fetching of ros=%i, drawer=%i failed with exception %s", ros,drawer,e)
1039 return None
1040
1041 #____________________________________________________________________
1042 def getDefaultDrawer(self, ros, drawer, pointInTime, printError=True):
1043 """
1044 Returns a TileCalibDrawer object for the given ROS and drawer.
1045 """
1046
1047 validityKey = getCoolValidityKey(pointInTime)
1048 self.log().debug("Validity key is %s", validityKey)
1049 try:
1050 calibDrawer = None
1051 #=== Have we retrieved data previously?
1052 key = (ros,drawer,validityKey)
1053 obj = self.__objDict.get(key)
1054 #=== ... if not, get it from DB
1055 if not obj:
1056 chanNum = TileCalibUtils.getDrawerIdx(ros,drawer)
1057 obj = self.__folder.findObject(validityKey, chanNum, self.__tag)
1058 self.log().debug("Fetching from DB: %s", obj)
1059 blob = obj.payload()[0]
1060 self.log().debug("blob size: %d", blob.size())
1061 #=== default policy
1062 while blob.size()==0:
1063 #=== no default at all?
1064 if ros==0 and drawer==0:
1065 raise Exception('No default available')
1066 #=== follow default policy
1067 ros,drawer = self.getDefault(ros,drawer)
1068 chanNum = TileCalibUtils.getDrawerIdx(ros,drawer)
1069 obj = self.__folder.findObject(validityKey, chanNum, self.__tag)
1070 blob = obj.payload()[0]
1071 #=== store object in dictionary
1072 self.__objDict[key] = obj
1073 #=== get blob
1074 blob = obj.payload()[0]
1075 self.log().debug("blob size: %d", blob.size())
1076
1077 #=== create calibDrawer depending on type
1078 calibDrawer = TileCalibDrawerCmt.getInstance(blob)
1079 typeName = TileCalibType.getClassName(calibDrawer.getObjType())
1080 del calibDrawer
1081 if typeName=='TileCalibDrawerFlt':
1082 calibDrawer = TileCalibDrawerFlt.getInstance(blob)
1083 self.log().debug( "typeName = Flt " )
1084 elif typeName=='TileCalibDrawerInt':
1085 calibDrawer = TileCalibDrawerInt.getInstance(blob)
1086 self.log().debug( "typeName = Int " )
1087 elif typeName=='TileCalibDrawerBch':
1088 calibDrawer = TileCalibDrawerBch.getInstance(blob)
1089 self.log().debug( "typeName = Bch " )
1090 elif typeName=='TileCalibDrawerOfc':
1091 calibDrawer = TileCalibDrawerOfc.getInstance(blob)
1092 self.log().debug( "typeName = Ofc " )
1093 else:
1094 raise Exception( "Invalid blob type requested: %s" % typeName )
1095 return calibDrawer
1096 except Exception as e:
1097 if printError:
1098 self.log().error("TileCalibTools.getDefaultDrawer(): Fetching of ros=%i, drawer=%i failed with exception %s", ros,drawer,e)
1099 return None
1100
1101 #____________________________________________________________________
1102 def getDBobjsWithinRange(self, ros, drawer, point1inTime=(0,0), point2inTime=(2147483647,4294967295), printError=True):
1103 """
1104 Returns all DB objects for the given ROS and drawer, within given validity range -- default: [0-Infty)
1105 Check getBlobsWithinRange for an example on how to loop over objects and check validity ranges.
1106 """
1107
1108 validityKey1 = getCoolValidityKey(point1inTime,True)
1109 validityKey2 = getCoolValidityKey(point2inTime,False)
1110
1111 #print "Validity keys range is %s - %s" % (validityKey1, validityKey2)
1112 self.log().debug("Validity key range is %s - %s", validityKey1,validityKey2)
1113
1114 objs = None
1115 try:
1116 dbChanNum = drawer if ros<0 else TileCalibUtils.getDrawerIdx(ros,drawer)
1117 dbChanSel = cool.ChannelSelection(dbChanNum)
1118 #self.log().debug("Fetching blobs from DB: %s" % obj)
1119 objs = self.__folder.browseObjects(validityKey1,validityKey2,dbChanSel,self.__tag)
1120 except Exception as e:
1121 if printError:
1122 self.log().error("TileCalibTools.getDBobjsWithinRange(): Fetching of ros=%i, drawer=%i failed with exception %s", ros,drawer,e)
1123
1124 return objs
1125
1126 #____________________________________________________________________
1127 def getIOVsWithinRange(self, ros, drawer, point1inTime=(0,0), point2inTime=(2147483647,4294967295), printError=True):
1128 """
1129 Returns list of IOVS for the given ROS and drawer, within given validity range -- default: [0-Infty)
1130 """
1131 iovs=[]
1132 dbobjs = self.getDBobjsWithinRange(ros,drawer,point1inTime, point2inTime, printError)
1133 if (dbobjs is None):
1134 log.warning( "Warning: can not read IOVs for ros %d drawer %d from input DB file", ros,drawer )
1135 else:
1136 while dbobjs.goToNext():
1137 obj = dbobjs.currentRef()
1138 objsince = obj.since()
1139 sinceRun = objsince >> 32
1140 sinceLum = objsince & 0xFFFFFFFF
1141 since = (sinceRun, sinceLum)
1142 iovs.append(since)
1143 return iovs
1144
1145 #____________________________________________________________________
1146 def getBlobsWithinRange(self, ros, drawer, point1inTime=(0,0), point2inTime=(2147483647,4294967295)):
1147 """
1148 Returns all blob objects for the given ROS and drawer, within given validity range -- default: [0-Infty)
1149 Note: the blobs don't contain validity range info. Check method getDBobjsWithinRange()
1150 """
1151
1152 validityKey1 = getCoolValidityKey(point1inTime,True)
1153 validityKey2 = getCoolValidityKey(point2inTime,False)
1154
1155 print ("Validity keys range is %s - %s" % (validityKey1, validityKey2))
1156 self.log().debug("Validity key range is %s - %s", validityKey1,validityKey2)
1157
1158 objs = self.getDBobjsWithinRange(self, ros, drawer, point1inTime, point2inTime)
1159
1160 #-- Loop over objs to extract blobs
1161 blobs = []
1162 calibDrawer = None
1163 while objs.goToNext():
1164 obj=objs.currentRef()
1165 sinceCool=obj.since()
1166 if sinceCool < validityKey1:
1167 sinceCool = validityKey1
1168 untilCool=obj.until()
1169 blob = obj.payload()[0]
1170 print ("[%d,%d)-[%d,%d) - %s" % ((sinceCool>>32),(sinceCool&0xFFFFFFFF),(untilCool>>32),(untilCool&0xFFFFFFFF),blob))
1171 self.log().debug("blob size: %d", blob.size())
1172
1173 #=== default policy
1174 while blob.size()==0:
1175 #=== no default at all?
1176 if ros==0 and drawer==0:
1177 raise Exception('No default available')
1178 #=== follow default policy
1179 ros,drawer = self.getDefault(ros,drawer)
1180 chanNum = TileCalibUtils.getDrawerIdx(ros,drawer)
1181 obj = self.__folder.findObject(sinceCool, chanNum, self.__tag)
1182 blob = obj.payload()[0]
1183 self.log().debug("blob size: 0 --> default: %d", blob.size())
1184
1185 #=== store object in dictionary
1186 self.__objDict[sinceCool] = obj
1187
1188 #=== create calibDrawer depending on type
1189 calibDrawer = TileCalibDrawerCmt.getInstance(blob)
1190 typeName = TileCalibType.getClassName(calibDrawer.getObjType())
1191 del calibDrawer
1192 if typeName=='TileCalibDrawerFlt':
1193 calibDrawer = TileCalibDrawerFlt.getInstance(blob)
1194 self.log().debug( "typeName = Flt " )
1195 elif typeName=='TileCalibDrawerInt':
1196 calibDrawer = TileCalibDrawerInt.getInstance(blob)
1197 self.log().debug( "typeName = Int " )
1198 elif typeName=='TileCalibDrawerBch':
1199 calibDrawer = TileCalibDrawerBch.getInstance(blob)
1200 self.log().debug( "typeName = Bch " )
1201 elif typeName=='TileCalibDrawerOfc':
1202 calibDrawer = TileCalibDrawerOfc.getInstance(blob)
1203 self.log().debug( "typeName = Ofc " )
1204 else:
1205 raise Exception( "Invalid blob type requested: %s" % typeName )
1206
1207 blobs.append( calibDrawer )
1208
1209 return blobs
1210
1211 #____________________________________________________________________
1213 """
1214 Returns true if MultiVersion folder is connected
1215 """
1216 if self.__folder.versioningMode()==cool.FolderVersioning.MULTI_VERSION:
1217 return True
1218 else:
1219 return False
1220
1221
1222#======================================================================
1223#===
1224#=== TileASCIIParser
1225#===
1226#======================================================================
1227
1228#
1229#______________________________________________________________________
1230class TileASCIIParser(TileCalibLogger):
1231 """
1232 This is a class capable of parsing TileCal conditions data stored in
1233 ASCII files. Both the single and multi-line formats are supported.
1234 """
1235
1236 #____________________________________________________________________
1237 def __init__(self, fileName, calibId, isSingleLineFormat=True):
1238 """
1239 Input:
1240 - fileName : input file name
1241 - isSingleLineFormat: if False, multi line format is assumed
1242 """
1243
1244 TileCalibLogger.__init__(self,"TileASCIIParser")
1245 self.__dataDict = {}
1246 try:
1247 lines = open(fileName,"r").readlines()
1248 except Exception as e:
1249 self.log().error( "TileCalibASCIIParser::ERROR: Problem opening input file:" )
1250 self.log().error( e )
1251 return
1252
1253 for line in lines:
1254 fields = line.strip().split()
1255 #=== ignore empty and comment lines
1256 if not len(fields) :
1257 continue
1258 if fields[0].startswith("#"):
1259 continue
1260
1261 #=== read in fields
1262 type = fields[0]
1263 frag = fields[1]
1264 chan = fields[2]
1265 data = fields[3:]
1266 if not isSingleLineFormat:
1267 raise Exception("Multiline format not implemented yet")
1268
1269 #=== check for correct calibId
1270 if type!=calibId:
1271 raise Exception("%s is not calibId=%s" % (type,calibId))
1272
1273 #=== decode fragment
1274 if not (frag.startswith('0x') or frag.startswith('-0x') or frag.startswith('h_')):
1275 raise Exception("Misformated fragment %s" % frag)
1276 if frag.startswith('0x') or frag.startswith('-0x'):
1277 frg = int(frag,16)
1278 ros = frg>>8
1279 if frg<0:
1280 mod = (-frg)&255
1281 else:
1282 mod = frg&255
1283 chn = int(chan)
1284 elif frag.startswith('h_'):
1285 part_dict = {'LBA':1,'LBC':2,'EBA':3,'EBC':4}
1286 partname = str(frag[2:5])
1287 ros=part_dict[partname]
1288 mod = int(frag[5:])-1
1289 if (chan.startswith('ch')):
1290 chn = int(chan[2:])
1291 else:
1292 pmt = int (chan)
1293 chn=self.PMT2channel(ros,mod,pmt)
1294
1295 #=== fill dictionary
1296 dictKey = (ros,mod,chn)
1297 self.__dataDict[dictKey] = data
1298
1299 #____________________________________________________________________
1300 def getData(self, ros, drawer, channel):
1301 dictKey = (int(ros), int(drawer), int(channel))
1302 data = self.__dataDict.get(dictKey,[])
1303 return data
1304
1305 #____________________________________________________________________
1306 def getDict(self):
1307 import copy
1308 return copy.deepcopy(self.__dataDict)
1309
1310 #____________________________________________________________________
1311 def PMT2channel(self,ros,drawer,pmt):
1312 "Reorder the PMTs (SV: how to get that from region.py???)"
1313 "This takes ros [1-4], drawer [0-63], pmt [1-48]"
1314
1315 PMT2chan_Special={1:0,2:1,3:2,4:3,5:4,6:5,7:6,8:7,9:8,10:9,
1316 11:10,12:11,13:12,14:13,15:14,16:15,17:16,18:17, 19:18, 20:19,
1317 21:20,22:21,23:22,24:23,27:24,26:25,25:26,31:27,32:28,28:29,
1318 33:30,29:31,30:32,36:33,35:34,34:35,44:36,38:37,37:38,43:39,42:40,
1319 41:41,45:42,39:43,40:44,48:45,47:46,46:47}
1320
1321
1322 PMT2chan_LB={1:0,2:1,3:2,4:3,5:4,6:5,7:6,8:7,9:8,10:9,
1323 11:10,12:11,13:12,14:13,15:14,16:15,17:16,18:17,19:18,20:19,
1324 21:20,22:21,23:22,24:23,27:24,26:25,25:26,30:27,29:28,28:29,
1325 33:30,32:31,31:32,36:33,35:34,34:35,39:36,38:37,37:38,42:39,41:40,
1326 40:41,45:42,44:43,43:44,48:45,47:46,46:47}
1327
1328
1329 PMT2chan_EB={1:0,2:1,3:2,4:3,5:4,6:5,7:6,8:7,9:8,10:9,
1330 11:10,12:11,13:12,14:13,15:14,16:15,17:16,18:17,19:18,20:19,
1331 21:20,22:21,23:22,24:23,25:24,26:25,27:26,28:27,31:28,32:29,
1332 33:30,29:31,30:32,35:33,36:34,34:35,44:36,38:37,37:38,43:39,42:40,
1333 41:41,39:42,40:43,45:44,46:45,47:46,48:47}
1334
1335 if ros <= 2:
1336 chan = PMT2chan_LB[pmt]
1337 elif (ros == 3 and drawer == 14) or (ros == 4 and drawer == 17):
1338 chan = PMT2chan_Special[pmt]
1339 else:
1340 chan = PMT2chan_EB[pmt]
1341
1342 return chan
1343
1344#======================================================================
1345#===
1346#=== TileASCIIParser2
1347#===
1348#======================================================================
1349
1350#
1351#______________________________________________________________________
1352class TileASCIIParser2(TileCalibLogger):
1353 """
1354 This is a class capable of parsing TileCal conditions data stored in
1355 ASCII files. This version of parser can be used when mutiple IOVs are
1356 given in the file. First column is (run,lumi) pair in this case
1357 """
1358
1359 #____________________________________________________________________
1360 def __init__(self, fileName, calibId="", readGain=True):
1361 """
1362 Input:
1363 - fileName : input file name
1364 - calibId : like Ped, Las, ... or (r,l) or (run,lumi) but can be empty string as well
1365 - readGain : if False, no gain field in input file
1366 """
1367
1368 TileCalibLogger.__init__(self,"TileASCIIParser2")
1369 self.__dataDict = {}
1370 self.__manyIOVs = (calibId=="(run,lumi)" or calibId=="(r,l)" )
1371 self.__readGain = readGain
1372 iov=(0,0)
1373 gain=-1
1374
1375 try:
1376 lines = open(fileName,"r").readlines()
1377 except Exception as e:
1378 self.log().error( "TileCalibASCIIParser2::ERROR: Problem opening input file:" )
1379 self.log().error( e )
1380 return
1381
1382 self.log().info("Parsing file %s",fileName)
1383 if len(calibId)>0:
1384 self.log().info("Looking for prefix %s",calibId)
1385
1386 for line in lines:
1387 fields = line.strip().split()
1388 #=== ignore empty and comment lines
1389 if not len(fields) :
1390 continue
1391 if fields[0].startswith("#"):
1392 continue
1393
1394 #=== read in fields
1395 if len(calibId)>0:
1396 pref = fields[0]
1397 frag = fields[1]
1398 chan = fields[2]
1399 if str(chan)[0:2].lower() == "pm":
1400 chan = self.PMT2channel(frag,fields.pop(2))
1401 if readGain:
1402 gain = fields[3]
1403 data = fields[4:]
1404 else:
1405 data = fields[3:]
1406
1407 #=== check for correct calibId
1408 if self.__manyIOVs:
1409 iov=tuple(int(i) for i in pref[1:-1].split(","))
1410 if len(iov)!=2 or pref[0]!="(" or pref[-1]!=")":
1411 raise Exception("%s is not %s IOV" % (pref,calibId))
1412 elif pref!=calibId:
1413 raise Exception("%s is not calibId=%s" % (pref,calibId))
1414 else:
1415 frag = fields[0]
1416 chan = fields[1]
1417 if str(chan)[0:2].lower() == "pm":
1418 chan = self.PMT2channel(frag,fields.pop(2))
1419 if readGain:
1420 gain = fields[2]
1421 data = fields[3:]
1422 else:
1423 data = fields[2:]
1424
1425 #=== decode fragment
1426 if frag.startswith('0x') or frag.startswith('-0x'):
1427 frg = int(frag,16)
1428 ros = frg>>8
1429 if frg<0:
1430 mod = (-frg)&255
1431 else:
1432 mod = frg&255
1433 elif (frag.startswith("AUX") or
1434 frag.startswith("LBA") or
1435 frag.startswith("LBC") or
1436 frag.startswith("EBA") or
1437 frag.startswith("EBC") or
1438 frag.startswith("ALL") or
1439 frag.startswith("XXX") ):
1440 part_dict = {'AUX':0,'LBA':1,'LBC':2,'EBA':3,'EBC':4,'ALL':5,'XXX':-1}
1441 partname = str(frag[0:3])
1442 ros=part_dict[partname]
1443 mod = int(frag[3:])-1
1444 else:
1445 raise Exception("Unknown fragment %s" % frag)
1446
1447 chn = int(chan)
1448 adc = int(gain)
1449
1450 #=== fill dictionary
1451 if ros<0:
1452 rosmin=0
1453 rosmax=5
1454 elif ros>=5:
1455 rosmin=1
1456 rosmax=5
1457 else:
1458 rosmin=ros
1459 rosmax=ros+1
1460
1461 if mod<0 or mod>=64:
1462 modmin=0
1463 modmax=64
1464 else:
1465 modmin=mod
1466 modmax=mod+1
1467
1468 allchannels=True
1469 if chn<-2:
1470 chnmin=0
1471 chnmax=-chn
1472 elif chn<0:
1473 chnmin=0
1474 chnmax=48
1475 allchannels=(chn==-1) # if chn=-2 only connected channels will be updated
1476 else:
1477 chnmin=chn
1478 chnmax=chn+1
1479
1480 if adc<-1:
1481 adcmin=0
1482 adcmax=-adc
1483 elif adc<0:
1484 adcmin=0
1485 adcmax=2
1486 else:
1487 adcmin=adc
1488 adcmax=adc+1
1489
1490 for ros in range(rosmin,rosmax):
1491 for mod in range(modmin,modmax):
1492 for chn in range(chnmin,chnmax):
1493 if allchannels or self.channel2PMT(ros,mod,chn)>0:
1494 for adc in range (adcmin,adcmax):
1495 dictKey = (ros,mod,chn,adc)
1496 if self.__manyIOVs:
1497 if dictKey in self.__dataDict:
1498 self.__dataDict[dictKey] += [(iov,data)]
1499 else:
1500 self.__dataDict[dictKey] = [(iov,data)]
1501 else:
1502 self.__dataDict[dictKey] = data
1503
1504 #____________________________________________________________________
1505 def getData(self, ros, drawer, channel, adc, iov=(MAXRUN,MAXLBK)):
1506 dictKey = (int(ros), int(drawer), int(channel), int(adc))
1507 data = self.__dataDict.get(dictKey,[])
1508 if self.__manyIOVs and len(data)>0:
1509 before= [i for i in sorted(data) if i[0] <= iov ]
1510 if len(before)>0:
1511 data = before[-1][1]
1512 else:
1513 data = []
1514 return data
1515
1516 #____________________________________________________________________
1517 def getDict(self):
1518 import copy
1519 return copy.deepcopy(self.__dataDict)
1520
1521 #____________________________________________________________________
1522 def channel2PMT(self,ros,drawer,chan):
1523 "Convert channel numbet to PMT number, negative for disconnected channels"
1524 "This takes ros [1-4], drawer [0-63], chan [0-47]"
1525
1526 chan2PMT_LB=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
1527 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
1528 27, 26, 25, 30, 29, 28,-33,-32, 31, 36, 35, 34,
1529 39, 38, 37, 42, 41, 40, 45,-44, 43, 48, 47, 46 ]
1530
1531 chan2PMT_EB=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
1532 13, 14, 15, 16, 17, 18,-19,-20, 21, 22, 23, 24,
1533 -27,-26,-25,-31,-32,-28, 33, 29, 30,-36,-35, 34,
1534 44, 38, 37, 43, 42, 41,-45,-39,-40,-48,-47,-46 ]
1535
1536 chan2PMT_Sp=[ -1, -2, -3, -4, 5, 6, 7, 8, 9, 10, 11, 12, # first 4 do not exist
1537 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, # PMT 19 and 20 exist
1538 -27,-26,-25,-31,-32,-28, 33, 29, 30,-36,-35, 34,
1539 44, 38, 37, 43, 42, 41,-45,-39,-40,-48,-47,-46 ]
1540
1541 if ros <= 2:
1542 pmt = chan2PMT_LB[chan]
1543 elif (ros == 3 and drawer == 14) or (ros == 4 and drawer == 17):
1544 pmt = chan2PMT_Sp[chan]
1545 else:
1546 pmt = chan2PMT_EB[chan]
1547
1548 return pmt
1549
1550 #____________________________________________________________________
1551 def PMT2channel(self,partition,pmt):
1552 "Convert PMT number to channel numbet"
1553 "This takes partition (LBA,LBC,EBA,EBC) and pmt [1-48]"
1554
1555 chan2PMT_LB=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
1556 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
1557 27, 26, 25, 30, 29, 28, 33, 32, 31, 36, 35, 34,
1558 39, 38, 37, 42, 41, 40, 45, 44, 43, 48, 47, 46 ]
1559
1560 chan2PMT_EB=[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
1561 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
1562 27, 26, 25, 31, 32, 28, 33, 29, 30, 36, 35, 34,
1563 44, 38, 37, 43, 42, 41, 45, 39, 40, 48, 47, 46 ]
1564
1565 chan = -1
1566 pm=abs(int(pmt))
1567
1568 if pm>0 and pm<=48:
1569 if str(partition)[0].upper() == "E":
1570 chan = chan2PMT_EB.index(pm)
1571 else:
1572 chan = chan2PMT_LB.index(pm)
1573
1574 return chan
1575
1576#======================================================================
1577#===
1578#=== TileASCIIParser3
1579#===
1580#======================================================================
1581
1582#______________________________________________________________________
1583class TileASCIIParser3(TileCalibLogger):
1584 """
1585 This is a class capable of parsing TileCal conditions data stored in
1586 ASCII files.
1587 """
1588
1589 #____________________________________________________________________
1590 def __init__(self, fileName, calibId):
1591 """
1592 Input:
1593 - fileName : input file name
1594 - calibId : like Trip, ...
1595 """
1596
1597 TileCalibLogger.__init__(self,"TileASCIIParser3")
1598 self.__dataDict = {}
1599 try:
1600 lines = open(fileName,"r").readlines()
1601 except Exception as e:
1602 self.log().error( "TileCalibASCIIParser3::ERROR: Problem opening input file:" )
1603 self.log().error( e )
1604 return
1605
1606 for line in lines:
1607 fields = line.strip().split()
1608 #=== ignore empty and comment lines
1609 if not len(fields) :
1610 continue
1611 if fields[0].startswith("#"):
1612 continue
1613
1614 #=== read in fields
1615 type = fields[0]
1616 frag = fields[1]
1617 data = fields[2:]
1618
1619 #=== check for correct calibId
1620 if type != calibId:
1621 raise Exception("%s is not calibId=%s" % (type, calibId))
1622
1623 #=== decode fragment
1624 if not (frag.startswith('0x') or frag.startswith('-0x')):
1625 raise Exception("Misformated fragment %s" % frag)
1626
1627 frg = int(frag,16)
1628 ros = frg>>8
1629 if frg<0:
1630 mod = (-frg)&255
1631 else:
1632 mod = frg&255
1633
1634 #=== fill dictionary
1635 dictKey = (ros, mod)
1636 self.__dataDict[dictKey] = data
1637
1638 #____________________________________________________________________
1639 def getData(self, ros, drawer):
1640 dictKey = (int(ros), int(drawer))
1641 data = self.__dataDict.get(dictKey,[])
1642 return data
1643
1644 #____________________________________________________________________
1645 def getDict(self):
1646 import copy
1647 return copy.deepcopy(self.__dataDict)
int upper(int c)
const bool debug
void print(char *figname, TCanvas *c1)
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
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 unsigned int getDrawerIdx(unsigned int ros, unsigned int drawer)
Returns a drawer hash.
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.
__init__(self, fileName, calibId="", readGain=True)
getData(self, ros, drawer, channel, adc, iov=(MAXRUN, MAXLBK))
getData(self, ros, drawer, channel)
__init__(self, fileName, calibId, isSingleLineFormat=True)
getComment(self, pointInTime, split=False)
getDefaultDrawer(self, ros, drawer, pointInTime, printError=True)
getBlobsWithinRange(self, ros, drawer, point1inTime=(0, 0), point2inTime=(2147483647, 4294967295))
getDBobjsWithinRange(self, ros, drawer, point1inTime=(0, 0), point2inTime=(2147483647, 4294967295), printError=True)
__init__(self, db, folder, tag="")
getIOVsWithinRange(self, ros, drawer, point1inTime=(0, 0), point2inTime=(2147483647, 4294967295), printError=True)
getDrawer(self, ros, drawer, pointInTime, printError=True, useDefault=True)
setComment(self, author, comment=None)
register(self, since=(MINRUN, MINLBK), until=(MAXRUN, MAXLBK), tag="", option=0)
getDrawer(self, ros, drawer, calibDrawerTemplate=None)
__init__(self, db, folderPath, calibDrawerType, isMultiVersionFolder=True, isRunLumiTimeStamp=True)
std::string description
glabal timer - how long have I taken so far?
Definition hcg.cxx:93
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:312
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:132
void search(TDirectory *td, const std::string &s, std::string cwd, node *n)
recursive directory search for TH1 and TH2 and TProfiles
Definition hcg.cxx:743
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
coolTimeFromRunLumi(runNum, lbkNum)
getAliasFromFile(aliastype='Current')
moduleListToString(modules, checkAUX=True, checkMOD=True, checkComment=True, shortLength=15, exceptLength=15)
openDb(db, instance, mode="READONLY", schema="COOLOFL_TILE", sqlfn="tileSqlite.db")
openDbConn(connStr, mode="READONLY")
getFolderTag(db, folderPath, globalTag)
openDbOracle(db, schema, folder)
getTilePrefix(ofl=True, splitOnlInOflSchema=True)
getAthenaFolderType(folderDescr)
copyFolder(dbr, dbw, folder, tagr, tagw, chanNum, pointInTime1, pointInTime2)
getCoolValidityKey(pointInTime, isSince=True)
getAthenaFolderDescr(type="run-lumi")
IovVectorMap_t read(const Folder &theFolder, const SelectionCriterion &choice, const unsigned int limit=10)