13 def log(log_type="",text=""):
22 v =
int(sys.version_info[0])
23 source =
"mkLumiAveragedPlots: " 27 print(source,
"[INFO] ",text)
31 print(source,
"[WARNING] ",text)
33 print(source,
"[ERROR] ",text)
35 print(source,
"[FATAL] ",text)
48 return line.strip(
'\n').
split(
" ")[index]
50 return line.strip(
'\r\n').
replace(
"\t",
" ").
split(
" ")[index]
58 for lumifile
in lumiPerRun:
59 f = open(lumifile,
"r") for line
in f:
67 for lumifile
in lumiPerRun:
68 f = open(lumifile,
"r") 77 for lumifile
in lumiPerIoV:
78 f = open(lumifile,
"r") 82 if int(first) == start_run:
86 if str(first) ==
str(start_run):
93 log(
"w",
"Lumi per IoV: "+
str(start_run)+
" not found.")
105 for lumifile
in lumiPerRun:
106 f = open(lumifile,
"r") for line
in f:
113 log(
"w",
"Lumi per run: "+
str(run)+
" not found.")
117 def getTuples(inputDir, filterNumbers=[]):
127 for dirpath,dirs,files
in os.walk(inputDir):
128 if len(dirs) == 0: dirs = [
""]
130 if len(filterNumbers)!=0
and (n_dir
not in filterNumbers
or not isNumber(n_dir)):
continue 140 _number = os.path.join(dirpath,
"OfflineValidationSummary.root")
141 if os.path.isfile(os.path.join(dirpath,n_dir+
"OfflineValidationSummary.root")):
142 test_root = ROOT.TFile(os.path.join(dirpath,n_dir+
"OfflineValidationSummary.root"),
"READ")
143 if test_root.IsZombie():
144 log(
"w",os.path.join(dirpath,n_dir+
"OfflineValidationSummary.root")+
" is ZOMBIE!")
145 tuples.append({
'file' :
"invalid.root",
151 tuples.append({
'file' : os.path.join(dirpath,n_dir+
"OfflineValidationSummary.root"),
157 log(
"w",os.path.join(dirpath,n_dir+
"OfflineValidationSummary.root")+
" NOT found! Directory is empty?")
158 tuples.append({
'file' :
"invalid.root",
162 if (valid_files < 2
and config[
'mode'] !=
"finalize")
or (valid_files < 1
and config[
'mode'] ==
"finalize"):
163 log(
"f",
"Check input directory. Less than two valid files to merge recognized.")
167 for dirpath,dirs,files
in os.walk(inputDir):
169 if "PVValidation" in n_file:
170 if isNumber((n_file.split(
"_")[-1]).
split(
".")[0])
and os.path.isfile(os.path.join(dirpath,n_file)):
171 tuples.append({
'file' : os.path.join(dirpath,n_file),
172 'number' :
int((n_file.split(
"_")[-1]).
split(
".")[0]),
176 log(
"f",
"Format for run by run PV results NOT recognised!")
180 if config[
'mode'] !=
"finalize":
181 tuples.sort(key=
lambda tuple: tuple[
'number'])
182 if len(lumiPerRun)!=0:
185 for ituple,tuple
in enumerate(tuples):
186 if ituple != len(tuples)-1
or len(config[
'validation'][
'firstFromNext']) != 0:
187 if int(tuple[
'lumi']) != 11111:
188 if ituple == len(tuples)-1:
189 tuple[
'lumi'] +=
getLumiPerIoV(tuples[ituple][
'number'],
int(config[
'validation'][
'firstFromNext'][0]))
191 tuple[
'lumi'] +=
getLumiPerIoV(tuples[ituple][
'number'],tuples[ituple+1][
'number'])
194 while _ituple > 0
and int(tuples[_ituple-1][
'lumi'])
in [11111,11112]:
197 if ituple == len(tuples)-1:
198 dLumi =
getLumiPerIoV(tuples[ituple][
'number'],
int(config[
'validation'][
'firstFromNext'][0]))
200 dLumi =
getLumiPerIoV(tuples[ituple][
'number'],tuples[ituple+1][
'number'])
201 if int(dLumi)
not in [11111,11112]:
202 tuples[_ituple-1][
'lumi'] += dLumi
205 log(
"w",
"Effectively adding luminosity of IoV: "+
str(tuples[ituple][
'number'])+
"(missing file with "+
str(dLumi)+
") to IoV: "+
str(tuples[_ituple-1][
'number']))
208 while __ituple < len(tuples)-1
and int(tuples[__ituple+1][
'lumi'])
in [11111,11112]:
210 if __ituple != len(tuples)-1:
211 dLumi =
getLumiPerIoV(tuples[ituple][
'number'],tuples[ituple+1][
'number'])
212 if int(dLumi)
not in [11111,11112]:
213 tuples[__ituple+1][
'lumi'] += dLumi
216 log(
"w",
"Effectively adding luminosity of IoV: "+
str(tuples[ituple][
'number'])+
"(missing file with "+
str(dLumi)+
") to IoV: "+
str(tuples[__ituple+1][
'number']))
219 log(
"i",
"User requested to skip IoV: "+
str(tuples[ituple][
'number']))
221 if int(tuple[
'lumi']) != 11111:
225 while _ituple > 0
and int(tuples[_ituple-1][
'lumi'])
in [11111,11112]:
229 if int(dLumi)
not in [11111,11112]:
230 tuples[_ituple-1][
'lumi'] += dLumi
233 log(
"w",
"Effectively adding luminosity of IoV: "+
str(tuples[ituple][
'number'])+
"(missing file with "+
str(dLumi)+
") to IoV: "+
str(tuples[_ituple-1][
'number']))
235 log(
"w",
"No more IOVs in the list to add luminosity from missing IOV"+
str(tuples[ituple][
'number'])+
".")
238 valid_tuples = [ tuple
for ituple,tuple
in enumerate(tuples)
if int(tuple[
'lumi'])
not in [11111,11112]
and ituple != len(tuples)-1 ]
240 valid_tuples = [ tuple
for tuple
in tuples
if int(tuple[
'lumi'])
not in [11111,11112] ]
241 tuples = valid_tuples
244 for ituple,tuple
in enumerate(tuples):
247 elif len(lumiPerIoV)!=0
and isDMR:
250 for ituple,tuple
in enumerate(tuples):
251 if tuple[
'lumi'] != 11111:
253 valid_tuples.append(tuple)
254 tuples = valid_tuples
268 for dirpath,dirs,files
in os.walk(inputDir):
270 if "PVValidation" in file:
271 if len(file.split(
"_")) == 3:
272 period = file.split(
"_")[1]
273 if period
not in tuples:
275 tuples[period].
append({
'file' : os.path.join(dirpath,file),
279 tuples[period].
append({
'file' : os.path.join(dirpath,file),
282 elif len(file.split(
"_")) == 2:
283 if ".root" in file.split(
"_")[1]:
284 period = file.split(
"_")[1].
replace(
".root",
"")
285 if period
not in tuples:
287 tuples[period].
append({
'file' : os.path.join(dirpath,file),
291 tuples[period].
append({
'file' : os.path.join(dirpath,file),
295 log(
"e",
"No extension found for PV MC input files.")
298 log(
"w",
"Incorrect format for <period> tag inside PV MC input-file names. Char \"_\" is not allowed inside tag.")
300 inputFile = os.path.join(inputDir,
"OfflineValidationSummary.root")
301 period = (inputDir.split(
"/")[-2])
303 if os.path.isfile(inputFile):
304 tuples[period].
append({
'file' : inputFile,
307 tuples[period].
append({
'file' :
"invalid.root",
326 for ituple,tuple
in enumerate(tuples):
327 if str(tuple[
'lumi'])
not in [
'11111',
'11112']:
328 if tuple[
'lumi']/intLumi > -1.:
329 fileArgument += tuple[
'file']+
" " 330 weightArgument +=
str(
format(tuple[
'lumi']/intLumi,
'.20f'))+
" " 332 countTest += tuple[
'lumi']/intLumi
334 log(
"i",
"Not including IOV "+
str(tuple[
'number'])+
" for weighting: "+
str(tuple[
'lumi']))
337 log(
"w",
"Normalization factor: "+
str(
format(countTest,
'.20f'))+
" is less than 1.")
338 if len(weightArgument.split(
" ")) != len(fileArgument.split(
" ")):
339 log(
"e",
"There is "+
str(len(fileArgument.split(
" ")))+
"rootfiles but "+
str(len(weightArgument.split(
" ")))+
" weights.")
341 log(
"i",
"Real number of files to merge is: "+
str(len(fileArgument.split(
" "))-1))
348 cmd = haddwsDir+
"haddws "+fileArgument+weightArgument+
" > haddws.out 2> haddws.err" 349 log(
"i",
"Running haddws.C")
355 if objName !=
"" and not objName.startswith(
"_"): objName =
"_"+objName
356 outFileName = os.path.join(config[
'output'],
"OfflineValidationSummary"+objName+
".root")
358 outFileName = os.path.join(config[
'output'],
"result"+objName+
".root")
359 if os.path.isfile(
"./result.root"):
360 os.system(
"mv result.root "+outFileName)
369 if tuple[
'lumi']
not in [11111,11112]:
370 intLumi += tuple[
'lumi']
375 parser = argparse.ArgumentParser(description =
"run the python plots for the AllInOneTool validations", formatter_class=argparse.RawTextHelpFormatter)
376 parser.add_argument(
"config", metavar=
'config', type=str, action=
"store", help=
"Averager AllInOneTool config (json/yaml format)")
377 parser.add_argument(
"-b",
"--batch", action =
"store_true", help =
"Batch mode")
381 return parser.parse_args()
383 if __name__ ==
'__main__':
393 with open(args.config,
"r") as configFile: if args.config.split(
".")[-1] ==
"json":
394 config = json.load(configFile)
395 elif args.config.split(
".")[-1] ==
"yaml":
396 config = yaml.load(configFile, Loader=yaml.Loader)
398 raise Exception(
"Unknown config extension '{}'. Please use json/yaml format!".
format(args.config.split(
".")[-1]))
400 log(
' ----- All-in-one Averager -----')
401 log(
' type: '+config[
'type'])
402 log(
' mode: '+config[
'mode'])
403 log(
' isData: '+
str(config[
'isData']))
404 log(
' isMC: '+
str(
not config[
'isData']))
405 if config[
'mode'] ==
"finalize":
406 nFiles = len(config[
'validation'][
'mergeFile'])
407 elif config[
'mode'] ==
"plot":
408 nFiles = len(config[
'plot'][
'inputData'])+len(config[
'plot'][
'inputMC'])
410 nFiles = len(config[
'validation'][
'IOV'])
411 log(
' nFiles: '+
str(nFiles))
412 log(
' -------------------------------')
421 if config[
'mode'] ==
"merge":
424 if len(config[
'validation'][
'IOV']) == 0:
425 log(
"f",
"No input DATA found. List of IOVs needs to contain at least one number.")
427 elif len(config[
'validation'][
'IOV']) != 0:
428 _dir = config[
'validation'][
'mergeFile'].
replace(
"{}",
"")
429 if os.path.isdir(_dir):
430 log(
"i",
"Will average "+
str(len(config[
'validation'][
'IOV']))+
" DATA files from directory(ies): ")
432 subDirMissing =
False 433 for IOV
in config[
'validation'][
'IOV']:
434 IOVs.append(
str(IOV))
435 if not os.path.isdir(config[
'validation'][
'mergeFile'].
replace(
"{}",
str(IOV))):
436 log(
"f",
"Subdir not found "+
str(IOV)+
"!")
441 inputDirData.append(_dir)
443 elif not config[
'isData']:
444 if len(config[
'validation'][
'IOV']) != 1 \
445 or (len(config[
'validation'][
'IOV']) == 1
and str(config[
'validation'][
'IOV'][0]) !=
"1"):
446 log(
"f",
"MC validation configuration error: IOV!=1")
449 IOVs.append(
str(config[
'validation'][
'IOV'][0]))
450 if len(config[
'validation'][
'mergeFile']) == 0:
451 log(
"f",
"No input MC found.")
454 log(
"i",
"Will scale and merge "+
str(len(config[
'validation'][
'mergeFile']))+
" MC directory(ies): ")
455 for _dir
in config[
'validation'][
'mergeFile']:
456 basedir = _dir.replace(
"{}",
"")
457 subdir = _dir.replace(
"{}",
str(config[
'validation'][
'IOV'][0]))
458 if os.path.isdir(basedir)
and os.path.isdir(subdir):
460 inputDirMC.append(subdir)
462 log(
"f",
"Directory not found "+subdir)
464 elif config[
'mode'] ==
"finalize":
467 if len(config[
'validation'][
'mergeFile']) == 0:
468 log(
"f",
"No files found to finalize.")
470 log(
"i",
"Will finalize average job for "+
str(len(config[
'validation'][
'mergeFile']))+
" parts:")
471 for partFile
in config[
'validation'][
'mergeFile']:
472 if os.path.isdir(partFile):
473 inputDirData.append(partFile)
474 log(
"i",
"---> "+partFile)
475 else:
log(
"w",
"Missing partial input: "+partFile)
476 if len(inputDirData) != len(config[
'validation'][
'mergeFile']):
477 log(
"e",
"Some input was not found for DATA finalization job.")
480 elif not config[
'isData']:
481 log(
"f",
"Nothing to finalize for MC.")
483 elif config[
'mode'] ==
"plot":
484 if len(config[
'plot'][
'inputData'])+len(config[
'plot'][
'inputMC']) == 0:
485 log(
"f",
"No files found for plotting!")
487 log(
"i",
"Will attempt to plot objects from "+
str(nFiles)+
" source files.")
488 for inputDir
in config[
'plot'][
'inputData']:
489 if os.path.isdir(inputDir):
490 inputDirData.append(inputDir)
491 for inputDir
in config[
'plot'][
'inputMC']:
492 if os.path.isdir(inputDir):
493 inputDirMC.append(inputDir)
499 isPV = (config[
'type'] ==
"PV")
500 isDMR = (config[
'type'] ==
"DMR")
501 if config[
'mode'] !=
"plot":
502 lumiPerRun = config[
'validation'][
'lumiPerRun']
503 lumiPerIoV = config[
'validation'][
'lumiPerIoV']
504 lumiMC = config[
'validation'][
'lumiMC']
509 if config[
'mode'] !=
"plot":
510 if isPV
and len(lumiPerIoV)!=0:
511 log(
"w",
"Are you sure you have run PV validation in IoV by IoV mode?")
512 if (isPV
or isDMR)
and len(lumiPerRun)==0
and len(lumiPerIoV)==0
and len(inputDirData) != 0:
513 log(
"e",
"Use option 'lumiPerRun' or 'lumiPerIoV' to specify luminosity files.")
515 if (isPV
or isDMR)
and len(lumiPerIoV)==0:
516 if len(lumiPerRun) != 0:
517 if config[
'mode'] ==
"finalize":
518 log(
"i",
"Integrated Luminosity per intermediate files found.")
520 log(
"w",
"Lumi per run list will be processed to get Lumi per IoV list (applies for DATA).")
521 elif len(inputDirMC) != 0
and len(inputDirData) == 0:
522 log(
"i",
"MC will be scaled per period to given integrated luminosity.")
523 if len(inputDirMC) != 0
and len(lumiMC) == 0:
524 log(
"w",
"MC object(s) found on input but lumi per period not specified.")
526 for formatLumi
in lumiMC:
527 if "::" in formatLumi:
529 float(formatLumi.split(
"::")[-1])
531 log(
"e",
"Wrong lumi per period for MC formatting. USAGE: <object>::<merge>::<lumi> or <merge>::<lumi> for single MC object (alignment).")
533 if len(formatLumi.split(
"::")) == 2:
534 _lumiMC[formatLumi.split(
"::")[0]] = {
'lumi' :
float(formatLumi.split(
"::")[-1]),
'group' : 0}
535 elif len(formatLumi.split(
"::")) == 3:
536 _lumiMC[formatLumi.split(
"::")[1]] = {
'lumi' :
float(formatLumi.split(
"::")[-1]),
'group' : formatLumi.split(
"::")[0]}
538 log(
"e",
"Wrong lumi per period for MC formatting. USAGE: <object>::<merge>::<lumi> or <merge>::<lumi> for single MC object (alignment).")
542 if isDMR
and config[
'isData']:
543 if len(config[
'validation'][
'firstFromNext']) == 0: skipLast =
True 548 if config[
'mode'] ==
"plot":
549 if len(config[
'plot'][
'colors']) < len(config[
'plot'][
'objects']):
550 log(
"e",
"Please specify color code for each object.")
552 if len(config[
'plot'][
'styles']) < len(config[
'plot'][
'objects']):
553 log(
"e",
"Please specify line style for each object.")
555 if len(config[
'plot'][
'objects']) != 0:
556 for obj
in config[
'plot'][
'objects']:
557 if len(obj.split(
" ")) != 1:
558 log(
"e",
"No space in object name is allowed. Use \"_\" instead.")
560 if len(config[
'plot'][
'objects']) != 0
and len(config[
'plot'][
'labels']) == 0:
561 log(
"i",
"Object labels will be generated automatically.")
562 if 'plotGlobal' not in config.keys():
563 log(
"w",
"Global plotting settings not found. Fallback to default.")
564 config[
'plotGlobal'] = {}
569 if config[
'mode'] ==
"plot":
570 if config[
'plot'][
'showMeanError']
and not config[
'plot'][
'showMean']:
571 log(
"w",
"Cannot show mean error without showing mean.")
572 config[
'plot'][
'showMeanError'] =
False 573 if config[
'plot'][
'showRMSError']
and not config[
'plot'][
'showRMS']:
574 log(
"w",
"Cannot show RMS error without showing RMS.")
575 config[
'plot'][
'showRMSError'] =
False 576 if config[
'plot'][
'useFitError']
and not config[
'plot'][
'useFit']:
577 log(
"w",
"Cannot show fit parameters error without fitting.")
578 config[
'plot'][
'useFitError'] =
False 584 if isDMR: whichValidation =
"DMR" 585 elif isPV: whichValidation =
"PV" 592 if config[
'mode'] ==
"merge":
593 for inputDir
in inputDirData:
601 log(
"e",
"Zero "+whichValidation+
" files to merge detected.")
603 log(
"i",
"Attempting to average "+
str(len(tuples))+
" "+whichValidation+
" files with (partial) integrated luminosity "+
str(intLumi)+
".")
607 outFileName = os.path.join(config[
'output'],
"OfflineValidationSummary"+objName+
".root")
609 objName = inputDir.split(
"/")[-1]
610 outFileName = os.path.join(config[
'output'],
"result"+objName+
".root")
611 tuples_total.append({
'file' : outFileName,
615 elif config[
'mode'] ==
"finalize":
618 for inputDir
in inputDirData:
627 log(
"e",
"Zero final "+whichValidation+
" files to merge detected.")
629 log(
"i",
"Attempting to average final "+
str(len(tuples))+
" "+whichValidation+
" files with overall integrated luminosity "+
str(intLumi)+
".")
636 if config[
'mode'] ==
"merge":
637 with open(os.path.join(config[
'output'],
'lumiPerFile.csv'),
'a')
as csvfile:
638 csvwriter = csv.writer(csvfile, delimiter=
' ')
639 for tuple
in tuples_total:
640 csvwriter.writerow([tuple[
'file'],
str(tuple[
'lumi'])])
647 if config[
'mode'] ==
"merge":
648 for inputDir
in inputDirMC:
650 for period, _list
in tuples.items():
652 if period
in lumiMC.keys():
653 tuple[
'lumi'] = lumiMC[period][
'lumi']
654 log(
"i",
"Group N."+
str(lumiMC[period][
'group'])+
" <-- "+
str(tuple[
'lumi']))
655 if lumiMC[period][
'group']
not in tupleGroupsMC.keys():
656 tupleGroupsMC[lumiMC[period][
'group']] = []
657 tupleGroupsMC[lumiMC[period][
'group']].
append(tuple)
659 tupleGroupsMC[lumiMC[period][
'group']].
append(tuple)
661 log(
"w",
"Period "+
str(period)+
" not recognised in lumiMC list.")
662 for group, tuples
in tupleGroupsMC.items():
663 log(
"i",
"Detected MC N."+
str(group)+
" group to be merged.")
670 if isDMR
and config[
'mode'] ==
"plot":
672 from Alignment.OfflineValidation.TkAlAllInOneTool.DMRplotter
import DMRplotter
676 plotInfo[
'outputDir'] = config[
'output']
677 for key
in [
'objects',
'labels',
'colors',
'styles', \
678 'useFit',
'useFitError',
'showMean',
'showMeanError',
'showRMS',
'showRMSError']:
679 plotInfo[key] = config[
'plot'][key]
680 if 'plotGlobal' in config.keys():
681 if 'CMSlabel' in config[
'plotGlobal'].
keys():
682 plotInfo[
'CMSlabel'] = config[
'plotGlobal'][
'CMSlabel']
684 plotInfo[
'CMSlabel'] =
"" 685 if 'Rlabel' in config[
'plotGlobal'].
keys():
686 plotInfo[
'Rlabel'] = config[
'plotGlobal'][
'Rlabel']
688 plotInfo[
'Rlabel'] =
"single muon (2016+2017+2018)" 692 for inputDir
in inputDirData:
693 plotter.addDATA(inputDir)
694 for inputDir
in inputDirMC:
695 plotter.addDirMC(inputDir)
701 def decodeLine(line, index, type)
def replace(string, replacements)
def getTuplesMC(inputDir)
def makeAveragedFile(tuples, intLumi, objName="")
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
def getLumiPerIoV(start_run, end_run=0)
def getTuples(inputDir, filterNumbers=[])
def split(sequence, size)
def log(log_type="", text="")