10Python helper module for managing CREST DB connections and TileCalibBlobs.
13import os, re, cppyy, base64, json, time, datetime
15from PyCool
import cool
16Blob = cppyy.gbl.coral.Blob
18from pycrest.api.crest_api
import CrestApi
20from TileCalibBlobObjs.Classes
import TileCalibUtils, TileCalibDrawerCmt, \
21 TileCalibDrawerInt, TileCalibDrawerOfc, TileCalibDrawerBch, \
22 TileCalibDrawerFlt, TileCalibType
23from TileCalibBlobPython
import TileCalibTools
26from TileCalibBlobPython.TileCalibLogger
import TileCalibLogger, getLogger
27log = getLogger(
"TileCalibCrest")
43MAXRUNLUMI = (MAXRUN<<32)+MAXLBK
50 TileCalibBlobReader is a helper class, managing the details of CREST interactions for
51 the user of TileCalibBlobs.
55 def __init__(self, db, folder='', tag='', run=None, lumi=0, modmin=0, modmax=275, copyBlob=False):
58 - db : server connection string or file name
59 - folder: full folder path
60 - tag : The folder tag, e.g. \"UPD4-24\" or full tag
61 - run : Run number (if known)
62 - lumi : Lumi block number
63 - modmin: Minimal module (COOL channel number)
64 - modmax: Maximal module (COOL channel number)
65 - copyBlob: save payload from CREST (Default:False, True to copy payload to json file)
68 TileCalibLogger.__init__(self,
"TileBlobReader")
85 self.
__remote = ((
"http://" in db)
or (
"https://" in db)
or (
"CREST" in db))
87 if 'http' not in self.
__db:
88 self.
__db = os.getenv(db,os.getenv(
'CREST_HOST',os.getenv(
'CREST_SERVER_PATH',
'http://crest-j23.cern.ch:8080/api-v5.0')))
89 self.log().info(
'Host %s' , (self.
__db))
91 socks = os.getenv(
'CREST_SOCKS',
'False')
94 if run
is not None and lumi
is not None:
95 log.info(
"Initializing for run %d, lumiblock %d", run,lumi)
98 self.log().info(
'File %s' , (self.
__db))
100 self.
__tag =
'unknown'
101 self.
__iovList.append(((MINRUN,MINLBK),(MAXRUN, MAXLBK)))
103 with open(self.
__db,
'r')
as the_file:
104 jdata = json.load(the_file)
110 blob=jdata[str(chan)][0]
115 blob=jdata[
'1000'][0]
126 if globalTag==
'CURRENT' or globalTag==
'UPD4' or globalTag==
'' or globalTag==
'HEAD':
127 globalTag=TileCalibTools.getAliasFromFile(
'Current')
128 log.info(
"Resolved CURRENT globalTag to \'%s\'", globalTag)
129 elif globalTag==
'CURRENTES' or globalTag==
'UPD1':
130 globalTag=TileCalibTools.getAliasFromFile(
'CurrentES')
131 log.info(
"Resolved CURRENT ES globalTag to \'%s\'", globalTag)
132 elif globalTag==
'NEXT':
133 globalTag=TileCalibTools.getAliasFromFile(
'Next')
134 log.info(
"Resolved NEXT globalTag to \'%s\'", globalTag)
135 elif globalTag==
'NEXTES':
136 globalTag=TileCalibTools.getAliasFromFile(
'NextES')
137 log.info(
"Resolved NEXT ES globalTag to \'%s\'", globalTag)
138 globalTag=globalTag.replace(
'*',
'')
141 for f
in folder.split(
'/'):
142 if re.findall(
'[a-z]+',f) != []
and f!=
'CellNoise':
145 prefix+=f.capitalize()
147 prefix=prefix.strip(
'-').
split(
'-')[0]
148 if prefix.startswith(
'Calo')
and 'NoiseCell' not in prefix:
149 prefix=
'CALO'+prefix[4:]
150 if 'UPD1' in globalTag
or 'UPD4' in globalTag
or 'COND' not in globalTag:
152 if globalTag.startswith(prefix)
or globalTag.startswith(prefix.upper()):
155 tag=prefix+
'-'+globalTag
156 self.log().info(
"Resolved localTag \'%s\' to folderTag \'%s\'", globalTag,tag)
157 elif folder!=
'' and not (globalTag.upper().startswith(
'TILE')
or globalTag.upper().startswith(
'CALO')):
159 if tag.startswith(
'Calo')
and 'NoiseCell' not in tag:
161 self.log().info(
"Resolved localTag \'%s\' to folderTag \'%s\'", globalTag,tag)
164 self.log().info(
"Use localTag \'%s\' as is", tag)
168 tags=api.find_global_tag_map(globalTag)
172 raise Exception(
"globalTag %s not found" % (globalTag) )
174 for i
in range(tags.size):
175 t=tags.resources[i].tag_name
176 l=tags.resources[i].label
177 if (prefix!=
'' and t.startswith(prefix))
or l==folder:
179 self.log().info(
"Resolved globalTag \'%s\' to folderTag \'%s\'", globalTag,tag)
185 def getIovs(self,since=(MINRUN,MINLBK),until=(MAXRUN,MAXLBK)):
189 run_lumi1=str((since[0]<<32)+since[1]+1)
190 run_lumi2=str((until[0]<<32)+until[1]+1)
191 MAXRUNLUMI1=str(MAXRUNLUMI+1)
192 iovs1=self.
__api_instance.select_iovs(self.
__tag,
"0",run_lumi1,sort=
'id.since:DESC,id.insertionTime:DESC',size=1,snapshot=0)
193 iovs2=self.
__api_instance.select_iovs(self.
__tag,run_lumi2,MAXRUNLUMI1,sort=
'id.since:ASC,id.insertionTime:DESC',size=1,snapshot=0)
194 since1=0
if iovs1.size==0
else iovs1.resources[0].since
195 until1=MAXRUNLUMI
if iovs2.size==0
else iovs2.resources[0].since
196 iovs=self.
__api_instance.select_iovs(self.
__tag,str(since1),str(until1),sort=
'id.since:ASC,id.insertionTime:DESC',size=999999,snapshot=0)
199 raise Exception(
"IOV for tag %s IOV [%s,%s] - (%s,%s) not found" % (self.
__tag,since[0],since[1],until[0],until[1]) )
201 for i
in range(iovs.size):
202 iov=iovs.resources[i]
205 lumiS=since&0xFFFFFFFF
206 if (runS,lumiS)
not in iovList:
207 iovList.append((runS,lumiS))
222 run_lumi1=str((runlumi[0]<<32)+runlumi[1]+1)
223 MAXRUNLUMI1=str(MAXRUNLUMI+1)
224 iovs1=self.
__api_instance.select_iovs(self.
__tag,
"0",run_lumi1,sort=
'id.since:DESC,id.insertionTime:DESC',size=1,snapshot=0)
225 iovs2=self.
__api_instance.select_iovs(self.
__tag,run_lumi1,MAXRUNLUMI1,sort=
'id.since:ASC,id.insertionTime:DESC',size=1,snapshot=0)
227 raise Exception(
"IOV for tag %s run,lumi (%s,%s) not found" % (self.
__tag,runlumi[0],runlumi[1]) )
229 iov=iovs1.resources[0]
232 lumiS=since&0xFFFFFFFF
233 until=MAXRUNLUMI
if iovs2.size==0
else iovs2.resources[0].since
235 lumiU=until&0xFFFFFFFF
236 hash=iov.payload_hash
239 self.log().info(
'IOV [%d,%d] - (%d,%d)' , runS,lumiS,runU,lumiU)
240 self.log().info(
'Insertion time %s' , iov.insertion_time)
241 self.log().info(
'Hash %s' , hash)
242 payload = self.
__api_instance.get_payload(hash=hash).decode(
'utf-8')
243 jdata=json.loads(payload)
247 self.
__iovList.append(((runS,lumiS),(runU, lumiU)))
254 blob=jdata[str(chan)][0]
259 blob=jdata[
'1000'][0]
267 since = (runlumi[0][0]<<32) + runlumi[0][1]
268 until = (runlumi[1][0]<<32) + runlumi[1][1]
273 point = (runlumi[0]<<32) + runlumi[1]
274 inrange = point>=self.
__iov[0]
and point<self.
__iov[1]
286 if b64string
is None or len(b64string)==0:
287 if b64string
is None:
293 blob1 = base64.decodebytes(bytes(b64string,
'ascii'))
300 if b64string
is None or isinstance(b64string, (int, float))
or len(b64string)==0:
301 if b64string
is None:
307 blob1 = base64.decodebytes(bytes(b64string,
'ascii'))
313 if typeName==
'TileCalibDrawerFlt':
315 self.log().
debug(
"typeName = Flt " )
316 elif typeName==
'TileCalibDrawerInt':
318 self.log().
debug(
"typeName = Int " )
319 elif typeName==
'TileCalibDrawerBch':
321 self.log().
debug(
"typeName = Bch " )
322 elif typeName==
'TileCalibDrawerOfc':
324 self.log().
debug(
"typeName = Ofc " )
325 elif typeName==
'TileCalibDrawerCmt':
327 self.log().
debug(
"typeName = CaloFlt " )
330 self.log().warn(
"Unknown blob type for chan %d - ignoring", chan)
342 def getBlob(self,ros, mod, runlumi=None, dbg=False):
349 if (chanNum>=0
and chanNum<len(self.
__drawer)):
352 raise Exception(
"Invalid drawer requested: %s %s" % (ros,mod) )
355 def getDrawer(self,ros, mod, runlumi=None, dbg=False, useDefault=True):
362 if (chanNum>=0
and chanNum<len(self.
__drawer)):
364 if not useDefault
and drawer
is None:
369 while drawer
is None:
371 if ros==0
and drawer==0:
372 raise Exception(
'No default available')
378 elif (chanNum == 1000):
381 raise Exception(
"Invalid drawer requested: %s %s" % (ros,mod) )
394 return "<no comment found>"
399 Returns a default drawer number (among first 20 COOL channels) for any drawer in any partition
402 if drawer<=4
or drawer==12
or drawer>=20:
408 elif ros==1
or ros==2:
411 OffsetEBA = [ 0, 0, 0, 0, 0, 0, 3, 2,
412 0, 0, 0, 0, 7, 6, 5, 7,
413 7, 6, 6, 7, 0, 0, 0, 2,
414 3, 0, 0, 0, 0, 0, 0, 0,
415 0, 0, 0, 0, 0, 0, 1, 1,
416 1, 1, 2, 3, 0, 0, 0, 0,
417 0, 0, 0, 0, 3, 2, 1, 1,
418 1, 1, 0, 0, 0, 0, 0, 0]
419 drawer1 = 12 + OffsetEBA[drawer]
421 OffsetEBC = [ 0, 0, 0, 0, 0, 0, 3, 2,
422 0, 0, 0, 0, 7, 6, 6, 7,
423 7, 5, 6, 7, 0, 0, 0, 2,
424 3, 0, 0, 3, 4, 0, 3, 4,
425 0, 4, 3, 0, 4, 3, 1, 1,
426 1, 1, 2, 3, 0, 0, 0, 0,
427 0, 0, 0, 0, 3, 2, 1, 1,
428 1, 1, 0, 0, 0, 0, 0, 0]
429 drawer1 = 12 + OffsetEBC[drawer]
436 def dumpIovs(self, iovList, rosmin, rosmax, drawermin, drawermax, option=1, comment=False, usenames=True):
438 Dumps statistics - how many non-empty modules exists in different IOVs
446 rosrange=list(range(rosmin,rosmax))
449 for since
in iovList:
450 iov=
"(%s,%s)" % since
458 (dmin,dmax) = (drawermin,drawermax)
463 for drawer
in range(dmin,dmax):
464 flt = self.
getDrawer(ros, drawer, since,
False,
False)
474 if mod
not in allmods:
481 allmod +=
" " + mod +
"_zero"
482 allmods[mod] +=
" " + iov +
"_zero"
485 allmods[mod] +=
" " + iov
489 word =
'module' if usenames
else 'COOL channel'
490 if miss==0
and nmod>1:
491 alliovs[iov] =
" All %s" %
plural(nmod,word)
492 elif miss>0
and miss<10:
493 alliovs[iov] =
" %s present, %s missing:%s" % (
plural(nmod-miss,word),
plural(miss,word),missmod)
495 alliovs[iov] =
"%s ; %s present, %s missing" % (allmod,
plural(nmod-miss,word),
plural(miss,word))
496 zeroiovs[iov] = (zero,zeromod)
500 for key,value
in allmods.items():
503 print(
"%s\t%s" % (key,value))
506 for key,value
in alliovs.items():
509 if zeroiovs[key]
and zeroiovs[key][0]>0:
510 if "_zero" not in value:
511 print(
"%s\t%s ; zero-sized blobs for %d modules:%s" % (key,value,zeroiovs[key][0],zeroiovs[key][1]))
513 print(
"%s\t%s ; zero-sized blobs for %d modules" % (key,value,zeroiovs[key][0]))
515 print(
"%s\t%s" % (key,value))
517 print(
"\nNo IOVs found")
522 TileBlobWriterCrest is a helper class, managing the details of
523 CREST interactions for the user of TileCalibBlobs.
527 def __init__(self, db, folderPath, calibDrawerType, payload=None):
530 - db : db should be a database connection
531 - folderPath: full folder path to create or update
535 TileCalibLogger.__init__(self,
"TileBlobWriter")
541 if payload
is not None:
546 if calibDrawerType
in [
'TileCalibDrawerFlt',
'Flt']:
548 self.
__defVec = cppyy.gbl.std.vector(
'std::vector<float>')()
549 elif calibDrawerType
in [
'TileCalibDrawerBch',
'Bch']:
551 self.
__defVec = cppyy.gbl.std.vector(
'std::vector<unsigned int>')()
552 elif calibDrawerType
in [
'TileCalibDrawerInt',
'Int']:
554 self.
__defVec = cppyy.gbl.std.vector(
'std::vector<unsigned int>')()
555 elif calibDrawerType
in [
'CaloCondBlobFlt',
'CaloFlt']:
557 self.
__defVec = cppyy.gbl.std.vector(
'std::vector<float>')()
559 raise Exception(
"Unknown calibDrawerType: %s" % calibDrawerType)
565 def register(self, since=(MINRUN,MINLBK), tag=
"", chan=-1, payload=
None):
567 Registers the folder in the database.
568 - since: lower limit of IOV
569 - tag : The tag to write to
570 - chan : COOL channel to write, if negative - all COOL channels are written
571 Comment channel is always written
573 The interpretation of the 'since' inputs depends on their type:
574 - tuple(int,int) : run and lbk number
577 if self.
__payload is None and payload
is None:
580 if chan<0
or drawerIdx==chan
or drawerIdx==1000:
581 if blob
is None or blob==0:
585 b64string = str(base64.b64encode(blob.read()),
'ascii')
586 jdata[drawerIdx] = [b64string]
588 if payload
is not None:
592 (sinceRun, sinceLumi) = since
594 if not self.
__db or (self.
__db and self.
__db.endswith(
'.json')):
597 if self.
__folderPath and not (tag.upper().startswith(
'TILE')
or tag.upper().startswith(
'CALO')):
599 fileName = f
"{fullTag}.{sinceRun}.{sinceLumi}.json"
601 fileName = f
'{self.__db[:-5]}.{fileName}'
603 with open(fileName,
'w')
as the_file:
604 json.dump(jdata, the_file)
608 self.log().info(
'Writting tag "%s"', fullTag)
609 self.log().info(
'... since : [%s,%s]' , sinceRun, sinceLumi)
611 self.log().info(
'... with comment field: "%s"', self.
getComment())
612 self.log().info(
'... into file : %s' , fileName)
617 Sets a general comment in the comment channel.
622 commentBlob.resize(0)
627 if isinstance(author, tuple)
and len(author) == 3:
628 tm = time.mktime(datetime.datetime.strptime(author[2],
"%a %b %d %H:%M:%S %Y").timetuple())
636 Returns the general comment (default if none is set)
642 return (comment.getAuthor(), self.__comment.
getComment(), self.__comment.getDate())
644 return comment.getFullComment()
646 return "<no comment found>"
649 def getDrawer(self, ros, drawer, calibDrawerTemplate=None):
651 Returns a TileCalibDrawer object of requested type
652 for the given ROS and drawer.
664 self.
__drawer[drawerIdx] = calibDrawer
667 if calibDrawerTemplate:
668 calibDrawer.clone(calibDrawerTemplate)
672 except Exception
as e:
673 self.log().critical( e )
679 Resets blob size to zero
685 except Exception
as e:
686 self.log().critical( e )
693 Calculates TileCalibDrawer index
694 from ros number and drawer number
707 merges integer number and text
708 and adds 's' at the end of text
void print(char *figname, TCanvas *c1)
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 std::string getDrawerString(unsigned int ros, unsigned int drawer)
Return the drawer name, e.g.
static unsigned int max_draweridx()
Python compatibility function.
static unsigned int getDrawerIdx(unsigned int ros, unsigned int drawer)
Returns a drawer hash.
static unsigned int getMaxDrawer(unsigned int ros)
Returns the maximal channel number for a given drawer.
static std::string getFullTag(const std::string &folder, const std::string &tag)
Returns the full tag string, composed of camelized folder name and tag part.
static unsigned int getCommentChannel()
Returns the COOL channel number for the comment channel.
__create_comment(self, b64string)
getIovs(self, since=(MINRUN, MINLBK), until=(MAXRUN, MAXLBK))
__create_drawer(self, b64string, chan)
getFolderTag(self, folder, prefix, globalTag, api=None)
getPayload(self, runlumi=None, dbg=False)
__init__(self, db, folder='', tag='', run=None, lumi=0, modmin=0, modmax=275, copyBlob=False)
__checkIov(self, runlumi)
getDrawer(self, ros, mod, runlumi=None, dbg=False, useDefault=True)
__getIov(self, runlumi, dbg=False)
dumpIovs(self, iovList, rosmin, rosmax, drawermin, drawermax, option=1, comment=False, usenames=True)
getComment(self, runlumi=None, split=False)
getBlob(self, ros, mod, runlumi=None, dbg=False)
__make_blob(self, string)
__runlumi2iov(self, runlumi)
getDefault(self, ros, drawer)
getDrawer(self, ros, drawer, calibDrawerTemplate=None)
zeroBlob(self, ros, drawer)
setComment(self, author, comment=None)
getComment(self, split=False)
__init__(self, db, folderPath, calibDrawerType, payload=None)
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
std::vector< std::string > split(const std::string &s, const std::string &t=":")
getDrawerIdx(ros, drawer)