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',
'https://atlas-crest-dev-mgr.cern.ch:443/api-v6.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 prefix=prefix.replace(
'Pileupnoiselumi',
'PileUpNoiseLumi')
151 if 'UPD1' in globalTag
or 'UPD4' in globalTag
or (
'COND' not in globalTag
and 'CREST' not in globalTag):
153 if prefix
in globalTag
or prefix.upper()
in globalTag:
156 tag=prefix+
'-'+globalTag
157 self.log().info(
"Resolved localTag \'%s\' to folderTag \'%s\'", globalTag,tag)
158 elif folder!=
'' and not (globalTag.upper().startswith(
'TILE')
or globalTag.upper().startswith(
'CALO')):
160 if tag.startswith(
'Calo')
and 'NoiseCell' not in tag:
162 tag=tag.replace(
'Pileupnoiselumi',
'PileUpNoiseLumi')
163 self.log().info(
"Resolved localTag \'%s\' to folderTag \'%s\'", globalTag,tag)
166 self.log().info(
"Use localTag \'%s\' as is", tag)
170 tags=api.find_global_tag_map(globalTag)
176 raise Exception(
"globalTag %s not found" % (globalTag) )
178 for i
in range(tags.size):
179 t=tags.resources[i].tag_name
180 l=tags.resources[i].label
181 if (prefix!=
'' and t.startswith(prefix))
or l==folder:
183 self.log().info(
"Resolved globalTag \'%s\' to folderTag \'%s\'", globalTag,tag)
189 def getIovs(self,since=(MINRUN,MINLBK),until=(MAXRUN,MAXLBK)):
193 run_lumi1=str((since[0]<<32)+since[1]+1)
194 run_lumi2=str((until[0]<<32)+until[1]+1)
195 MAXRUNLUMI1=str(MAXRUNLUMI+1)
196 iovs1=self.
__api_instance.select_iovs(self.
__tag,
"0",run_lumi1,sort=
'id.since:DESC,id.insertionTime:DESC',size=1,snapshot=0)
197 iovs2=self.
__api_instance.select_iovs(self.
__tag,run_lumi2,MAXRUNLUMI1,sort=
'id.since:ASC,id.insertionTime:DESC',size=1,snapshot=0)
198 since1=0
if iovs1.size==0
else iovs1.resources[0].since
199 until1=MAXRUNLUMI
if iovs2.size==0
else iovs2.resources[0].since
200 iovs=self.
__api_instance.select_iovs(self.
__tag,str(since1),str(until1),sort=
'id.since:ASC,id.insertionTime:DESC',size=999999,snapshot=0)
203 raise Exception(
"IOV for tag %s IOV [%s,%s] - (%s,%s) not found" % (self.
__tag,since[0],since[1],until[0],until[1]) )
205 for i
in range(iovs.size):
206 iov=iovs.resources[i]
209 lumiS=since&0xFFFFFFFF
210 if (runS,lumiS)
not in iovList:
211 iovList.append((runS,lumiS))
226 run_lumi1=str((runlumi[0]<<32)+runlumi[1]+1)
227 MAXRUNLUMI1=str(MAXRUNLUMI+1)
228 iovs1=self.
__api_instance.select_iovs(self.
__tag,
"0",run_lumi1,sort=
'id.since:DESC,id.insertionTime:DESC',size=1,snapshot=0)
229 iovs2=self.
__api_instance.select_iovs(self.
__tag,run_lumi1,MAXRUNLUMI1,sort=
'id.since:ASC,id.insertionTime:DESC',size=1,snapshot=0)
231 raise Exception(
"IOV for tag %s run,lumi (%s,%s) not found" % (self.
__tag,runlumi[0],runlumi[1]) )
233 iov=iovs1.resources[0]
236 lumiS=since&0xFFFFFFFF
237 until=MAXRUNLUMI
if iovs2.size==0
else iovs2.resources[0].since
239 lumiU=until&0xFFFFFFFF
240 hash=iov.payload_hash
243 self.log().info(
'IOV [%d,%d] - (%d,%d)' , runS,lumiS,runU,lumiU)
244 self.log().info(
'Insertion time %s' , iov.insertion_time)
245 self.log().info(
'Hash %s' , hash)
246 payload = self.
__api_instance.get_payload(hash=hash).decode(
'utf-8')
247 jdata=json.loads(payload)
251 self.
__iovList.append(((runS,lumiS),(runU, lumiU)))
258 blob=jdata[str(chan)][0]
263 blob=jdata[
'1000'][0]
271 since = (runlumi[0][0]<<32) + runlumi[0][1]
272 until = (runlumi[1][0]<<32) + runlumi[1][1]
277 point = (runlumi[0]<<32) + runlumi[1]
278 inrange = point>=self.
__iov[0]
and point<self.
__iov[1]
290 if b64string
is None or len(b64string)==0:
291 if b64string
is None:
297 blob1 = base64.decodebytes(bytes(b64string,
'ascii'))
304 if b64string
is None or isinstance(b64string, (int, float))
or len(b64string)==0:
305 if b64string
is None:
311 blob1 = base64.decodebytes(bytes(b64string,
'ascii'))
317 if typeName==
'TileCalibDrawerFlt':
319 self.log().
debug(
"typeName = Flt " )
320 elif typeName==
'TileCalibDrawerInt':
322 self.log().
debug(
"typeName = Int " )
323 elif typeName==
'TileCalibDrawerBch':
325 self.log().
debug(
"typeName = Bch " )
326 elif typeName==
'TileCalibDrawerOfc':
328 self.log().
debug(
"typeName = Ofc " )
329 elif typeName==
'TileCalibDrawerCmt':
331 self.log().
debug(
"typeName = CaloFlt " )
334 self.log().warn(
"Unknown blob type for chan %d - ignoring", chan)
346 def getBlob(self,ros, mod, runlumi=None, dbg=False):
353 if (chanNum>=0
and chanNum<len(self.
__drawer)):
356 raise Exception(
"Invalid drawer requested: %s %s" % (ros,mod) )
359 def getDrawer(self,ros, mod, runlumi=None, dbg=False, useDefault=True):
366 if (chanNum>=0
and chanNum<len(self.
__drawer)):
368 if not useDefault
and drawer
is None:
373 while drawer
is None:
375 if ros==0
and drawer==0:
376 raise Exception(
'No default available')
382 elif (chanNum == 1000):
385 raise Exception(
"Invalid drawer requested: %s %s" % (ros,mod) )
398 return "<no comment found>"
403 Returns a default drawer number (among first 20 COOL channels) for any drawer in any partition
406 if drawer<=4
or drawer==12
or drawer>=20:
412 elif ros==1
or ros==2:
415 OffsetEBA = [ 0, 0, 0, 0, 0, 0, 3, 2,
416 0, 0, 0, 0, 7, 6, 5, 7,
417 7, 6, 6, 7, 0, 0, 0, 2,
418 3, 0, 0, 0, 0, 0, 0, 0,
419 0, 0, 0, 0, 0, 0, 1, 1,
420 1, 1, 2, 3, 0, 0, 0, 0,
421 0, 0, 0, 0, 3, 2, 1, 1,
422 1, 1, 0, 0, 0, 0, 0, 0]
423 drawer1 = 12 + OffsetEBA[drawer]
425 OffsetEBC = [ 0, 0, 0, 0, 0, 0, 3, 2,
426 0, 0, 0, 0, 7, 6, 6, 7,
427 7, 5, 6, 7, 0, 0, 0, 2,
428 3, 0, 0, 3, 4, 0, 3, 4,
429 0, 4, 3, 0, 4, 3, 1, 1,
430 1, 1, 2, 3, 0, 0, 0, 0,
431 0, 0, 0, 0, 3, 2, 1, 1,
432 1, 1, 0, 0, 0, 0, 0, 0]
433 drawer1 = 12 + OffsetEBC[drawer]
440 def dumpIovs(self, iovList, rosmin, rosmax, drawermin, drawermax, option=1, comment=False, usenames=True):
442 Dumps statistics - how many non-empty modules exists in different IOVs
450 rosrange=list(range(rosmin,rosmax))
453 for since
in iovList:
454 iov=
"(%s,%s)" % since
462 (dmin,dmax) = (drawermin,drawermax)
467 for drawer
in range(dmin,dmax):
468 flt = self.
getDrawer(ros, drawer, since,
False,
False)
478 if mod
not in allmods:
485 allmod +=
" " + mod +
"_zero"
486 allmods[mod] +=
" " + iov +
"_zero"
489 allmods[mod] +=
" " + iov
493 word =
'module' if usenames
else 'COOL channel'
494 if miss==0
and nmod>1:
495 alliovs[iov] =
" All %s" %
plural(nmod,word)
496 elif miss>0
and miss<10:
497 alliovs[iov] =
" %s present, %s missing:%s" % (
plural(nmod-miss,word),
plural(miss,word),missmod)
499 alliovs[iov] =
"%s ; %s present, %s missing" % (allmod,
plural(nmod-miss,word),
plural(miss,word))
500 zeroiovs[iov] = (zero,zeromod)
504 for key,value
in allmods.items():
507 print(
"%s\t%s" % (key,value))
510 for key,value
in alliovs.items():
513 if zeroiovs[key]
and zeroiovs[key][0]>0:
514 if "_zero" not in value:
515 print(
"%s\t%s ; zero-sized blobs for %d modules:%s" % (key,value,zeroiovs[key][0],zeroiovs[key][1]))
517 print(
"%s\t%s ; zero-sized blobs for %d modules" % (key,value,zeroiovs[key][0]))
519 print(
"%s\t%s" % (key,value))
521 print(
"\nNo IOVs found")
526 TileBlobWriterCrest is a helper class, managing the details of
527 CREST interactions for the user of TileCalibBlobs.
531 def __init__(self, db, folderPath, calibDrawerType, payload=None):
534 - db : db should be a database connection
535 - folderPath: full folder path to create or update
539 TileCalibLogger.__init__(self,
"TileBlobWriter")
545 if payload
is not None:
550 if calibDrawerType
in [
'TileCalibDrawerFlt',
'Flt']:
552 self.
__defVec = cppyy.gbl.std.vector(
'std::vector<float>')()
553 elif calibDrawerType
in [
'TileCalibDrawerBch',
'Bch']:
555 self.
__defVec = cppyy.gbl.std.vector(
'std::vector<unsigned int>')()
556 elif calibDrawerType
in [
'TileCalibDrawerInt',
'Int']:
558 self.
__defVec = cppyy.gbl.std.vector(
'std::vector<unsigned int>')()
559 elif calibDrawerType
in [
'CaloCondBlobFlt',
'CaloFlt']:
561 self.
__defVec = cppyy.gbl.std.vector(
'std::vector<float>')()
563 raise Exception(
"Unknown calibDrawerType: %s" % calibDrawerType)
569 def register(self, since=(MINRUN,MINLBK), tag=
"", chan=-1, payload=
None):
571 Registers the folder in the database.
572 - since: lower limit of IOV
573 - tag : The tag to write to
574 - chan : COOL channel to write, if negative - all COOL channels are written
575 Comment channel is always written
577 The interpretation of the 'since' inputs depends on their type:
578 - tuple(int,int) : run and lbk number
581 if self.
__payload is None and payload
is None:
584 if chan<0
or drawerIdx==chan
or drawerIdx==1000:
585 if blob
is None or blob==0:
589 b64string = str(base64.b64encode(blob.read()),
'ascii')
590 jdata[drawerIdx] = [b64string]
592 if payload
is not None:
596 (sinceRun, sinceLumi) = since
598 if not self.
__db or (self.
__db and self.
__db.endswith(
'.json')):
601 if self.
__folderPath and not (tag.upper().startswith(
'TILE')
or tag.upper().startswith(
'CALO')):
603 fileName = f
"{fullTag}.{sinceRun}.{sinceLumi}.json"
605 fileName = f
'{self.__db[:-5]}.{fileName}'
607 with open(fileName,
'w')
as the_file:
608 json.dump(jdata, the_file, separators=(
',',
':'), sort_keys=
True)
611 self.log().info(
'Writting tag "%s"', fullTag)
612 self.log().info(
'... since : [%s,%s]' , sinceRun, sinceLumi)
614 self.log().info(
'... with comment field: "%s"', self.
getComment())
615 self.log().info(
'... into file : %s' , fileName)
620 Sets a general comment in the comment channel.
625 commentBlob.resize(0)
630 if isinstance(author, tuple)
and len(author) == 3:
631 tm = time.mktime(datetime.datetime.strptime(author[2],
"%a %b %d %H:%M:%S %Y").timetuple())
639 Returns the general comment (default if none is set)
645 return (comment.getAuthor(), self.__comment.
getComment(), self.__comment.getDate())
647 return comment.getFullComment()
649 return "<no comment found>"
652 def getDrawer(self, ros, drawer, calibDrawerTemplate=None):
654 Returns a TileCalibDrawer object of requested type
655 for the given ROS and drawer.
667 self.
__drawer[drawerIdx] = calibDrawer
670 if calibDrawerTemplate:
671 calibDrawer.clone(calibDrawerTemplate)
675 except Exception
as e:
676 self.log().critical( e )
682 Resets blob size to zero
688 except Exception
as e:
689 self.log().critical( e )
696 Calculates TileCalibDrawer index
697 from ros number and drawer number
710 merges integer number and text
711 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, std::string_view author="", std::string_view comment="", uint64_t timeStamp=0)
Returns a pointer to a non-const TileCalibDrawerOfc.
static std::string getClassName(TileCalibType::TYPE type)
Returns the class name.
static std::string getDrawerString(unsigned int ros, unsigned int drawer)
Return the drawer name, e.g.
static unsigned int max_draweridx()
Python compatibility function.
static unsigned int getDrawerIdx(unsigned int ros, unsigned int drawer)
Returns a drawer hash.
static unsigned int getMaxDrawer(unsigned int ros)
Returns the maximal channel number for a given drawer.
static std::string getFullTag(const std::string &folder, const std::string &tag)
Returns the full tag string, composed of camelized folder name and tag part.
static unsigned int getCommentChannel()
Returns the COOL channel number for the comment channel.
__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)
register(self, since=(MINRUN, MINLBK), tag="", chan=-1, payload=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)