Belle II Software development
ecms.py
1
8
9"""
10Validation of the Invariant Collision Energy calibration
11"""
12
13
14from prompt import ValidationSettings
15
16import ROOT
17import sys
18import subprocess
19import json
20
21import numpy as np
22import pandas as pd
23import matplotlib.pyplot as plt
24from matplotlib import rcParams
25
26import re
27import os
28from glob import glob
29
30from datetime import datetime
31
32from collections import OrderedDict
33from shutil import copyfile, rmtree
34
35
36
37settings = ValidationSettings(name='eCMS Calibrations',
38 description=__doc__,
39 download_files=['stdout'],
40 expert_config={})
41
42
43def setPlotRange(df, tag):
44 """
45 Function which adjusts the y-axis range of the plot according to tag
46 """
47
48 if tag == '4S':
49 df4S = df[df['Ecms'] > 10560]['Ecms']
50 if len(df4S) > 0:
51 yMin = df4S.min()
52 plt.ylim(bottom=yMin-3)
53
54 dfHigh = df[df['Ecms'] < 10600]['Ecms']
55 if len(dfHigh) > 0:
56 yMax = dfHigh.max()
57 plt.ylim(top=yMax+3)
58
59 elif tag == 'Off':
60 dfOff = df[df['Ecms'] < 10560]['Ecms']
61 if len(dfOff) > 0:
62 yMax = dfOff.max()
63 plt.ylim(top=yMax+3)
64
65
66def toJST(times):
67 """
68 Converts time from UTC to the JST
69 """
70 return np.vectorize(lambda t: datetime.utcfromtimestamp((t + 9) * 3600))(times)
71
72
73def plotSplitLines(dfC):
74 """
75 Plot vertical lines in places where run energy type changes
76 """
77 indx = np.where(np.diff(dfC['pull'] == 0))[0]
78 for i in indx:
79 tt1 = toJST(dfC['t2'].loc[i]).item()
80 tt2 = toJST(dfC['t1'].loc[i+1]).item()
81 tt = tt1 + (tt2 - tt1) / 2
82 plt.axvline(x=tt, color='g', linestyle='--')
83
84
85def get_Ecms_values(path):
86 """
87 Load the values of the Ecms properties from the payloads into the list
88 """
89
90 runDict = {}
91 with open(path + '/database.txt') as fDB:
92 for ll in fDB:
93 ll = ll.strip()
94 ll = ll.split()
95
96 # deriving file name
97 fN = ll[0].replace('/', '_') + '_rev_' + ll[1] + '.root'
98
99 r = ll[2].split(',')
100 runDict[fN] = ((int(r[0]), int(r[1])), (int(r[2]), int(r[3])))
101
102 arr = []
103
104 fList = glob(path + '/*.root')
105 for fName in fList:
106 bName = os.path.basename(fName)
107 runExp = runDict[bName]
108
109 f = ROOT.TFile.Open(fName)
110 ecmsObj = f.Get("CollisionInvariantMass")
111 assert (ecmsObj.ClassName() == "Belle2::CollisionInvariantMass")
112
113 eCMS = ecmsObj.getMass()
114 eCMSe = ecmsObj.getMassError()
115 eCMSs = ecmsObj.getMassSpread()
116
117 arr.append((runExp, (eCMS, eCMSe, eCMSs)))
118
119 f.Close()
120
121 arr = sorted(arr, key=lambda x: x[0])
122
123 return arr
124
125
126class Plotter():
127 """Plotting class"""
128
129 def __init__(self, location):
130 """
131 Data are loaded from text files to pandas
132 """
133
134
135 self.dfB = pd.read_csv(f'{location}/BonlyEcmsCalib.txt', delim_whitespace=True)
136
137
138 self.dfC = pd.read_csv(f'{location}/finalEcmsCalib.txt', delim_whitespace=True)
139
140
141 self.dfM = pd.read_csv(f'{location}/mumuEcalib.txt', delim_whitespace=True)
142
143 # add the state
144 dfM = self.dfM
145 dfC = self.dfC
146 state = -1
147 dfM['type'] = 1
148 dfC['type'] = 1
149 for i in range(len(dfM)):
150 if (dfM['id'][i]) == 0:
151 state *= -1
152
153 dfM.at[i, 'type'] = state
154 dfC.at[i, 'type'] = state
155
156 @staticmethod
157 def plotLine(df, var, color, label):
158 """
159 Plot single line with error band
160 """
161
162 varUnc = var + 'Unc'
163 nan = np.full(len(df), np.nan)
164 avg = (df['t1']+df['t2']).to_numpy()/2
165 times = np.c_[df[['t1', 't2']].to_numpy(), avg].ravel()
166 eCMS = np.c_[df[[var, var]].to_numpy(), nan].ravel()
167 eCMSu = np.c_[df[[varUnc, varUnc]].to_numpy(), nan].ravel()
168
169 timesg = np.c_[df['t1'].to_numpy(), avg, df['t2'].to_numpy()].ravel()
170 eCMSg = np.c_[df[var].to_numpy(), nan, df[var].to_numpy()].ravel()
171
172 times = toJST(times)
173 timesg = toJST(timesg)
174
175 plt.fill_between(times, eCMS-eCMSu, eCMS+eCMSu, alpha=0.2, color=color)
176 plt.plot(times, eCMS, linewidth=2, color=color, label=label)
177 plt.plot(timesg, eCMSg, linewidth=2, color=color, alpha=0.35)
178
179 def plotEcmsComparison(self, limits=None, tag=''):
180 """
181 Plot Ecms obtained from combined, hadB and mumu method
182 """
183
184 Plotter.plotLine(self.dfB, 'Ecms', 'green', label='B decay method')
185 Plotter.plotLine(self.dfC, 'Ecms', 'red', label='Combined method')
186
187 d = np.nanmedian(self.dfC['Ecms']-self.dfM['Ecms'])
188
189 dfMc = self.dfM.copy()
190 dfMc['Ecms'] += d
191 Plotter.plotLine(dfMc, 'Ecms', 'blue', label=f'mumu method (+{round(d,1)} MeV)')
192
193 plotSplitLines(self.dfC)
194 setPlotRange(self.dfC, tag)
195
196 plt.xlabel('time')
197 plt.ylabel('Ecms [MeV]')
198
199 plt.legend()
200
201 loc = 'plots/allData'
202 if limits is not None:
203 plt.xlim(datetime.strptime(limits[0], '%Y-%m-%d'), datetime.strptime(limits[1], '%Y-%m-%d'))
204 loc = 'plots/' + limits[0] + 'to' + limits[1]
205
206 os.makedirs(loc, exist_ok=True)
207 plt.savefig(f'{loc}/EcmsComparison{tag}.png')
208 plt.clf()
209
210 def plotSpreadComparison(self, limits=None):
211 """
212 Plot Ecms spread estimated from the combined method and B-decay method
213 """
214
215 Plotter.plotLine(self.dfB, 'spread', 'green', label='B decay method')
216 Plotter.plotLine(self.dfC, 'spread', 'red', label='Combined method')
217
218 plotSplitLines(self.dfC)
219
220 plt.legend()
221
222 plt.xlabel('time')
223 plt.ylabel('spread [MeV]')
224
225 loc = 'plots/allData'
226 if limits is not None:
227 plt.xlim(datetime.strptime(limits[0], '%Y-%m-%d'), datetime.strptime(limits[1], '%Y-%m-%d'))
228 loc = 'plots/' + limits[0] + 'to' + limits[1]
229
230 os.makedirs(loc, exist_ok=True)
231 plt.savefig(f'{loc}/SpreadComparison.png')
232 plt.clf()
233
234 @staticmethod
235 def plotCurve(df, var, label, withBand=True, withCurve=True):
236 """
237 Plot curve with possible error band where large intervals are distinguished by color
238 """
239
240 def plotBands(df, var, color, withBand=True, withCurve=True):
241 varUnc = var + 'Unc'
242 nan = np.full(len(df), np.nan)
243 avg = (df['t1']+df['t2']).to_numpy()/2
244 times = np.c_[df[['t1', 't2']].to_numpy(), avg].ravel()
245 eCMS = np.c_[df[[var, var]].to_numpy(), nan].ravel()
246 times = toJST(times)
247
248 if withBand:
249 eCMSu = np.c_[df[[varUnc, varUnc]].to_numpy(), nan].ravel()
250 plt.fill_between(times, eCMS-eCMSu, eCMS+eCMSu, alpha=0.15, color=color)
251 if withCurve:
252 plt.plot(times, eCMS, linewidth=2, color=color)
253
254 nan = np.full(len(df), np.nan)
255 avg = (df['t1']+df['t2']).to_numpy()/2
256 timesg = np.c_[df['t1'].to_numpy(), avg, df['t2'].to_numpy()].ravel()
257 eCMSg = np.c_[df[var].to_numpy(), nan, df[var].to_numpy()].ravel()
258 timesg = toJST(timesg)
259
260 if withCurve:
261 plt.plot(timesg, eCMSg, linewidth=2, color='gray', alpha=0.35)
262
263 plotBands(df[df['type'] == 1], var, 'red', withBand, withCurve)
264 plotBands(df[df['type'] == -1], var, 'blue', withBand, withCurve)
265
266 def plotShift(self, limits=None):
267 """
268 Plot shift between Bhad and mumu method
269 """
270
271 Plotter.plotCurve(self.dfC, 'shift', label='Combined method')
272
273 plotSplitLines(self.dfC)
274
275 plt.xlabel('time')
276 plt.ylabel('shift [MeV]')
277
278 loc = 'plots/allData'
279 if limits is not None:
280 plt.xlim(datetime.strptime(limits[0], '%Y-%m-%d'), datetime.strptime(limits[1], '%Y-%m-%d'))
281 loc = 'plots/' + limits[0] + 'to' + limits[1]
282
283 os.makedirs(loc, exist_ok=True)
284 plt.savefig(f'{loc}/Shift.png')
285
286 plt.clf()
287
288 def plotEcms(self, limits=None, tag=''):
289 """
290 Plot Ecms of the combined fit, 'tag' can be '4S' means that y-axis is zoomed to 4S mass region, 'Off' to off-resonance
291 """
292
293 Plotter.plotCurve(self.dfC, 'Ecms', label='Combined method')
294
295 plotSplitLines(self.dfC)
296
297 plt.xlabel('time')
298 plt.ylabel('Ecms [MeV]')
299
300 setPlotRange(self.dfC, tag)
301
302 loc = 'plots/allData'
303 if limits is not None:
304 plt.xlim(datetime.strptime(limits[0], '%Y-%m-%d'), datetime.strptime(limits[1], '%Y-%m-%d'))
305 loc = 'plots/' + limits[0] + 'to' + limits[1]
306
307 os.makedirs(loc, exist_ok=True)
308 plt.savefig(f'{loc}/Ecms{tag}.png')
309 plt.clf()
310
311 def plotPulls(self, limits=None):
312 """
313 Plot pulls of the combined fit.
314 """
315
316 dfC = self.dfC.copy()
317 dfC['ref'] = 0
318 dfC['refUnc'] = 1
319 Plotter.plotCurve(dfC, 'pull', label='Combined method', withBand=False)
320 Plotter.plotCurve(dfC, 'ref', label='Combined method', withCurve=False)
321
322 plotSplitLines(self.dfC)
323
324 plt.ylim(-1.5, 1.5)
325 plt.xlabel('time')
326 plt.ylabel('pull')
327
328 loc = 'plots/allData'
329 if limits is not None:
330 plt.xlim(datetime.strptime(limits[0], '%Y-%m-%d'), datetime.strptime(limits[1], '%Y-%m-%d'))
331 loc = 'plots/' + limits[0] + 'to' + limits[1]
332
333 os.makedirs(loc, exist_ok=True)
334 plt.savefig(f'{loc}/Pull.png')
335 plt.clf()
336
337
338# Get the results from the combined calibration
339def read_Combined_data(outputDir):
340 """
341 It reads the calibration table from the text file produced by the CAF calibration.
342 This text file includes the results from the final calibration.
343 (combined or mumu-only)
344 """
345
346 arr = []
347 with open(outputDir + '/finalEcmsCalib.txt') as text_file:
348 for i, ll in enumerate(text_file):
349 if i == 0:
350 continue
351 ll = ll.strip().split()
352 arr.append(
353 ((float(
354 ll[0]), float(
355 ll[1])), (int(ll[2]), int(ll[3]), int(ll[4]), int(ll[5])), int(
356 ll[2+4]), (float(
357 ll[3+4]), float(
358 ll[4+4])), float(
359 ll[5+4]), (float(
360 ll[6+4]), float(
361 ll[7+4])), (float(
362 ll[8+4]), float(
363 ll[9+4]))))
364 return arr
365
366
367# Get the results from the combined calibration
368def read_Bonly_data(outputDir):
369 """
370 It reads the calibration table from the text file produced by the CAF calibration.
371 This text file includes the results from the B-only calibration.
372 """
373
374 arr = []
375 with open(outputDir + '/BonlyEcmsCalib.txt') as text_file:
376 for i, ll in enumerate(text_file):
377 if i == 0:
378 continue
379 ll = ll.strip().split()
380 arr.append(
381 ((float(
382 ll[0]), float(
383 ll[1])), (int(ll[2]), int(ll[3]), int(ll[4]), int(ll[5])),
384 (float(ll[2+4]), float(ll[3+4])), (float(ll[4+4]), float(ll[5+4]))))
385 return arr
386
387
388def read_mumu_data(outputDir):
389 """
390 It reads the calibration table from the text file produced by the CAF calibration.
391 This text file includes the results from the mumu-based calibration.
392 """
393
394 arr = []
395 with open(outputDir + '/mumuEcalib.txt') as text_file:
396 for i, ll in enumerate(text_file):
397 if i == 0:
398 continue
399 ll = ll.strip().split()
400 arr.append(
401 ((float(
402 ll[2+0]), float(
403 ll[2+1])), (int(ll[2+2]), int(ll[2+3]), int(ll[2+4]), int(ll[2+5])),
404 (float(ll[2+6]), float(ll[2+7])), (int(ll[0]), int(ll[1]))))
405 return arr
406
407
408# Create multi-page pdf file with the fit plots
409def create_hadB_fit_plots(outputDir, pdflatex):
410 """
411 Create multi-page pdf file with the fit plots for hadronic B decays (with mumu constraint).
412 The file is created using pdflatex
413 """
414
415 arr = read_Combined_data(outputDir)
416
417 dName = 'plotsHadB'
418
419 files = glob(outputDir+'/'+dName + '/*.pdf')
420 files = list(map(os.path.basename, files))
421
422 items = OrderedDict()
423
424 for f in files:
425 res = re.search('B[p0]_([0-9]*)_([0-9]*)\\.pdf', f)
426 t = int(res.group(1))
427 i = int(res.group(2))
428 if t not in items:
429 items[t] = 1
430 else:
431 items[t] = max(items[t], i + 1)
432
433 times = sorted(items)
434
435 header = """\\documentclass[aspectratio=169]{beamer}
436 \\usepackage{graphicx}
437
438 \\begin{document}
439 """
440
441 body = ""
442 for t in times:
443
444 i0 = None
445 for i0Temp in range(len(arr)):
446 if int(round(arr[i0Temp][0][0], 0)) == t:
447 i0 = i0Temp
448 break
449 assert (i0 is not None)
450
451 frac = 1. / (items[t] + 0.2)
452 if items[t] >= 6:
453 frac = 1. / (items[t] + 0.3)
454
455 body += '\\begin{frame}[t]\n'
456 shift, shiftE = str(round(arr[i0][5][0], 1)), str(round(arr[i0][5][1], 1))
457 spread, spreadE = str(round(arr[i0][6][0], 1)), str(round(arr[i0][6][1], 1))
458
459 body += '$E_\\mathrm{shift} = (' + shift + '\\pm' + shiftE + ')$~MeV \\hspace{2cm} \n'
460 body += '$E_\\mathrm{spread} = (' + spread + '\\pm' + spreadE + ')$~MeV \\\\ \\vspace{0.5cm}\n'
461 for iShort in range(items[t]):
462 i = i0 + iShort
463 tStart, tEnd = arr[i][0][0], arr[i][0][1]
464
465 exp1, run1, exp2, run2 = map(str, arr[i][1])
466
467 eCMS, eCMSe = str(round(arr[i][3][0], 1)), str(round(arr[i][3][1], 1))
468 pull = str(round(arr[i][4], 2))
469
470 t1 = datetime.utcfromtimestamp((tStart + 9) * 3600).strftime('%y-%m-%d %H:%M')
471 t2 = datetime.utcfromtimestamp((tEnd + 9) * 3600).strftime('%y-%m-%d %H:%M')
472
473 body += '\\begin{minipage}{' + str(frac) + '\\textwidth}\n'
474 body += '\\begin{center}\n'
475 body += '\\scriptsize ' + exp1 + ' '+run1 + ' \\\\\n'
476 body += '\\scriptsize ' + exp2 + ' '+run2 + ' \\\\\n'
477 body += '\\scriptsize ' + t1 + ' \\\\\n'
478 body += '\\scriptsize ' + t2 + ' \\\\\n'
479 body += '\\scriptsize ' + str(round(tEnd - tStart, 1)) + ' hours \\\\ \\vspace{0.3cm}\n'
480 body += '$(' + eCMS + '\\pm' + eCMSe + ')$~MeV \\\\\n'
481 body += '$\\mathrm{pull} = ' + pull + '$ \\\\\n'
482 body += '\\includegraphics[width=1.0\\textwidth]{' + outputDir + \
483 '/' + dName + '/B0_' + str(t) + '_' + str(iShort) + '.pdf}\\\\\n'
484 body += '\\includegraphics[width=1.0\\textwidth]{' + outputDir + \
485 '/' + dName + '/Bp_' + str(t) + '_' + str(iShort) + '.pdf}\n'
486 body += '\\end{center}\n'
487 body += '\\end{minipage}\n'
488
489 body += '\\end{frame}\n\n'
490
491 tail = '\n\\end{document}'
492
493 whole = header + body + tail
494
495 os.makedirs('tmp', exist_ok=True)
496
497 with open("tmp/hadBfits.tex", "w") as text_file:
498 text_file.write(whole)
499
500 subprocess.call(f'{pdflatex} tmp/hadBfits.tex', shell=True)
501
502 os.makedirs('plots', exist_ok=True)
503 copyfile('hadBfits.pdf', 'plots/hadBfits.pdf')
504
505 ext = ['aux', 'log', 'nav', 'out', 'pdf', 'snm', 'toc']
506 for e in ext:
507 if os.path.exists(f'hadBfits.{e}'):
508 os.remove(f'hadBfits.{e}')
509
510 rmtree('tmp')
511
512
513# Create multi-page pdf file with the fit plots
514def create_hadBonly_fit_plots(outputDir, pdflatex):
515 """
516 Create multi-page pdf file with the fit plots for hadronic B decays (without using mumu constraint).
517 The file is created using pdflatex
518 """
519
520 arr = read_Bonly_data(outputDir)
521
522 dName = 'plotsHadBonly'
523
524 files = glob(outputDir+'/'+dName + '/*.pdf')
525 files = list(map(os.path.basename, files))
526
527 items = set()
528
529 for f in files:
530 res = re.search('B[p0]Single_([0-9]*)\\.pdf', f)
531 t = int(res.group(1))
532 items.add(t) # [t] = 1
533
534 items = sorted(items)
535
536 header = """\\documentclass[aspectratio=169]{beamer}
537 \\usepackage{graphicx}
538
539 \\begin{document}
540 """
541
542 body = ""
543 for i, t in enumerate(items):
544
545 body += '\\begin{frame}[t]\n'
546
547 exp1, run1, exp2, run2 = map(str, arr[i][1])
548 eCMS, eCMSe = str(round(arr[i][2][0], 1)), str(round(arr[i][2][1], 1))
549 spread, spreadE = str(round(arr[i][3][0], 1)), str(round(arr[i][3][1], 1))
550
551 body += '$E_\\mathrm{cms} = (' + eCMS + '\\pm' + eCMSe + ')$~MeV \\\\\n'
552 body += '$E_\\mathrm{spread} = (' + spread + '\\pm' + spreadE + ')$~MeV \\\\ \\vspace{0.5cm}\n'
553
554 tStart, tEnd = arr[i][0][0], arr[i][0][1]
555
556 t1 = datetime.utcfromtimestamp((tStart + 9) * 3600).strftime('%y-%m-%d %H:%M')
557 t2 = datetime.utcfromtimestamp((tEnd + 9) * 3600).strftime('%y-%m-%d %H:%M')
558
559 body += '\\begin{minipage}{' + str(0.99) + '\\textwidth}\n'
560 body += '\\begin{center}\n'
561 body += '\\scriptsize ' + exp1 + ' ' + run1 + '\\hspace{1cm} ' + t1 + ' \\\\\n'
562 body += '\\scriptsize ' + exp2 + ' ' + run2 + '\\hspace{1cm} ' + t2 + ' \\\\\n'
563 body += '\\scriptsize ' + str(round(tEnd - tStart, 1)) + ' hours \\\\ \\vspace{0.3cm}\n'
564 body += '\\includegraphics[width=0.48\\textwidth]{'+outputDir + '/' + dName + '/B0Single_' + str(t) + '.pdf}\n'
565 body += '\\includegraphics[width=0.48\\textwidth]{'+outputDir + '/' + dName + '/BpSingle_' + str(t) + '.pdf}\n'
566 body += '\\end{center}\n'
567 body += '\\end{minipage}\n'
568
569 body += '\\end{frame}\n\n'
570
571 tail = '\n\\end{document}'
572
573 whole = header + body + tail
574
575 os.makedirs('tmp', exist_ok=True)
576
577 with open("tmp/hadBonlyFits.tex", "w") as text_file:
578 text_file.write(whole)
579
580 subprocess.call(f'{pdflatex} tmp/hadBonlyFits.tex', shell=True)
581
582 os.makedirs('plots', exist_ok=True)
583 copyfile('hadBonlyFits.pdf', 'plots/hadBonlyFits.pdf')
584
585 ext = ['aux', 'log', 'nav', 'out', 'pdf', 'snm', 'toc']
586 for e in ext:
587 if os.path.exists(f'hadBonlyFits.{e}'):
588 os.remove(f'hadBonlyFits.{e}')
589
590 if os.path.exists("tmp/hadBonlyFits.tex"):
591 os.remove("tmp/hadBonlyFits.tex")
592 rmtree('tmp')
593
594
595def create_mumu_fit_plots(outputDir, pdflatex):
596 """
597 Create multi-page pdf file with the fit plots for mumu method.
598 The file is created using pdflatex
599 """
600
601 arr = read_mumu_data(outputDir)
602
603 limits = []
604 for i, a in enumerate(arr):
605 if a[3][1] == a[3][0] - 1:
606 limits.append((i - a[3][1], a[3][0]))
607
608 dName = 'plotsMuMu'
609
610 files = glob(outputDir+'/'+dName + '/*.pdf')
611 files = list(map(os.path.basename, files))
612
613 items = set()
614
615 for f in files:
616 res = re.search('mumu_([0-9]*)\\.pdf', f)
617 t = int(res.group(1))
618 items.add(t)
619
620 items = sorted(items)
621
622 header = """\\documentclass[aspectratio=169]{beamer}
623 \\usepackage{graphicx}
624
625 \\begin{document}
626 """
627
628 body = ""
629 for k, n in limits:
630
631 frac = None
632 if n >= 11:
633 frac = 0.159
634 elif n >= 9:
635 frac = 0.193
636 elif n >= 7:
637 frac = 0.24
638 elif n >= 5:
639 frac = 0.3
640 elif n >= 3:
641 frac = 0.33
642 elif n >= 2:
643 frac = 0.48
644 elif n >= 1:
645 frac = 0.75
646
647 body += '\\begin{frame}[t]\n'
648
649 for i in range(k, k+n):
650
651 body += '\\begin{minipage}{' + str(frac) + '\\textwidth}\n'
652
653 exp1, run1, exp2, run2 = map(str, arr[i][1])
654 eCMS, eCMSe = str(round(arr[i][2][0], 1)), str(round(arr[i][2][1], 1))
655
656 tStart, tEnd = arr[i][0][0], arr[i][0][1]
657
658 t1 = datetime.utcfromtimestamp((tStart + 9) * 3600).strftime('%y-%m-%d %H:%M')
659 t2 = datetime.utcfromtimestamp((tEnd + 9) * 3600).strftime('%y-%m-%d %H:%M')
660
661 body += '\\begin{center}\n'
662 body += '\\tiny $E_\\mathrm{cms} = (' + eCMS + '\\pm' + eCMSe + ')$~MeV \\\\\n'
663 body += '\\tiny ' + exp1 + ' ' + run1 + '\\hspace{0.3cm} ' + t1 + ' \\\\\n'
664 body += '\\tiny ' + exp2 + ' ' + run2 + '\\hspace{0.3cm} ' + t2 + ' \\\\\n'
665 body += '\\tiny ' + str(round(tEnd - tStart, 1)) + ' hours \\vspace{0.3cm}\n'
666 body += '\\includegraphics[trim=0.3cm 0.0cm 1.3cm 0.7cm,clip=true,width=0.99\\textwidth]{' + \
667 outputDir + '/' + dName + '/mumu_' + str(items[i]) + '.pdf}\n'
668 body += '\\end{center}\n'
669 body += '\\end{minipage}\n'
670
671 body += '\\end{frame}\n\n'
672
673 tail = '\n\\end{document}'
674
675 whole = header + body + tail
676
677 os.makedirs('tmp', exist_ok=True)
678
679 with open("tmp/mumuFits.tex", "w") as text_file:
680 text_file.write(whole)
681
682 subprocess.call(f'{pdflatex} tmp/mumuFits.tex', shell=True)
683
684 os.makedirs('plots', exist_ok=True)
685 copyfile('mumuFits.pdf', 'plots/mumuFits.pdf')
686
687 ext = ['aux', 'log', 'nav', 'out', 'pdf', 'snm', 'toc']
688 for e in ext:
689 if os.path.exists(f'mumuFits.{e}'):
690 os.remove(f'mumuFits.{e}')
691
692 if os.path.exists("tmp/mumuFits.tex"):
693 os.remove("tmp/mumuFits.tex")
694 rmtree('tmp')
695
696
697def run_validation(job_path, input_data_path, requested_iov, expert_config):
698 """
699 Create validation plots related to the Ecms calibration
700 """
701
702 # get location of pdflatex
703 result = subprocess.run('locate pdflatex | grep "/pdflatex$"', stdout=subprocess.PIPE, shell=True)
704 pdflatex = result.stdout.strip().decode('utf-8')
705
706 # Expert config can contain the time ranges of the plots
707 if expert_config != '':
708 expert_config = json.loads(expert_config)
709
710 allLimits = [None]
711 if expert_config is not None and 'plotsRanges' in expert_config:
712 allLimits += expert_config['plotsRanges']
713
714 plt.figure(figsize=(18, 9))
715 rcParams['axes.formatter.useoffset'] = False
716
717 location = f'{job_path}/eCMS/0/algorithm_output'
718
719 plotter = Plotter(location)
720 # plot the results
721 for limits in allLimits:
722 plotter.plotEcmsComparison(limits, tag='4S')
723 plotter.plotEcmsComparison(limits, tag='Off')
724 plotter.plotEcmsComparison(limits)
725 plotter.plotSpreadComparison(limits)
726
727 plotter.plotEcms(limits, tag='4S')
728 plotter.plotEcms(limits, tag='Off')
729 plotter.plotEcms(limits, tag='')
730
731 plotter.plotShift(limits)
732 plotter.plotPulls(limits)
733
734 # create pdf with plots of fits
735 create_hadB_fit_plots(location, pdflatex)
736 create_hadBonly_fit_plots(location, pdflatex)
737 create_mumu_fit_plots(location, pdflatex)
738
739 # copy csv files to validation directory
740 copyfile(f'{location}/BonlyEcmsCalib.txt', 'plots/BonlyEcmsCalib.txt')
741 copyfile(f'{location}/finalEcmsCalib.txt', 'plots/finalEcmsCalib.txt')
742 copyfile(f'{location}/mumuEcalib.txt', 'plots/mumuEcalib.txt')
743
744
745if __name__ == "__main__":
746 run_validation(*sys.argv[1:])
dfC
read combined calibration
Definition ecms.py:138
plotSpreadComparison(self, limits=None)
Definition ecms.py:210
plotEcms(self, limits=None, tag='')
Definition ecms.py:288
dfM
read mumu calibration
Definition ecms.py:141
plotPulls(self, limits=None)
Definition ecms.py:311
plotShift(self, limits=None)
Definition ecms.py:266
plotEcmsComparison(self, limits=None, tag='')
Definition ecms.py:179
__init__(self, location)
Definition ecms.py:129
plotLine(df, var, color, label)
Definition ecms.py:157
plotCurve(df, var, label, withBand=True, withCurve=True)
Definition ecms.py:235
dfB
read B-only calibration
Definition ecms.py:135
STL class.