CMS 3D CMS Logo

plotBaryCentre_VS_BeamSpot.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 import sys, os
4 from array import array
5 import optparse
6 from collections import OrderedDict
7 import json
8 
9 import ROOT
10 ROOT.gSystem.Load("libFWCoreFWLite.so")
11 
12 import CondCore.Utilities.conddblib as conddb
13 import Alignment.OfflineValidation.TkAlAllInOneTool.findAndChange as fnc
14 
15 # 1/lumiScaleFactor to go from 1/pb to 1/fb
16 lumiScaleFactor = 1000
17 
18 grootargs = []
19 def callback_rootargs(option, opt, value, parser):
20  grootargs.append(opt)
21 
22 def vararg_callback(option, opt_str, value, parser):
23  assert value is None
24  value = []
25 
26  def floatable(str):
27  try:
28  float(str)
29  return True
30  except ValueError:
31  return False
32 
33  for arg in parser.rargs:
34  # stop on --foo like options
35  if arg[:2] == "--" and len(arg) > 2:
36  break
37  # stop on -a, but not on -3 or -3.0
38  if arg[:1] == "-" and len(arg) > 1 and not floatable(arg):
39  break
40  value.append(arg)
41 
42  del parser.rargs[:len(value)]
43  setattr(parser.values, option.dest, value)
44 
46  usage = ('usage: %prog [options]\n'
47  + '%prog -h for help')
48  parser = optparse.OptionParser(usage)
49 
50  parser.add_option("--inputFileName", dest="inputFileName", default="PixelBaryCentre.root",help="name of the ntuple file that contains the barycentre tree")
51  parser.add_option("--plotConfigFile", dest="plotConfigFile", default="PixelBaryCentrePlotConfig.json",help="json file that configs the plotting")
52 
53  parser.add_option("--usePixelQuality",action="store_true", dest="usePixelQuality", default=False,help="whether use SiPixelQuality")
54  parser.add_option("--showLumi",action="store_true", dest="showLumi", default=False,help="whether use integrated lumi as x-axis")
55  parser.add_option("--years", dest="years", default = [2017], action="callback", callback=vararg_callback, help="years to plot")
56 
57  parser.add_option("-l",action="callback",callback=callback_rootargs)
58  parser.add_option("-q",action="callback",callback=callback_rootargs)
59  parser.add_option("-b",action="callback",callback=callback_rootargs)
60 
61  return parser
62 
63 
64 def findRunIndex(run, runs) :
65  #runs has to be sorted
66  if(len(runs)==0) :
67  print("Empty run list!")
68  return -1
69  elif(len(runs)==1) :
70  if(run>=runs[0]) :
71  return 0
72  else :
73  print("Only one run but the run requested is before the run!")
74  return -1
75  else :
76  # underflow
77  if(run <= runs[0]) :
78  return 0
79  # overflow
80  elif(run >= runs[len(runs)-1]) :
81  return len(runs)-1
82  else :
83  return ROOT.TAxis(len(runs)-1,array('d',runs)).FindBin(run) - 1
84 
85 
86 def readBaryCentreAnalyzerTree(t, branch_names, accumulatedLumiPerRun, showLumi, isEOY) :
87  # to store lumi sections info for each run
88  run_maxlumi = {}
89  run_lumis = {}
90 
91  # y-axis of TGraph
92  # runs for all years // integrated luminosity as a function of run
93  runs = list(accumulatedLumiPerRun.keys())
94  runs.sort()
95 
96  current_run = 0
97  for iov in t :
98  # skip runs out-of-range
99  if(iov.run>runs[len(runs)-1] or iov.run<runs[0]):
100  continue
101 
102  if(iov.run!=current_run) : # a new run, initialize lumi sections
103  run_lumis[iov.run] = [iov.ls]
104  run_maxlumi[iov.run] = iov.ls
105  else : # current run, append lumi sections
106  run_lumis[iov.run].append(iov.ls)
107  if(run_maxlumi[iov.run]<iov.ls):
108  run_maxlumi[iov.run] = iov.ls
109  # update current run
110  current_run = iov.run
111 
112  # initialize store barycentre
113  pos = {}
114  for branch_name in branch_names :
115  for coord in ["x","y","z"] :
116  pos[coord+"_"+branch_name] = array('d',[])
117  # max and min to determine the plotting range
118  pos[coord+"max_"+branch_name] = -9999
119  pos[coord+"min_"+branch_name] = 9999
120 
121  # y-errors
122  zeros = array('d',[])
123 
124  # x-axis of TGraph
125  runlumi = array('d',[])
126  runlumiplot = array('d',[])
127  runlumiplot_error = array('d',[])
128 
129  max_run = 0
130  # loop over IOVs
131  for iov in t :
132  # skip runs out-of-range
133  if(iov.run>runs[len(runs)-1] or iov.run<runs[0]):
134  continue
135  # exclude 2018D for EOY rereco
136  if(isEOY and iov.run>=320413 and iov.run<=325175):
137  continue
138 
139  # if x-axis is luminosity
140  if(showLumi) :
141  run_index = findRunIndex(iov.run,runs)
142  instLumi = 0
143  if(run_index==0) :
144  instLumi = accumulatedLumiPerRun[ runs[run_index] ]
145  if(run_index>0) :
146  instLumi = accumulatedLumiPerRun[ runs[run_index] ] - accumulatedLumiPerRun[ runs[run_index-1] ]
147  # remove runs with zero luminosity if x-axis is luminosity
148  if( instLumi==0 ) : #and accumulatedLumiPerRun[ runs[run_index] ]==0 ) :
149  continue
150 
151  if(len(run_lumis[iov.run])>1) : # lumi-based conditions
152  if(run_index==0) :
153  runlumi.append(0.0+instLumi*iov.ls*1.0/run_maxlumi[iov.run])
154  else :
155  runlumi.append(accumulatedLumiPerRun[ runs[run_index-1] ]+instLumi*iov.ls*1.0/run_maxlumi[iov.run])
156 
157  else : # run-based or only one-IOV in the run
158  runlumi.append(accumulatedLumiPerRun[ runs[run_index] ])
159 
160  else: # else x-axis is run number
161  if(len(run_lumis[iov.run])>1) :#lumi-based conditions
162  runlumi.append(iov.run+iov.ls*1.0/run_maxlumi[iov.run])
163 
164  else : # run-based or only one-IOV in the run
165  runlumi.append(iov.run)
166 
167  zeros.append(0)
168 
169  #10000 is to translate cm to micro-metre
170  for branch_name in branch_names :
171  pos_ = {"x":10000*getattr(iov, branch_name).x(),
172  "y":10000*getattr(iov, branch_name).y(),
173  "z":10000*getattr(iov, branch_name).z()}
174 
175  for coord in ["x","y","z"] :
176  pos[coord+"_"+branch_name].append(pos_[coord])
177  # max/min
178  if(pos_[coord]>pos[coord+"max_"+branch_name]) :
179  pos[coord+"max_"+branch_name] = pos_[coord]
180  max_run = iov.run
181  if(pos_[coord]<pos[coord+"min_"+branch_name]) :
182  pos[coord+"min_"+branch_name] = pos_[coord]
183 
184  # x-axis : run/lumi or integrtated luminosity
185  for iov in range(len(runlumi)-1) :
186  runlumiplot.append(0.5*(runlumi[iov]+runlumi[iov+1]))
187  runlumiplot_error.append(0.5*(runlumi[iov+1]-runlumi[iov]))
188 
189  runlumiplot.append(runlumiplot[len(runlumiplot_error)-1]+2*runlumiplot_error[len(runlumiplot_error)-1])
190  runlumiplot_error.append(runlumiplot_error[len(runlumiplot_error)-1])
191 
192  v_runlumiplot = ROOT.TVectorD(len(runlumiplot),runlumiplot)
193  v_runlumiplot_error = ROOT.TVectorD(len(runlumiplot_error),runlumiplot_error)
194 
195  # y-axis error
196  v_zeros = ROOT.TVectorD(len(zeros),zeros)
197 
198  # store barycentre into a dict
199  barryCentre = {}
200  v_pos = {}
201  for branch_name in branch_names :
202  for coord in ["x","y","z"] :
203  v_pos[coord] = ROOT.TVectorD(len(pos[coord+"_"+branch_name]),pos[coord+"_"+branch_name])
204 
205  barryCentre[coord+'_'+branch_name] = ROOT.TGraphErrors(v_runlumiplot, v_pos[coord], v_runlumiplot_error, v_zeros)
206  barryCentre['a_'+coord+'_'+branch_name] = pos[coord+"_"+branch_name]
207 
208  barryCentre[coord+'max_'+branch_name] = pos[coord+"max_"+branch_name]
209  barryCentre[coord+'min_'+branch_name] = pos[coord+"min_"+branch_name]
210 
211  barryCentre['v_runlumiplot'] = v_runlumiplot
212  barryCentre['v_runlumierror'] = v_runlumiplot_error
213  barryCentre['v_zeros'] = v_zeros
214 
215  return barryCentre
216 
217 
218 def blackBox(x1, y1, x2, y2):
219  x = array('d',[x1, x2, x2, x1, x1])
220  y = array('d',[y1, y1, y2, y2, y1])
221  v_x = ROOT.TVectorD(len(x),x)
222  v_y = ROOT.TVectorD(len(y),y)
223 
224  gr = ROOT.TGraph(v_x,v_y)
225  gr.SetLineColor(ROOT.kBlack)
226 
227  return gr
228 
229 
230 def plotbarycenter(bc,coord,plotConfigJson, substructure,runsPerYear,pixelLocalRecos,accumulatedLumiPerRun, withPixelQuality,showLumi) :
231  runs = list(accumulatedLumiPerRun.keys())
232  runs.sort()
233  years = list(runsPerYear.keys())
234  years.sort()
235  labels = list(bc.keys())
236 
237  can = ROOT.TCanvas("barycentre_"+substructure+"_"+coord, "", 2000, 900)
238  can.cd()
239 
240  range_ = 0
241  width_ = 0
242  upper = 0
243  lower = 0
244  xmax = 0
245 
246  gr = {}
247  firstGraph = True
248  for label in labels :
249  gr[label] = ROOT.TGraph()
250  gr[label] = bc[label][coord+"_"+substructure]
251 
252  gr[label].SetMarkerStyle(8)
253  gr[label].SetMarkerSize(0)
254  gr[label].SetMarkerStyle(8)
255  gr[label].SetMarkerSize(0)
256  gr[label].SetLineColor(plotConfigJson["colorScheme"][label])
257 
258  width_ = gr[label].GetXaxis().GetXmax() - gr[label].GetXaxis().GetXmin()
259  xmax = gr[label].GetXaxis().GetXmax()
260 
261  if firstGraph :
262  upper = bc[label][coord+"max_"+substructure]
263  lower = bc[label][coord+"min_"+substructure]
264  firstGraph = False
265  else :
266  upper = max(upper, bc[label][coord+"max_"+substructure])
267  lower = min(lower, bc[label][coord+"min_"+substructure])
268 
269  scale = 1.1
270  if(upper>0) :
271  upper = upper * scale
272  else :
273  upper = upper / scale
274  if(lower>0) :
275  lower = lower / scale
276  else :
277  lower = lower * scale
278  range_ = upper - lower
279 
280  firstGraph = True
281  for label in labels :
282  if(firstGraph) :
283  gr[label].GetYaxis().SetRangeUser(lower, upper)
284  gr[label].GetYaxis().SetTitle(plotConfigJson["substructures"][substructure]+" barycentre ("+coord+") [#mum]")
285  gr[label].GetXaxis().SetTitle("Run Number")
286  gr[label].GetYaxis().CenterTitle(True)
287  gr[label].GetXaxis().CenterTitle(True)
288  gr[label].GetYaxis().SetTitleOffset(0.80)
289  gr[label].GetYaxis().SetTitleSize(0.055)
290  gr[label].GetXaxis().SetTitleOffset(0.80)
291  gr[label].GetXaxis().SetTitleSize(0.055)
292  gr[label].GetXaxis().SetMaxDigits(6)
293  if(showLumi) :
294  gr[label].GetXaxis().SetTitle("Delivered luminosity [1/fb]")
295 
296  gr[label].Draw("AP")
297  firstGraph = False
298  else :
299  gr[label].Draw("P")
300 
301  # dummy TGraph for pixel local reco changes and first-of-year Run
302  gr_dummyFirstRunOfTheYear = blackBox(-999, 10000, -999, -10000)
303  gr_dummyFirstRunOfTheYear.SetLineColor(ROOT.kBlack)
304  gr_dummyFirstRunOfTheYear.SetLineStyle(1)
305  gr_dummyFirstRunOfTheYear.Draw("L")
306  gr_dummyPixelReco = blackBox(-999, 10000, -999, -10000)
307  gr_dummyPixelReco.SetLineColor(ROOT.kGray+1)
308  gr_dummyPixelReco.SetLineStyle(3)
309  gr_dummyPixelReco.Draw("L")
310  gr_dummyFirstRunOfTheYear.SetTitle("First run of the year")
311  gr_dummyPixelReco.SetTitle("Pixel calibration update")
312 
313  for label in labels :
314  gr[label].SetTitle(plotConfigJson["baryCentreLabels"][label])
315  legend = can.BuildLegend()#0.65, 0.65, 0.85, 0.85)
316  legend.SetShadowColor(0)
317  legend.SetFillColor(0)
318  legend.SetLineColor(1)
319 
320  for label in labels :
321  gr[label].SetTitle("")
322 
323  # Add legends
324  # and vertical lines
325  years_label = ""
326  for year in years :
327  years_label += str(year)
328  years_label += "+"
329  years_label = years_label.rstrip("+")
330 
331  # CMS logo
332  CMSworkInProgress = ROOT.TPaveText( xmax-0.3*width_, upper+range_*0.005,
333  xmax, upper+range_*0.055, "nb")
334  CMSworkInProgress.AddText("CMS #bf{#it{Preliminary} ("+years_label+" pp collisions)}")
335  CMSworkInProgress.SetTextAlign(32) #right/bottom aligned
336  CMSworkInProgress.SetTextSize(0.04)
337  CMSworkInProgress.SetFillColor(10)
338  CMSworkInProgress.Draw()
339 
340  # vertical lines
341  #pixel local reco
342  line_pixels = {}
343  for since in pixelLocalRecos :
344  if showLumi :
345  run_index = findRunIndex(since,runs)
346  integrated_lumi = accumulatedLumiPerRun[runs[run_index]]
347  line_pixels[since] = ROOT.TLine(integrated_lumi, lower, integrated_lumi, upper)
348 
349  else :
350  line_pixels[since] = ROOT.TLine(since, lower, since, upper)
351 
352  line_pixels[since].SetLineColor(ROOT.kGray+1)
353  line_pixels[since].SetLineStyle(3)
354  line_pixels[since].Draw()
355 
356  # years
357  line_years = {}
358  box_years = {}
359  text_years = {}
360  if(len(years)>1 or (not showLumi) ) : # indicate begining of the year if more than one year to show or use run number
361  for year in years :
362  if showLumi :
363  #first run of the year
364  run_index = findRunIndex(runsPerYear[year][0],runs)
365  integrated_lumi = accumulatedLumiPerRun[runs[run_index]]
366  line_years[year] = ROOT.TLine(integrated_lumi, lower, integrated_lumi, upper)
367  text_years[year] = ROOT.TPaveText( integrated_lumi+0.01*width_, upper-range_*0.05,
368  integrated_lumi+0.05*width_, upper-range_*0.015, "nb")
369  box_years[year] = blackBox(integrated_lumi+0.005*width_, upper-range_*0.01, integrated_lumi+0.055*width_, upper-range_*0.055)
370  else :
371  line_years[year] = ROOT.TLine(runsPerYear[year][0], lower, runsPerYear[year][0], upper)
372  text_years[year] = ROOT.TPaveText( runsPerYear[year][0]+0.01*width_, upper-range_*0.05,
373  runsPerYear[year][0]+0.05*width_, upper-range_*0.015, "nb")
374  box_years[year] = blackBox(runsPerYear[year][0]+0.01*width_, upper-range_*0.015, runsPerYear[year][0]+0.05*width_, upper-range_*0.05)
375 
376 
377  box_years[year].Draw("L")
378  line_years[year].Draw()
379 
380  # Add TextBox at the beginning of each year
381  text_years[year].AddText(str(year))
382  text_years[year].SetTextAlign(22)
383  text_years[year].SetTextSize(0.025)
384  text_years[year].SetFillColor(10)
385  text_years[year].Draw()
386 
387  #legend.Draw()
388  can.Update()
389 
390  if(showLumi) :
391  can.SaveAs("baryCentre"+withPixelQuality+"_"+coord+"_"+substructure+"_"+years_label+"_IntegratedLumi.pdf")
392  can.SaveAs("baryCentre"+withPixelQuality+"_"+coord+"_"+substructure+"_"+years_label+"_IntegratedLumi.png")
393  else :
394  can.SaveAs("baryCentre"+withPixelQuality+"_"+coord+"_"+substructure+"_"+years_label+"_RunNumber.pdf")
395  can.SaveAs("baryCentre"+withPixelQuality+"_"+coord+"_"+substructure+"_"+years_label+"_RunNumber.png")
396 
397 
398 
399 
400 # main call
401 def Run():
402 
403  #ROOT.gSystem.Load("libFWCoreFWLite.so")
404  parser=parseOptions()
405  (options,args) = parser.parse_args()
406  sys.argv = grootargs
407 
408  inputFileName = options.inputFileName
409  if os.path.isfile(inputFileName) == False :
410  print ("File "+inputFileName+" not exist!")
411  return -1
412 
413  plotConfigFile = open(options.plotConfigFile)
414  plotConfigJson = json.load(plotConfigFile)
415  plotConfigFile.close()
416 
417  usePixelQuality = options.usePixelQuality
418  withPixelQuality = ""
419  if(usePixelQuality) :
420  withPixelQuality = "WithPixelQuality"
421  showLumi = options.showLumi
422  # order years from old to new
423  years = options.years
424  years.sort()
425 
426  # runs per year
427  runsPerYear = {}
428  for year in years :
429  runsPerYear[year] = []
430  # integrated lumi vs run
431  accumulatedLumiPerRun = {}
432 
433  run_index = 0
434  lastRun = 1
435 
436  # get lumi per IOV
437  for year in years :
438  inputLumiFile = fnc.digest_path("Alignment/OfflineValidation/data/lumiperrun"+str(year)+".txt")
439  if os.path.isfile(inputLumiFile) == False :
440  print ("File "+inputLumiFile+" not exist!")
441  return -1
442  lumiFile = open(inputLumiFile,'r')
443  lines = lumiFile.readlines()
444 
445  for line in lines :
446  # line = "run inst_lumi"
447  run = int(line.split()[0])
448  integrated_lumi = float(line.split()[1])/lumiScaleFactor # 1/pb to 1/fb
449 
450  # runs per year
451  runsPerYear[year].append(run)
452  # integrated luminosity per run
453  # run number must be ordered from small to large in the text file
454  if(run_index == 0) :
455  accumulatedLumiPerRun[run] = integrated_lumi
456  else :
457  accumulatedLumiPerRun[run] = accumulatedLumiPerRun[lastRun]+integrated_lumi
458 
459  run_index+=1
460  lastRun = run
461 
462  # close file
463  lumiFile.close()
464 
465  # order by key (year)
466  runsPerYear = OrderedDict(sorted(runsPerYear.items(), key=lambda t: t[0]))
467  # order by key (run number)
468  accumulatedLumiPerRun = OrderedDict(sorted(accumulatedLumiPerRun.items(), key=lambda t: t[0]))
469 
470  #pixel local reco update (IOVs/sinces)
471  pixelLocalRecos = []
472  # connnect to ProdDB to access pixel local reco condition change
473  db = plotConfigJson["pixelDataBase"]
474  pixel_template = plotConfigJson["pixelLocalReco"]
475  db = db.replace("sqlite_file:", "").replace("sqlite:", "")
476  db = db.replace("frontier://FrontierProd/CMS_CONDITIONS", "pro")
477  db = db.replace("frontier://FrontierPrep/CMS_CONDITIONS", "dev")
478 
479  con = conddb.connect(url = conddb.make_url(db))
480  session = con.session()
481  # get IOV table
482  IOV = session.get_dbtype(conddb.IOV)
483  iovs = set(session.query(IOV.since).filter(IOV.tag_name == pixel_template).all())
484  session.close()
485  pixelLocalRecos = sorted([int(item[0]) for item in iovs])
486  #pixelLocalRecos = [1, 186500, 195360, 197749, 200961, 203368, 204601, 206446, 238341, 246866, 253914, 255655, 271866, 276315, 278271, 280928, 290543, 297281, 298653, 299443, 300389, 301046, 302131, 303790, 303998, 304911, 313041, 314881, 316758, 317475, 317485, 317527, 317661, 317664, 318227, 320377, 321831, 322510, 322603, 323232, 324245]
487 
488  # substructures to plot
489  substructures = list(plotConfigJson["substructures"].keys())
490 
491  # start barycentre plotter
492  bc = {}
493  try:
494  f = ROOT.TFile(inputFileName,"READ")
495  # read TTrees
496  for label in list(plotConfigJson["baryCentreLabels"].keys()) :
497  isEOY = False
498  t = ROOT.TTree()
499  if label == "" :
500  t = f.Get("PixelBaryCentreAnalyzer"+withPixelQuality+"/PixelBarycentre")
501  else :
502  t = f.Get("PixelBaryCentreAnalyzer"+withPixelQuality+"/PixelBarycentre_"+label)
503  if(label=="EOY") :
504  isEOY = True
505 
506  bc[label] = readBaryCentreAnalyzerTree(t, substructures, accumulatedLumiPerRun, showLumi, isEOY)
507 
508  except IOError:
509  print("File "+inputFileName+" not accessible")
510 
511  # plot
512  for substructure in substructures :
513  for coord in ['x','y','z'] :
514  plotbarycenter(bc,coord,plotConfigJson,substructure, runsPerYear,pixelLocalRecos,accumulatedLumiPerRun, withPixelQuality,showLumi)
515 
516 
517 if __name__ == "__main__":
518  Run()
def all(container)
workaround iterator generators for ROOT classes
Definition: cmstools.py:25
def replace(string, replacements)
def readBaryCentreAnalyzerTree(t, branch_names, accumulatedLumiPerRun, showLumi, isEOY)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
def plotbarycenter(bc, coord, plotConfigJson, substructure, runsPerYear, pixelLocalRecos, accumulatedLumiPerRun, withPixelQuality, showLumi)
def callback_rootargs(option, opt, value, parser)
#define str(s)
def vararg_callback(option, opt_str, value, parser)
if(threadIdxLocalY==0 &&threadIdxLocalX==0)