ATLAS Offline Software
Loading...
Searching...
No Matches
WriteCellNoiseToCrest.py
Go to the documentation of this file.
1#!/bin/env python
2
3# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
4#
5# File: WriteCellNoiseToCrest.py
6# Sanya Solodkov <Sanya.Solodkov@cern.ch>, 2025-11-18
7#
8# Purpose: Prepare JSON file with new cell noise constants
9# reading them from ascii file specified after --txtfile= option
10# or just rescale old constants using one of --scale??? options
11# All cells are always written, for cells which are not
12# mentioned in ascii file previous values are copied from CREST DB
13#
14
15import getopt,sys,os,re,bisect
16os.environ['TERM'] = 'linux'
17
18def usage():
19 print ("Usage: ",sys.argv[0]," [OPTION] ... ")
20 print ("Updates Cell Noise database using new values from ASCII file")
21 print ("")
22 print ("-h, --help shows this help")
23 print ("-i, --inschema= specify name of input JSON file or CREST_SERVER_PATH")
24 print ("-o, --outschema= specify name of output JSON file, default is CaloNoise.json")
25 print ("-t, --tag= specify the input tag")
26 print ("-T, --outtag= specify the output tag if different from input tag")
27 print ("-f, --folder= specify status folder to use e.g. /TILE/OFL02/NOISE/CELL")
28 print ("-x, --txtfile= specify the text file with the new noise constants")
29 print ("-r, --run= specify run number for start of IOV")
30 print ("-l, --lumi= specify lumiblock number for start of IOV, default is 0")
31 print ("-b, --begin= specify run number of first iov in multi-iov mode, by default uses very first iov")
32 print ("-e, --end= specify run number of last iov in multi-iov mode, by default uses latest iov")
33 print ("-L, --endlumi= specify lumi block number for last iov in multi-iov mode, default is 0")
34 print ("-A, --adjust in multi-iov mode adjust iov boundaries to nearest iov available in DB, default is False")
35 print ("-c, --comment= specify comment which should be written to DB, in multi-iov mode it is appended to old comment")
36 print ("-C, --Comment= specify comment which should be written to DB, in mutli-iov mode it overwrites old comment")
37 print ("-U, --user= specify username for comment")
38 print ("-n, --channel= specify COOL channel to use (48 by defalt)")
39 print ("-s, --scale= specify scale factor for all the fields except ratio field")
40 print ("--scaleElec= specify separate scale factor for all electronic noise fields except ratio field")
41 print ("if run number and lumiblock number are omitted - all IOVs from input file are updated")
42
43letters = "hi:o:t:T:f:x:r:l:b:e:L:A:c:C:U:n:s:"
44keywords = ["help","inschema=","outschema=","tag=","outtag=","folder=","txtfile=","run=","lumi=","begin=","end=","endlumi=","adjust",
45 "channel=","scale=","scaleA=","scaleB=","scaleD=","scaleE=","scaleD4=","scaleC10=","scaleD4sp=","scaleC10sp=","scaleElec=",
46 "comment=","Comment=","user=","intag=","infile=","outfile="]
47
48try:
49 opts, extraparams = getopt.getopt(sys.argv[1:],letters,keywords)
50except getopt.GetoptError as err:
51 print (str(err))
52 usage()
53 sys.exit(2)
54
55# defaults
56inSchema = 'CREST'
57outSchema = 'CaloNoise.json'
58inTag = ''
59outTag = ''
60folderPath = '/TILE/OFL02/NOISE/CELL'
61txtFile = ''
62run = -1
63lumi = 0
64beg = -1
65end = 2147483647
66endlumi = 0
67iov = True
68adjust = False
69update = False
70chan = 48 # represents Tile
71scale = 0.0 # means do not scale
72scaleA = 0.0 # scale for pileup term in A cells
73scaleB = 0.0 # scale for pileup term in B cells
74scaleD = 0.0 # scale for pileup term in D cells
75scaleE = 0.0 # scale for pileup term in E cells
76scaleD4 = 0.0 # scale for pileup term in D4
77scaleC10 = 0.0 # scale for pileup term in C10
78scaleD4sp = 0.0 # scale for pileup term in D4 special
79scaleC10sp = 0.0 # scale for pileup term in C10 special
80scaleElec = 0.0 # scale for electronic noise
81
82comment = ""
83Comment = None
84try:
85 user=os.getlogin()
86except Exception:
87 user="UnknownUser"
88
89for o, a in opts:
90 a = a.strip()
91 if o in ("-i","--inschema","--infile"):
92 inSchema = a
93 elif o in ("-o","--outschema","--outfile"):
94 outSchema = a
95 elif o in ("-t","--tag","--intag"):
96 inTag = a
97 elif o in ("-T","--outtag"):
98 outTag = a
99 elif o in ("-f","--folder"):
100 folderPath = a
101 elif o in ("-r","--run"):
102 run = int(a)
103 if run>=0:
104 iov = False
105 elif o in ("-l","--lumi"):
106 lumi = int(a)
107 elif o in ("-b","--begin"):
108 beg = int(a)
109 iov = True
110 elif o in ("-e","--end"):
111 end = int(a)
112 elif o in ("-L","--endlumi"):
113 endlumi = int(a)
114 elif o in ("-A","--adjust"):
115 adjust = True
116 elif o in ("-u","--update"):
117 update = True
118 elif o in ("-n","--channel"):
119 chan = int(a)
120 elif o in ("-s","--scale"):
121 scale = float(a)
122 elif o in ("-s","--scaleA"):
123 scaleA = float(a)
124 elif o in ("-s","--scaleB"):
125 scaleB = float(a)
126 elif o in ("-s","--scaleD"):
127 scaleD = float(a)
128 elif o in ("-s","--scaleE"):
129 scaleE = float(a)
130 elif o in ("-s","--scaleD4"):
131 scaleD4 = float(a)
132 elif o in ("-s","--scaleC10"):
133 scaleC10 = float(a)
134 elif o in ("-s","--scaleD4sp"):
135 scaleD4sp = float(a)
136 elif o in ("-s","--scaleC10sp"):
137 scaleC10sp = float(a)
138 elif o in ("-s","--scaleElec"):
139 scaleElec = float(a)
140 elif o in ("-x","--txtfile"):
141 txtFile = a
142 elif o in ("-c","--comment"):
143 comment = a
144 elif o in ("-C","--Comment"):
145 Comment = a
146 comment = a
147 elif o in ("-U","--user"):
148 user = a
149 elif o in ("-h","--help"):
150 usage()
151 sys.exit(2)
152 else:
153 print (o, a)
154 usage()
155 sys.exit(2)
156
157tile=(chan==48)
158
159rescale=(scale>0.0)
160if scaleElec == 0.0:
161 scaleElec = scale
162else:
163 rescale=True
164if scaleA == 0.0:
165 scaleA = scale
166else:
167 rescale=True
168if scaleB == 0.0:
169 scaleB = scale
170else:
171 rescale=True
172if scaleD == 0.0:
173 scaleD = scale
174else:
175 rescale=True
176if scaleE == 0.0:
177 scaleE = scale
178else:
179 rescale=True
180if scaleD4 == 0.0:
181 scaleD4 = scaleD
182else:
183 rescale=True
184if scaleC10 == 0.0:
185 scaleC10 = scaleB
186else:
187 rescale=True
188if scaleD4sp == 0.0:
189 scaleD4sp = scaleD4
190else:
191 rescale=True
192if scaleC10sp == 0.0:
193 scaleC10sp = scaleC10
194else:
195 rescale=True
196
197#=== check presence of all parameters
198print ("")
199inputIsFile = os.path.isfile(inSchema)
200inTagIsFullTag = (inTag.upper().startswith('TILE') or inTag.upper().startswith('CALO') or inTag.upper().startswith("LAR"))
201if len(outTag)<1:
202 outTag = inTag
203outTagIsFullTag = (outTag.upper().startswith('TILE') or outTag.upper().startswith('CALO') or outTag.upper().startswith("LAR"))
204if len(inSchema)<1:
205 print("Please, provide inschema (e.g. --inschema=CaloNoise.json or --inschema=CREST)")
206 sys.exit(2)
207if len(outSchema)<1:
208 print("Please, provide outschema (e.g. --outschema=CaloNoise.json)")
209 sys.exit(2)
210if not inputIsFile:
211 if len(folderPath)<1 and not inTagIsFullTag:
212 print("Please, provide folder (e.g. --folder=/TILE/OFL02/NOISE/CELL)")
213 sys.exit(2)
214 if len(inTag)<1:
215 print("Please, provide tag (e.g. --tag=RUN2-UPD4-34 or --tag=TileOfl02NoiseCell-RUN2-UPD4-34)")
216 sys.exit(2)
217if len(outTag)<1:
218 print("Please, provide outtag (e.g. --tag=RUN2-UPD4-35 --outtag=TileOfl02NoiseCell-RUN2-UPD4-35)")
219 sys.exit(2)
220if not outTagIsFullTag:
221 if inputIsFile:
222 print("Please, provide full outtag (e.g. --outtag=TileOfl02NoiseCell-RUN2-UPD4-35)")
223 sys.exit(2)
224 elif len(folderPath)<1:
225 print("Please, provide folder (e.g. --folder=/TILE/OFL02/NOISE/CELL)")
226 sys.exit(2)
227
228import cppyy
229
230from TileCalibBlobPython import TileCalibLogger
231from TileCalibBlobPython import TileCalibCrest
232from TileCalibBlobPython import TileCellTools
233
234# get a logger
235log = TileCalibLogger.getLogger("WriteCellNoise")
236import logging
237if iov:
238 log.setLevel(logging.INFO)
239else:
240 log.setLevel(logging.DEBUG)
241
242rb = max(run,beg)
243if rb<0:
244 if rb<=-30:
245 cabling = 'RUN3'
246 elif rb<=-21:
247 cabling = 'RUN2a'
248 elif rb<=-20:
249 cabling = 'RUN2'
250 elif rb<=-10:
251 cabling = 'RUN1'
252 else:
253 cabling = 'RUN2a'
254elif rb>=400000:
255 cabling = 'RUN3'
256elif rb>=342550:
257 cabling = 'RUN2a'
258elif rb>=222222:
259 cabling = 'RUN2'
260else:
261 cabling = 'RUN1'
262
263hashMgr=None
264hashMgrDef=TileCellTools.TileCellHashMgr(cabling=cabling)
265hashMgrA=TileCellTools.TileCellHashMgr("UpgradeA")
266hashMgrBC=TileCellTools.TileCellHashMgr("UpgradeBC")
267hashMgrABC=TileCellTools.TileCellHashMgr("UpgradeABC")
268
269iovList = []
270iovUntil = []
271until = (TileCalibCrest.MAXRUN,TileCalibCrest.MAXLBK)
272if end >= TileCalibCrest.MAXRUN:
273 end = TileCalibCrest.MAXRUN
274 endlumi = TileCalibCrest.MAXLBK
275
276#=== Initialize blob reader
277inFolder = folderPath
278if inTagIsFullTag:
279 inFolder=""
280if not inputIsFile:
281 log.info("Initializing folder %s with tag %s", inFolder, inTag)
282reader = TileCalibCrest.TileBlobReaderCrest(inSchema,inFolder,inTag)
283blob = reader.getBlob(-1,chan,(end,endlumi),False)
284if blob is None:
285 log.critical("Could not locate a data blob in CREST payload for COOL channel %s", chan)
286 sys.exit(1)
287
288if not outTagIsFullTag and not inputIsFile :
289 if inTag==outTag:
290 outTag = reader.getTag()
291 else:
292 outTag = reader.getFolderTag(folderPath,None,outTag)
293
294if iov:
295 iovList = reader.getIovs()
296 iovList += [until]
297 if beg<0:
298 since = iovList[0]
299 else:
300 since = (beg, lumi)
301 ib=bisect.bisect(iovList,since)-1
302 if ib<0:
303 ib=0
304 if iovList[ib] != since:
305 if adjust:
306 since = iovList[ib]
307 log.info( "Moving beginning of first IOV with new cell noise from (%d,%d) to (%d,%d)" , beg,lumi,since[0],since[1])
308 else:
309 iovList[ib] = since
310 log.info( "Creating new IOV starting from (%d,%d) with new cell noise" , beg,lumi)
311
312 if end<0:
313 ie=ib+1
314 if ie>=len(iovList):
315 ie=ib
316 until=iovList[ie]
317 log.info( "Next IOV with old cell noise starts from (%d,%d)" , until[0],until[1])
318 else:
319 until=(end,endlumi)
320 ie=bisect.bisect_left(iovList,until)
321 if ie>=len(iovList):
322 ie=len(iovList)-1
323
324 if iovList[ie] != until:
325 if adjust:
326 until=iovList[ie]
327 log.info( "Moving end of last IOV from (%d,%d) to (%d,%d)" , end,endlumi,until[0],until[1])
328 else:
329 log.info( "Keeping end of last IOV at (%d,%d) - new IOV is shorter than IOV in input DB" , end,endlumi)
330 iovList[ie] = until
331
332 iovList = iovList[ib:ie]
333 iovUntil = iovList[1:] + [until]
334 run = since[0]
335 lumi = since[1]
336 log.info( "IOVs: %s" , str(iovList))
337 log.info( "%d IOVs in total, end of last IOV is %s" , ie-ib,str(until))
338else:
339 if Comment is None and len(comment)>0:
340 Comment = comment
341
342if len(iovList)==0:
343 if run<0:
344 print("Please, provide run number at command line")
345 sys.exit(2)
346 else:
347 log.info( "Creating single IOV starting from run,lumi %d,%d" , run,lumi)
348 since = (run, lumi)
349 until = (end, endlumi)
350 iovList = [since]
351 iovUntil = [until]
352
353#== read input file
354cellData = {}
355ival=0
356igain=0
357icell=[0,0,0,0,0,0,0]
358gain=-1
359useNames=None
360useModuleNames=None
361useGain=None
362
363if len(txtFile):
364 try:
365 with open(txtFile,"r") as f:
366 cellDataText = f.readlines()
367 except Exception:
368 print("\nCan not read input file %s" % (txtFile))
369 sys.exit(2)
370
371 for line in cellDataText:
372 fields = line.strip().split()
373 #=== ignore empty and comment lines
374 if not len(fields) :
375 continue
376 if fields[0].startswith("#"):
377 continue
378
379 if fields[0][:1].isalpha():
380 print (fields)
381 if useNames is not None and not useNames:
382 print("Mixture of formats in inpyt file %s - useNames" % (txtFile))
383 sys.exit(2)
384 useNames=True
385 if fields[0]=='Cell':
386 if useModuleNames is not None and useModuleNames:
387 print("Mixture of formats in inpyt file %s - useModuleNames" % (txtFile))
388 sys.exit(2)
389 useModuleNames=False
390 modName=''
391 cellName=fields[1]
392 else:
393 if useModuleNames is not None and not useModuleNames:
394 print("Mixture of formats in inpyt file %s - useModuleNames" % (txtFile))
395 sys.exit(2)
396 useModuleNames=True
397 modName=fields[0]
398 cellName=fields[1]
399 if fields[2].isdigit():
400 if useGain is not None and not useGain:
401 print("Mixture of formats in inpyt file %s - useGain" % (txtFile))
402 sys.exit(2)
403 useGain=True
404 gain=int(fields[2])
405 noise = fields[3:]
406 if ival<len(noise):
407 ival=len(noise)
408 if igain<gain:
409 igain=gain
410 else:
411 if useGain is not None and useGain:
412 print("Mixture of formats in inpyt file %s - useGain" % (txtFile))
413 sys.exit(2)
414 if len(fields)>3:
415 print("Too many fields in input file %s" % (txtFile))
416 sys.exit(2)
417 useGain=False
418 gain=-1
419 noise = [-1]+fields[2:]
420 ival=1
421 if cellName=='D0':
422 cellName='D*0'
423 if cellName.startswith('BC'):
424 cellName='B'+cellName[2:]
425 if not ('+' in cellName or '-' in cellName or '*' in cellName):
426 p = re.search("\\d", cellName).start()
427 cellPos = modName+cellName[:p] + '+' + cellName[p:]
428 cellNeg = modName+cellName[:p] + '-' + cellName[p:]
429 dictKey = (cellPos,gain)
430 cellData[dictKey] = noise
431 dictKey = (cellNeg,gain)
432 cellData[dictKey] = noise
433 if (cellName=='spE1'):
434 for cellNm in ['mbE+1','mbE-1','e4E+1','e4E-1']:
435 cellN = modName+cellNm
436 dictKey = (cellN,gain)
437 if dictKey not in cellData:
438 cellData[dictKey] = noise
439 else:
440 cellN = modName+cellName
441 dictKey = (cellN,gain)
442 cellData[dictKey] = noise
443 if (cellName=='spE+1'):
444 for cellNm in ['mbE+1','e4E+1']:
445 cellN = modName+cellNm
446 dictKey = (cellN,gain)
447 if dictKey not in cellData:
448 cellData[dictKey] = noise
449 if (cellName=='spE-1'):
450 for cellNm in ['mbE-1','e4E-1']:
451 cellN = modName+cellNm
452 dictKey = (cellN,gain)
453 if dictKey not in cellData:
454 cellData[dictKey] = noise
455 icell[gain]+=1
456 else:
457 if useNames is not None and useNames:
458 print("Mixture of formats in input file %s - useNames" % (txtFile))
459 sys.exit(2)
460 useNames=False
461 cellHash = int(fields[0])
462 cellGain = int(fields[1])
463 noise = fields[2:]
464 dictKey = (cellHash,cellGain)
465 cellData[dictKey] = noise
466 if icell[gain]<cellHash:
467 icell[gain]=cellHash
468 if igain<cellGain:
469 igain=cellGain
470 if ival<len(noise):
471 ival=len(noise)
472 if not useNames:
473 icell[gain]+=1
474 else:
475 print (cellData)
476 igain=igain+1
477else:
478 log.info("No input txt file provided, making copy from input DB to output DB")
479
480nval=ival
481ngain=igain
482ncell=max(icell)
483
484if not tile:
485 modName="LAr %2d" % chan
486 cellName=""
487 fullName=modName
488
489#=== loop over all iovs
490for io,since in enumerate(iovList):
491
492 sinceRun = since[0]
493 sinceLum = since[1]
494
495 until=iovUntil[io]
496 untilRun = until[0]
497 untilLum = until[1]
498
499 log.info("")
500 log.info("Updating IOV [%d,%d] - [%d,%d)" , sinceRun, sinceLum, untilRun, untilLum)
501
502 blobR = reader.getDrawer(-1,chan,(sinceRun,sinceLum),False,False)
503 if blobR is None:
504 continue
505 mcell=blobR.getNChans()
506 mgain=blobR.getNGains()
507 mval=blobR.getObjSizeUint32()
508
509 log.info("input file: ncell: %d ngain %d nval %d" , max(icell), igain, ival)
510 log.info("input db: ncell: %d ngain %d nval %d" , mcell, mgain, mval)
511 if mcell>ncell:
512 ncell=mcell
513 if mgain>ngain:
514 ngain=mgain
515 if mval>nval:
516 nval=mval
517
518 log.info("output db: ncell: %d ngain %d nval %d" , ncell, ngain, nval)
519
520 if ncell>hashMgrA.getHashMax():
521 hashMgr=hashMgrABC
522 elif ncell>hashMgrBC.getHashMax():
523 hashMgr=hashMgrA
524 elif ncell>hashMgrDef.getHashMax():
525 hashMgr=hashMgrBC
526 else:
527 hashMgr=hashMgrDef
528 log.info("Using %s CellMgr with hashMax %d" , hashMgr.getGeometry(),hashMgr.getHashMax())
529
530 GainDefVec = cppyy.gbl.std.vector('float')()
531 for val in range(nval):
532 GainDefVec.push_back(0.0)
533 defVec = cppyy.gbl.std.vector('std::vector<float>')()
534 for gain in range(ngain):
535 defVec.push_back(GainDefVec)
536
537 #=== Initialize blob writer
538 writer = TileCalibCrest.TileBlobWriterCrest(outSchema,folderPath,'CaloFlt')
539 blobW = writer.getDrawer(-1,chan)
540 blobW.init(defVec,ncell,1)
541
542 src = ['Default','DB','File','Scale']
543 FullName=None
544 cell=None
545 gain=None
546 field=None
547 strval=None
548 noise=None
549
550 try:
551 for cell in range(ncell):
552 exist0 = (cell<mcell)
553 if tile:
554 (modName,cellName)=hashMgr.getNames(cell)
555 fullName="%s %6s" % (modName,cellName)
556 for gain in range(ngain):
557 exist1 = (exist0 and (gain<mgain))
558 if useNames:
559 if useGain:
560 gn=gain
561 else:
562 gn=-1
563 if useModuleNames:
564 dictKey = (modName+cellName,gn)
565 else:
566 dictKey = (cellName,gn)
567 else:
568 dictKey = (cell, gain)
569 noise = cellData.get(dictKey,[])
570 nF = len(noise)
571 for field in range(nval):
572 exist = (exist1 and (field<mval))
573 value = GainDefVec[field]
574 if field<nF:
575 strval=str(noise[field])
576 if strval.startswith("*"):
577 coef=float(strval[1:])
578 value = blobR.getData(cell,gain,field)*coef
579 elif strval.startswith("++") or strval.startswith("+-") :
580 coef=float(strval[1:])
581 value = blobR.getData(cell,gain,field)+coef
582 elif strval=="keep" or strval=="None":
583 value = None
584 else:
585 value = float(strval)
586 if (value is None or value<0) and exist: # negative value means that we don't want to update this field
587 value = blobR.getData(cell,gain,field)
588 elif exist:
589 exist = 2
590 elif exist:
591 value = blobR.getData(cell,gain,field)
592 if rescale:
593 if field==1 or field>4:
594 if 'spC' in cellName:
595 sc = scaleC10sp
596 elif 'spD' in cellName:
597 sc = scaleD4sp
598 elif 'C' in cellName and '10' in cellName:
599 sc = scaleC10
600 elif 'D' in cellName and '4' in cellName:
601 sc = scaleD4
602 elif 'E' in cellName:
603 sc = scaleE
604 elif 'D' in cellName:
605 sc = scaleD
606 elif 'B' in cellName:
607 sc = scaleB
608 elif 'A' in cellName:
609 sc = scaleA
610 else:
611 sc = scale
612 if sc>0.0:
613 exist = 3
614 value *= sc
615 src[exist] = "ScalePileUp %s" % str(sc)
616 elif field<4 and scaleElec>0.0:
617 exist = 3
618 value *= scaleElec
619 src[exist] = "ScaleElec %s" % str(scaleElec)
620
621 blobW.setData( cell, gain, field, value )
622 if rescale or exist>1:
623 print ("%s hash %4d gain %d field %d value %f Source %s" % (fullName, cell, gain, field, value, src[exist]))
624 except Exception as e:
625 log.warning("Exception on IOV [%d,%d]-[%d,%d)" , sinceRun, sinceLum, untilRun, untilLum)
626 print (FullName,"Cell",cell,"gain",gain,"field",field,"value",strval,"noise vector",noise)
627 #e = sys.exc_info()[0]
628 print (e)
629
630 author = "<no comment found>"
631 if Comment:
632 author = user
633 comm = Comment
634 elif comment == "keep":
635 author = reader.getComment(since,True)
636 comm = ""
637 if author == "<no comment found>":
638 author = user
639 if comment and comment!="keep":
640 comm = comment
641 else:
642 if sinceLum!=0:
643 comm = "Update for run,lumi %i,%i from file %s" % (sinceRun,sinceLum,txtFile)
644 else:
645 comm = "Update for run %i from file %s" % (sinceRun,txtFile)
646 comm1 = reader.getComment(since)
647 if comm1 and comm1 != "<no comment found>" and iov:
648 comm += " // " + comm1
649 writer.setComment(author,comm)
650 writer.register((sinceRun,sinceLum), outTag, chan)
651
652log.info("Using %s CellMgr with hashMax %d" , hashMgr.getGeometry(),hashMgr.getHashMax())
void print(char *figname, TCanvas *c1)
#define max(a, b)
Definition cfImp.cxx:41
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177