5 import os, sys, errno, glob, subprocess, pathlib, getpass, datetime
12 folderInfo[
"/LAR/ElecCalibOflSC/OFC/PhysWave/RTM/4samples1phase"] = {
"key":
"LArOFC",
"classtype":
"LArOFCComplete"}
13 folderInfo[
"/LAR/ElecCalibOflSC/OFC/CaliWave1phase"] = {
"key":
"LArOFC",
"classtype":
"LArOFCComplete"}
14 folderInfo[
"/LAR/ElecCalibOflSC/Shape/RTM/4samples1phase"] = {
"key":
"LArShape",
"classtype":
"LArShapeComplete"}
15 folderInfo[
"/LAR/ElecCalibOflSC/Pedestals/Pedestal"] = {
"key":
"LArPedestal",
"classtype":
"LArPedestalComplete"}
16 folderInfo[
"/LAR/ElecCalibOflSC/Ramps/RampLinea"] = {
"key":
"LArRamp",
"classtype":
"LArRampComplete"}
17 folderInfo[
"/LAR/ElecCalibOflSC/MphysOverMcal/RTM"] = {
"key":
"LArMphysOverMcal",
"classtype":
"LArMphysOverMcalComplete"}
20 if "Athena_DIR" not in os.environ:
21 print(
"It looks like Athena is not set up... this script will not work without it.")
23 print(
"setupATLAS; asetup Athena,24.0.54; source /eos/project-a/atlas-larcalib/public/build/x86_64-el9-gcc13-opt/setup.sh")
27 from PyCool
import cool,coral
31 dbSvc=cool.DatabaseSvcFactory.databaseService()
34 db=dbSvc.openDatabase(dbstring)
35 except Exception
as e:
36 print(f
"Problem opening database {e}")
38 print(f
"Opened database {dbstring}")
40 folderlist= [
str(s)
for s
in db.listAllNodes()]
44 folderlist = [f
for f
in folderlist
if f.count(
"/") >= 3]
61 self.
file.writelines(string +
'\n')
71 print(
"mkdir "+path )
73 except OSError
as exception:
74 if exception.errno != errno.EEXIST:
79 dqmsite =
"atlasdqm.cern.ch"
80 dqmpassfile =
"/afs/cern.ch/user/l/larmon/public/atlasdqmpass.txt"
81 if not os.path.isfile(dqmpassfile):
85 with open(dqmpassfile,
"r")
as f:
86 dqmpass = f.readlines()[0].strip()
87 if ":" not in dqmpass:
88 print(
"Problem reading dqmpass")
93 print(
"Failed to connect to atlasdqm, therefore giving a fake run number 555555")
95 if dqmapi
is not None:
96 return dqmapi.get_latest_run()
106 self.
name = pathlib.Path(logpath).stem
110 for line
in self.
lines:
111 if not line.startswith(
"Run "):
continue
112 runs.append(
int(line.split(
"Run")[1].
split(
":")[0]))
116 for line
in self.
lines:
117 if not line.startswith(
"Run "):
continue
118 line = line.strip(
"\n")
120 return "\n".
join(toprint)
123 for run
in self.
runs:
124 self.
infiles = glob.glob(f
"{topdir}/*{run}*/root_files/*{run}*")
132 indbs = [ g
for pd
in self.
topdirs for g
in glob.glob(f
"{pd}/*/mysql.db") ]
138 indbs = [ g
for pd
in self.
topdirs for g
in glob.glob(f
"{pd}/*/SnapshotBadChannel.db") ]
145 if isinstance(vals, list):
146 vals =
",".
join(vals)
151 print(
"**** RUNNING THE FOLLOWING COMMAND ****")
153 print(
"***************************************")
155 process = subprocess.Popen(cmd, shell=
True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
156 out,err = process.communicate()
157 retcode = process.returncode
158 print(
"**** Return code:", retcode,
"*"*10)
160 if outlogpath
is not None:
161 print(f
"See log: {outlogpath}")
162 log =
cfile(outlogpath)
163 log.wl(
"~~~~~~~~ OUTPUT ~~~~~~~~")
164 log.wl(out.decode(
'ascii'))
165 log.wl(
"~~~~~~~~~~~~~~~~~~~~~~~~")
166 log.wl(
"~~~~~~~~ ERROR ~~~~~~~~")
167 log.wl(err.decode(
'ascii'))
168 log.wl(
"~~~~~~~~~~~~~~~~~~~~~~~~")
170 print(
"~~~~~~~~ OUTPUT ~~~~~~~~")
171 print(out.decode(
'ascii'))
172 print(
"~~~~~~~~~~~~~~~~~~~~~~~~")
173 print(
"~~~~~~~~ ERROR ~~~~~~~~")
174 print(err.decode(
'ascii'))
175 print(
"~~~~~~~~~~~~~~~~~~~~~~~~")
177 print(
"!!!!!!!! DID NOT TERMINATE SUCCESSFULLY... exiting")
180 def run_merge(insqlite, inkeys, outsqlite, outpool, Ncoll=0, poolcat="mergedPoolCat.xml", outlogpath=None, runNow=True):
181 ''' Step 1 of the merging. '''
184 cmd = f
"python -m LArCalibProcessing.LArNewCalib_MergeDB --insqlite {insqlite} --inkeys {inkeys} --outsqlite {outsqlite} --poolfile {outpool} --isSC --poolcat {poolcat} --Ncoll {Ncoll}"
187 def run_fillofcphase(phases_txt, outkey="LArSCOFCPhase", default_phase=22, folder="/LAR/ElecCalibOflSC/OFCBin/PhysShift", tag="LARElecCalibOflSCOFCBinPhysShift-10", outsql="SCOFCPhase.db", outpool="SC_OFC_Phase_10.pool.root", poolcat="mergedPoolCat.xml", outlogpath=None, runNow=True):
188 ''' Step 2 *if needed* - make an sql file from picked OFC phase txt file '''
189 cmd = f
"LArNewCalib_FillOFCPhase.py --infile {phases_txt} --outkey {outkey} --isSC --hasid --default {default_phase} --folder {folder} --tag {tag} --outsql {outsql} --outp {outpool} --poolcat {poolcat}"
193 def run_ofcpick(insqlite, outsqlite, phase_sql, run, BCsnapshotDB, outpdir="./", outrdir="./", outname="Picked_phase24052024", tag="LARElecCalibOflSCOFCBinPhysShift-10", Ncoll=0, poolcat="mergedPoolCat.xml", isPhys=True, outlogpath=None, runNow=True):
194 ''' Step 3, picking the phase in the DB '''
195 cmd=f
"LArNewCalib_PhysOFCPhasePicker.py --run {run} -b {BCsnapshotDB} --insqlite {insqlite} --poolcat {poolcat} --outsqlite {outsqlite} --isSC --outpdir {outpdir} --outrdir {outrdir} --subdet {outname} --ofcphasetag {tag} --ofcphasesqlite {phase_sql} --Ncoll {Ncoll}"
197 cmd +=
" --isCalib --outprefix LArOFCCaliOnePhase"
202 def run_toCoolInline(mergedDB, outDB, infolders="ConvertToInlineSC", globalTag="LARCALIB-RUN2-00", poolcat="mergedPoolCat.xml", outlogpath=None, runNow=True):
203 ''' Step 4: flattening the DB '''
205 cmd=f
"/afs/cern.ch/user/l/larcalib/LArDBTools/python/BuildTagHierarchy.py {mergedDB} {globalTag}"
207 cmd=f
"LArCalib_ToCoolInlineConfig.py --insqlite {mergedDB} --infolders {infolders} --poolcat {poolcat} --outsqlite {outDB} --isSC"
212 print(f
"** Adding pool files from {poolDir} with pool_insertFileToCatalog **")
213 for f
in [os.path.join(poolDir, f)
for f
in os.listdir(poolDir)
if f.endswith(
".pool.root")]:
214 cmd1 =
"pool_extractFileIdentifier "+f
215 process = subprocess.Popen(cmd1,shell=
True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
216 out,err = process.communicate()
217 retcode = process.returncode
218 ident=out.decode(
'ascii').
split(
" ")[0]
219 cmd=f
"pool_insertFileToCatalog.py {f}"
220 if catalog
is not None:
221 cmd += f
" --catalog='xmlcatalog_file:{catalog}'"
222 print(f
"---- {cmd} ({ident})")
224 process = subprocess.Popen(cmd,shell=
True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
225 out,err = process.communicate()
226 retcode = process.returncode
228 print(err.decode(
'ascii'))
233 dbstring=f
"sqlite://;schema={sql};dbname={dbname}"
234 folderlist, db =
getFolderList(dbstring, retdb=
True, cleanlist=
True)
238 myfolder=db.getFolder(f)
240 if verbose:
print(
"*"*20)
241 if verbose:
print(f
"Reading folder {f}")
242 if verbose:
print(
"*"*20)
243 if verbose:
print(
"Checking tags...")
244 taglist=myfolder.listTags()
245 if verbose:
print( f
"{len(taglist)} Tags in folder:" )
247 for i
in taglist:
print( i )
250 taglist = [
str(t)
for t
in taglist ]
252 posstag = [ t
for t
in taglist
if mustr
in t ]
254 posstag = [ t
for t
in taglist
if "mu-" not in t ]
255 if len(posstag) == 1:
258 if verbose:
print(len(posstag),
"Choosing first tag")
260 if verbose:
print(f
"Will use tag {thetag}")
263 except Exception
as e:
267 if __name__ ==
"__main__":
268 parser = argparse.ArgumentParser()
270 parser.add_argument(
'inputLog', type=str, help=
'Name of input log file which lists the runs' )
271 parser.add_argument(
'-logDir', type=str, dest=
'logDir', default=
"/afs/cern.ch/user/l/lardaq/public/hfec-calibration-logs", help=
"Input path for log files. Default %(default)s." )
272 parser.add_argument(
'-inDir',
'-i', type=str, default=
'/eos/project-a/atlas-larcalib/AP', help=
"Input directory containing root files from the processing. Default %(default)s.")
273 parser.add_argument(
'-r',
'-run', dest=
'run', type=int, default=
get_latest_run(), help=
'Run number - used for bad channels. Default is latest run.')
275 parser.add_argument(
'--folders', dest=
"folders", nargs=
'+', default=[
"Pedestal",
"MphysOverMcal",
"Ramp",
"AutoCorr",
"OFCCali",
"LArOFCPhys4samples",
"LArOFCPhys4samplesMu",
"PhysWave",
"PhysAutoCorr",
"CaliPulseParams",
"DetCellParams",
"CaliWave",
"LArShape4samples"], help=
"List of folders to merge in a separate db 'mergeSC.db'. Default %(default)s.")
276 parser.add_argument(
'-o',
'--outdir', dest=
'outdir', default=f
'/tmp/{getpass.getuser()}', help=
"Output directory for running and producing merged files. Default %(default)s.")
277 parser.add_argument(
'-Ncoll', dest=
'Ncoll', type=int, default=0, help=
"Pileup setting. Default %(default)s.")
278 parser.add_argument(
'-phase_txt', dest=
"phase_txt", type=str, default=
None, help=
"Full path to .txt file which contains picked phases. Provide either this or a .db version")
279 parser.add_argument(
'-phase_db', dest=
"phase_db", type=str, default=
None, help=
"Full path to .db file which contains picked phases. Provide either this or a .txt version")
280 parser.add_argument(
'-t',
'--tag', dest=
"out_tag", type=str, default=
None, help=
"A tag to add to the name of output files, to help keep track of what was used. e.g. could use 'Onl' or 'Ofl' to separate blobs for different uploads. Default is empty, but the current date will be added.")
281 parser.add_argument(
'-d',
'--dryRun', dest=
'dryRun', action=
'store_true', help=
"Perform a dry run? This will print the commands to terminal without running them")
282 args = parser.parse_args()
284 runNow =
not args.dryRun
286 outtag = f
"mu{args.Ncoll}_{datetime.datetime.now().strftime('%y%m%d')}"
287 if args.out_tag
is not None:
288 outtag = f
"{args.out_tag}_{outtag}"
291 if not args.inputLog.endswith(
".log"):
292 args.inputLog +=
".log"
294 logPath = f
"{args.logDir}/{args.inputLog}"
296 if not os.path.isfile(logPath):
297 print(f
"Couldn't find file {logPath}")
301 if args.phase_txt
is None and args.phase_db
is None:
302 print(
"NO PICKED PHASE FILE PROVIDED!! Please supply either a .txt (-phase_txt) or .db (-phase_db) file so that the phases can be picked for the OFCs")
303 print(
"** This means we will skip the picking part... therefore the single-phase OFC folders **")
305 if args.phase_txt
is not None and args.phase_db
is not None:
306 print(
"BOTH .txt AND .db PICKED PHASE FILES WERE PROVIDED. Please only provide one, so there is no ambiguity")
309 for f
in [
"phase_txt",
"phase_db" ]:
310 if getattr(args,f)
is not None:
311 if not os.path.isfile(getattr(args,f)):
312 print(f
"PROVIDED {f} DOES NOT EXIST!! Please check the path")
319 theLog.getTopDirs(args.inDir)
320 insqlite = theLog.sqldbs
321 bcsnapshots = theLog.bcsnapshots
324 args.outdir = f
"{args.outdir}/{theLog.name}"
325 args.outdir += f
"_{outtag}"
326 outdir_root = f
"{args.outdir}/rootFiles"
327 outdir_pool = f
"{args.outdir}/poolFiles"
328 outdir_logs = f
"{args.outdir}/logs"
329 print(f
"Output (including root and pool files) will go to {args.outdir}")
335 mergedDB = f
"{outdir_pool}/mergeSC_{outtag}.db"
336 mergedPool = f
"{outdir_pool}/merged_SC_{outtag}.pool.root"
337 finalDB_flat = f
"{outdir_pool}/freshConstants_1.5_{outtag}.db"
338 poolcat = f
"{outdir_pool}/mergedPoolCat.xml"
339 phase_pool = f
"{outdir_pool}/SC_OFC_Phase_10_{outtag}.pool.root"
341 for pd
in theLog.pooldirs:
346 run_merge(insqlite=insqlite, inkeys=args.folders, outsqlite=mergedDB, outpool=mergedPool, Ncoll=args.Ncoll, poolcat=poolcat, outlogpath=f
"{outdir_logs}/run_merge_nopick.txt", runNow=runNow)
349 phaseDBname = f
"SCOFCPhase_{outtag}.db"
350 if args.phase_txt
is not None:
352 args.phase_db = f
"{args.outdir}/{phaseDBname}"
353 run_fillofcphase(phases_txt=args.phase_txt, outkey=
"LArSCOFCPhase", default_phase=22, folder=
"/LAR/ElecCalibOflSC/OFCBin/PhysShift", tag=
"LARElecCalibOflSCOFCBinPhysShift-10", outsql=args.phase_db, outpool=phase_pool, outlogpath=f
"{outdir_logs}/run_fillofcphase.txt", runNow=runNow, poolcat=poolcat)
358 run_ofcpick(insqlite=mergedDB, outsqlite=mergedDB, phase_sql=args.phase_db, run=args.run, BCsnapshotDB=bcsnapshots[0], outpdir=outdir_pool, outrdir=outdir_root, outname=f
"Picked_phase_{outtag}", tag=
"LARElecCalibOflSCOFCBinPhysShift-10", Ncoll=args.Ncoll, poolcat=poolcat, outlogpath=f
"{outdir_logs}/run_ofcpick.txt", runNow=runNow, isPhys=
True)
360 run_ofcpick(insqlite=mergedDB, outsqlite=mergedDB, phase_sql=args.phase_db, run=args.run, BCsnapshotDB=bcsnapshots[0], outpdir=outdir_pool, outrdir=outdir_root, outname=f
"Picked_phase_{outtag}", tag=
"LARElecCalibOflSCOFCBinPhysShift-10", Ncoll=args.Ncoll, poolcat=poolcat, outlogpath=f
"{outdir_logs}/run_ofccalipick.txt", runNow=runNow, isPhys=
False)
363 print(
"**** NOTE: NO OFC PICKING WAS DONE, DUE TO LACK OF PICKING INPUT ****")
368 foldersTags =
folderNamesTags(mergedDB, mustr=f
"mu-{args.Ncoll}", verbose=
True)
371 print(
"Folders and tags to be used for flattening:")
372 for k
in foldersTags.keys():
373 print(k,
":", foldersTags[k])
376 folderScript = f
"{args.outdir}/ConvertToInlineSC"
378 print(f
"Writing folder info to {folderScript}.py")
379 with open(f
"{folderScript}.py",
"w")
as ffile:
380 lines = [
"inputFolders=[]"]
381 for f
in foldersTags.keys():
382 if f
in folderInfo.keys():
384 theTag = foldersTags[f]
385 theKey = folderInfo[f][
"key"]
386 theClassType = folderInfo[f][
"classtype"]
388 theline = f
'inputFolders.append(("{theFolder}","{theTag}","{theKey}","{theClassType}"))'
389 lines.append(theline)
392 print(f
"NOT SURE HOW TO FLATTEN {f}, so will skip it")
394 ffile.write(
"\n".
join(lines))
398 run_toCoolInline(mergedDB=mergedDB, infolders=folderScript, outDB=finalDB_flat, globalTag=
"LARCALIB-RUN2-00", poolcat=poolcat, outlogpath=f
"{outdir_logs}/run_toCoolInline.txt", runNow=runNow)