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