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