Belle II Software  release-06-00-14
ecms.py
1 # -*- coding: utf-8 -*-
2 
3 
10 
11 """
12 Validation of the Invariant Collision Energy calibration
13 """
14 
15 
16 from prompt import ValidationSettings
17 
18 import ROOT
19 import sys
20 import subprocess
21 import json
22 
23 import numpy as np
24 import pandas as pd
25 import matplotlib.pyplot as plt
26 from matplotlib import rcParams
27 
28 import re
29 import os
30 from glob import glob
31 
32 from datetime import datetime
33 
34 from collections import OrderedDict
35 from shutil import copyfile, rmtree
36 
37 
38 
39 settings = ValidationSettings(name='Ecms Calibrations',
40  description=__doc__,
41  download_files=['stdout'],
42  expert_config={})
43 
44 
45 def setPlotRange(df, tag):
46  """
47  Function which adjusts the y-axis range of the plot according to tag
48  """
49 
50  if tag == '4S':
51  df4S = df[df['Ecms'] > 10560]['Ecms']
52  if len(df4S) > 0:
53  yMin = df4S.min()
54  plt.ylim(bottom=yMin-3)
55 
56  dfHigh = df[df['Ecms'] < 10600]['Ecms']
57  if len(dfHigh) > 0:
58  yMax = dfHigh.max()
59  plt.ylim(top=yMax+3)
60 
61  elif tag == 'Off':
62  dfOff = df[df['Ecms'] < 10560]['Ecms']
63  if len(dfOff) > 0:
64  yMax = dfOff.max()
65  plt.ylim(top=yMax+3)
66 
67 
68 def toJST(times):
69  """
70  Converts time from UTC to the JST
71  """
72  return np.vectorize(lambda t: datetime.utcfromtimestamp((t + 9) * 3600))(times)
73 
74 
75 def plotSplitLines(dfC):
76  """
77  Plot vertical lines in places where run energy type changes
78  """
79  indx = np.where(np.diff(dfC['pull'] == 0))[0]
80  for i in indx:
81  tt1 = toJST(dfC['t2'].loc[i]).item()
82  tt2 = toJST(dfC['t1'].loc[i+1]).item()
83  tt = tt1 + (tt2 - tt1) / 2
84  plt.axvline(x=tt, color='g', linestyle='--')
85 
86 
87 def get_Ecms_values(path):
88  """
89  Load the values of the Ecms properties from the payloads into the list
90  """
91 
92  runDict = {}
93  with open(path + '/database.txt') as fDB:
94  for ll in fDB:
95  ll = ll.strip()
96  ll = ll.split()
97 
98  # deriving file name
99  fN = ll[0].replace('/', '_') + '_rev_' + ll[1] + '.root'
100 
101  r = ll[2].split(',')
102  runDict[fN] = ((int(r[0]), int(r[1])), (int(r[2]), int(r[3])))
103 
104  arr = []
105 
106  fList = glob(path + '/*.root')
107  for fName in fList:
108  bName = os.path.basename(fName)
109  runExp = runDict[bName]
110 
111  f = ROOT.TFile.Open(fName)
112  ecmsObj = f.Get("CollisionInvariantMass")
113  assert(ecmsObj.ClassName() == "Belle2::CollisionInvariantMass")
114 
115  eCMS = ecmsObj.getMass()
116  eCMSe = ecmsObj.getMassError()
117  eCMSs = ecmsObj.getMassSpread()
118 
119  arr.append((runExp, (eCMS, eCMSe, eCMSs)))
120 
121  f.Close()
122 
123  arr = sorted(arr, key=lambda x: x[0])
124 
125  return arr
126 
127 
128 class Plotter():
129  def __init__(self, location):
130  """
131  Data are loaded from text files to pandas
132  """
133 
134  # read B-only calibration
135  self.dfBdfB = pd.read_csv(f'{location}/BonlyEcmsCalib.txt', delim_whitespace=True)
136 
137  # read combined calibration
138  self.dfCdfC = pd.read_csv(f'{location}/finalEcmsCalib.txt', delim_whitespace=True)
139 
140  # read mumu calibration
141  self.dfMdfM = pd.read_csv(f'{location}/mumuEcalib.txt', delim_whitespace=True)
142 
143  # add the state
144  dfM = self.dfMdfM
145  dfC = self.dfCdfC
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.dfBdfB, 'Ecms', 'green', label='B decay method')
185  Plotter.plotLine(self.dfCdfC, 'Ecms', 'red', label='Combined method')
186 
187  d = np.nanmedian(self.dfCdfC['Ecms']-self.dfMdfM['Ecms'])
188 
189  dfMc = self.dfMdfM.copy()
190  dfMc['Ecms'] += d
191  Plotter.plotLine(dfMc, 'Ecms', 'blue', label=f'mumu method (+{round(d,1)} MeV)')
192 
193  plotSplitLines(self.dfCdfC)
194  setPlotRange(self.dfCdfC, 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.dfBdfB, 'spread', 'green', label='B decay method')
216  Plotter.plotLine(self.dfCdfC, 'spread', 'red', label='Combined method')
217 
218  plotSplitLines(self.dfCdfC)
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.dfCdfC, 'shift', label='Combined method')
272 
273  plotSplitLines(self.dfCdfC)
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.dfCdfC, 'Ecms', label='Combined method')
294 
295  plotSplitLines(self.dfCdfC)
296 
297  plt.xlabel('time')
298  plt.ylabel('Ecms [MeV]')
299 
300  setPlotRange(self.dfCdfC, 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.dfCdfC.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.dfCdfC)
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
339 def 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', "r") 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
368 def 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', "r") 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 
388 def 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', "r") 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
409 def 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
514 def 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 
595 def 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 
697 def 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 
745 if __name__ == "__main__":
746  run_validation(*sys.argv[1:])
def plotEcms(self, limits=None, tag='')
Definition: ecms.py:288
def __init__(self, location)
Definition: ecms.py:129
def plotSpreadComparison(self, limits=None)
Definition: ecms.py:210
def plotLine(df, var, color, label)
Definition: ecms.py:157
def plotEcmsComparison(self, limits=None, tag='')
Definition: ecms.py:179
def plotPulls(self, limits=None)
Definition: ecms.py:311
def plotShift(self, limits=None)
Definition: ecms.py:266
def plotCurve(df, var, label, withBand=True, withCurve=True)
Definition: ecms.py:235