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 
14 # 1/lumiScaleFactor to go from 1/pb to 1/fb
15 lumiScaleFactor = 1000
16 
17 grootargs = []
18 def callback_rootargs(option, opt, value, parser):
19  grootargs.append(opt)
20 
21 def vararg_callback(option, opt_str, value, parser):
22  assert value is None
23  value = []
24 
25  def floatable(str):
26  try:
27  float(str)
28  return True
29  except ValueError:
30  return False
31 
32  for arg in parser.rargs:
33  # stop on --foo like options
34  if arg[:2] == "--" and len(arg) > 2:
35  break
36  # stop on -a, but not on -3 or -3.0
37  if arg[:1] == "-" and len(arg) > 1 and not floatable(arg):
38  break
39  value.append(arg)
40 
41  del parser.rargs[:len(value)]
42  setattr(parser.values, option.dest, value)
43 
45  usage = ('usage: %prog [options]\n'
46  + '%prog -h for help')
47  parser = optparse.OptionParser(usage)
48 
49  parser.add_option("--inputFileName", dest="inputFileName", default="PixelBaryCentre.root",help="name of the ntuple file that contains the barycentre tree")
50  parser.add_option("--plotConfigFile", dest="plotConfigFile", default="PixelBaryCentrePlotConfig.json",help="json file that configs the plotting")
51 
52  parser.add_option("--usePixelQuality",action="store_true", dest="usePixelQuality", default=False,help="whether use SiPixelQuality")
53  parser.add_option("--showLumi",action="store_true", dest="showLumi", default=False,help="whether use integrated lumi as x-axis")
54  parser.add_option("--years", dest="years", default = [2017], action="callback", callback=vararg_callback, help="years to plot")
55 
56  parser.add_option("-l",action="callback",callback=callback_rootargs)
57  parser.add_option("-q",action="callback",callback=callback_rootargs)
58  parser.add_option("-b",action="callback",callback=callback_rootargs)
59 
60  return parser
61 
62 
63 def findRunIndex(run, runs) :
64  #runs has to be sorted
65  if(len(runs)==0) :
66  print("Empty run list!")
67  return -1
68  elif(len(runs)==1) :
69  if(run>=runs[0]) :
70  return 0
71  else :
72  print("Only one run but the run requested is before the run!")
73  return -1
74  else :
75  # underflow
76  if(run <= runs[0]) :
77  return 0
78  # overflow
79  elif(run >= runs[len(runs)-1]) :
80  return len(runs)-1
81  else :
82  return ROOT.TAxis(len(runs)-1,array('d',runs)).FindBin(run) - 1
83 
84 
85 def readBaryCentreAnalyzerTree(t, branch_names, accumulatedLumiPerRun, showLumi, isEOY) :
86  # to store lumi sections info for each run
87  run_maxlumi = {}
88  run_lumis = {}
89 
90  # y-axis of TGraph
91  # runs for all years // integrated luminosity as a function of run
92  runs = list(accumulatedLumiPerRun.keys())
93  runs.sort()
94 
95  current_run = 0
96  for iov in t :
97  # skip runs out-of-range
98  if(iov.run>runs[len(runs)-1] or iov.run<runs[0]):
99  continue
100 
101  if(iov.run!=current_run) : # a new run, initialize lumi sections
102  run_lumis[iov.run] = [iov.ls]
103  run_maxlumi[iov.run] = iov.ls
104  else : # current run, append lumi sections
105  run_lumis[iov.run].append(iov.ls)
106  if(run_maxlumi[iov.run]<iov.ls):
107  run_maxlumi[iov.run] = iov.ls
108  # update current run
109  current_run = iov.run
110 
111  # initialize store barycentre
112  pos = {}
113  for branch_name in branch_names :
114  for coord in ["x","y","z"] :
115  pos[coord+"_"+branch_name] = array('d',[])
116  # max and min to determine the plotting range
117  pos[coord+"max_"+branch_name] = -9999
118  pos[coord+"min_"+branch_name] = 9999
119 
120  # y-errors
121  zeros = array('d',[])
122 
123  # x-axis of TGraph
124  runlumi = array('d',[])
125  runlumiplot = array('d',[])
126  runlumiplot_error = array('d',[])
127 
128  max_run = 0
129  # loop over IOVs
130  for iov in t :
131  # skip runs out-of-range
132  if(iov.run>runs[len(runs)-1] or iov.run<runs[0]):
133  continue
134  # exclude 2018D for EOY rereco
135  if(isEOY and iov.run>=320413 and iov.run<=325175):
136  continue
137 
138  # if x-axis is luminosity
139  if(showLumi) :
140  run_index = findRunIndex(iov.run,runs)
141  instLumi = 0
142  if(run_index==0) :
143  instLumi = accumulatedLumiPerRun[ runs[run_index] ]
144  if(run_index>0) :
145  instLumi = accumulatedLumiPerRun[ runs[run_index] ] - accumulatedLumiPerRun[ runs[run_index-1] ]
146  # remove runs with zero luminosity if x-axis is luminosity
147  if( instLumi==0 ) : #and accumulatedLumiPerRun[ runs[run_index] ]==0 ) :
148  continue
149 
150  if(len(run_lumis[iov.run])>1) : # lumi-based conditions
151  if(run_index==0) :
152  runlumi.append(0.0+instLumi*iov.ls*1.0/run_maxlumi[iov.run])
153  else :
154  runlumi.append(accumulatedLumiPerRun[ runs[run_index-1] ]+instLumi*iov.ls*1.0/run_maxlumi[iov.run])
155 
156  else : # run-based or only one-IOV in the run
157  runlumi.append(accumulatedLumiPerRun[ runs[run_index] ])
158 
159  else: # else x-axis is run number
160  if(len(run_lumis[iov.run])>1) :#lumi-based conditions
161  runlumi.append(iov.run+iov.ls*1.0/run_maxlumi[iov.run])
162 
163  else : # run-based or only one-IOV in the run
164  runlumi.append(iov.run)
165 
166  zeros.append(0)
167 
168  #10000 is to translate cm to micro-metre
169  for branch_name in branch_names :
170  pos_ = {"x":10000*getattr(iov, branch_name).x(),
171  "y":10000*getattr(iov, branch_name).y(),
172  "z":10000*getattr(iov, branch_name).z()}
173 
174  for coord in ["x","y","z"] :
175  pos[coord+"_"+branch_name].append(pos_[coord])
176  # max/min
177  if(pos_[coord]>pos[coord+"max_"+branch_name]) :
178  pos[coord+"max_"+branch_name] = pos_[coord]
179  max_run = iov.run
180  if(pos_[coord]<pos[coord+"min_"+branch_name]) :
181  pos[coord+"min_"+branch_name] = pos_[coord]
182 
183  # x-axis : run/lumi or integrtated luminosity
184  for iov in range(len(runlumi)-1) :
185  runlumiplot.append(0.5*(runlumi[iov]+runlumi[iov+1]))
186  runlumiplot_error.append(0.5*(runlumi[iov+1]-runlumi[iov]))
187 
188  runlumiplot.append(runlumiplot[len(runlumiplot_error)-1]+2*runlumiplot_error[len(runlumiplot_error)-1])
189  runlumiplot_error.append(runlumiplot_error[len(runlumiplot_error)-1])
190 
191  v_runlumiplot = ROOT.TVectorD(len(runlumiplot),runlumiplot)
192  v_runlumiplot_error = ROOT.TVectorD(len(runlumiplot_error),runlumiplot_error)
193 
194  # y-axis error
195  v_zeros = ROOT.TVectorD(len(zeros),zeros)
196 
197  # store barycentre into a dict
198  barryCentre = {}
199  v_pos = {}
200  for branch_name in branch_names :
201  for coord in ["x","y","z"] :
202  v_pos[coord] = ROOT.TVectorD(len(pos[coord+"_"+branch_name]),pos[coord+"_"+branch_name])
203 
204  barryCentre[coord+'_'+branch_name] = ROOT.TGraphErrors(v_runlumiplot, v_pos[coord], v_runlumiplot_error, v_zeros)
205  barryCentre['a_'+coord+'_'+branch_name] = pos[coord+"_"+branch_name]
206 
207  barryCentre[coord+'max_'+branch_name] = pos[coord+"max_"+branch_name]
208  barryCentre[coord+'min_'+branch_name] = pos[coord+"min_"+branch_name]
209 
210  barryCentre['v_runlumiplot'] = v_runlumiplot
211  barryCentre['v_runlumierror'] = v_runlumiplot_error
212  barryCentre['v_zeros'] = v_zeros
213 
214  return barryCentre
215 
216 
217 def blackBox(x1, y1, x2, y2):
218  x = array('d',[x1, x2, x2, x1, x1])
219  y = array('d',[y1, y1, y2, y2, y1])
220  v_x = ROOT.TVectorD(len(x),x)
221  v_y = ROOT.TVectorD(len(y),y)
222 
223  gr = ROOT.TGraph(v_x,v_y)
224  gr.SetLineColor(ROOT.kBlack)
225 
226  return gr
227 
228 
229 def plotbarycenter(bc,coord,plotConfigJson, substructure,runsPerYear,pixelLocalRecos,accumulatedLumiPerRun, withPixelQuality,showLumi) :
230  runs = list(accumulatedLumiPerRun.keys())
231  runs.sort()
232  years = list(runsPerYear.keys())
233  years.sort()
234  labels = list(bc.keys())
235 
236  can = ROOT.TCanvas("barycentre_"+substructure+"_"+coord, "", 2000, 900)
237  can.cd()
238 
239  range_ = 0
240  width_ = 0
241  upper = 0
242  lower = 0
243  xmax = 0
244 
245  gr = {}
246  firstGraph = True
247  for label in labels :
248  gr[label] = ROOT.TGraph()
249  gr[label] = bc[label][coord+"_"+substructure]
250 
251  gr[label].SetMarkerStyle(8)
252  gr[label].SetMarkerSize(0)
253  gr[label].SetMarkerStyle(8)
254  gr[label].SetMarkerSize(0)
255  gr[label].SetLineColor(plotConfigJson["colorScheme"][label])
256 
257  width_ = gr[label].GetXaxis().GetXmax() - gr[label].GetXaxis().GetXmin()
258  xmax = gr[label].GetXaxis().GetXmax()
259 
260  if firstGraph :
261  upper = bc[label][coord+"max_"+substructure]
262  lower = bc[label][coord+"min_"+substructure]
263  firstGraph = False
264  else :
265  upper = max(upper, bc[label][coord+"max_"+substructure])
266  lower = min(lower, bc[label][coord+"min_"+substructure])
267 
268  scale = 1.1
269  if(upper>0) :
270  upper = upper * scale
271  else :
272  upper = upper / scale
273  if(lower>0) :
274  lower = lower / scale
275  else :
276  lower = lower * scale
277  range_ = upper - lower
278 
279  firstGraph = True
280  for label in labels :
281  if(firstGraph) :
282  gr[label].GetYaxis().SetRangeUser(lower, upper)
283  gr[label].GetYaxis().SetTitle(plotConfigJson["substructures"][substructure]+" barycentre ("+coord+") [#mum]")
284  gr[label].GetXaxis().SetTitle("Run Number")
285  gr[label].GetYaxis().CenterTitle(True)
286  gr[label].GetXaxis().CenterTitle(True)
287  gr[label].GetYaxis().SetTitleOffset(0.80)
288  gr[label].GetYaxis().SetTitleSize(0.055)
289  gr[label].GetXaxis().SetTitleOffset(0.80)
290  gr[label].GetXaxis().SetTitleSize(0.055)
291  gr[label].GetXaxis().SetMaxDigits(6)
292  if(showLumi) :
293  gr[label].GetXaxis().SetTitle("Delivered luminosity [1/fb]")
294 
295  gr[label].Draw("AP")
296  firstGraph = False
297  else :
298  gr[label].Draw("P")
299 
300  # dummy TGraph for pixel local reco changes and first-of-year Run
301  gr_dummyFirstRunOfTheYear = blackBox(-999, 10000, -999, -10000)
302  gr_dummyFirstRunOfTheYear.SetLineColor(ROOT.kBlack)
303  gr_dummyFirstRunOfTheYear.SetLineStyle(1)
304  gr_dummyFirstRunOfTheYear.Draw("L")
305  gr_dummyPixelReco = blackBox(-999, 10000, -999, -10000)
306  gr_dummyPixelReco.SetLineColor(ROOT.kGray+1)
307  gr_dummyPixelReco.SetLineStyle(3)
308  gr_dummyPixelReco.Draw("L")
309  gr_dummyFirstRunOfTheYear.SetTitle("First run of the year")
310  gr_dummyPixelReco.SetTitle("Pixel calibration update")
311 
312  for label in labels :
313  gr[label].SetTitle(plotConfigJson["baryCentreLabels"][label])
314  legend = can.BuildLegend()#0.65, 0.65, 0.85, 0.85)
315  legend.SetShadowColor(0)
316  legend.SetFillColor(0)
317  legend.SetLineColor(1)
318 
319  for label in labels :
320  gr[label].SetTitle("")
321 
322  # Add legends
323  # and vertical lines
324  years_label = ""
325  for year in years :
326  years_label += str(year)
327  years_label += "+"
328  years_label = years_label.rstrip("+")
329 
330  # CMS logo
331  CMSworkInProgress = ROOT.TPaveText( xmax-0.3*width_, upper+range_*0.005,
332  xmax, upper+range_*0.055, "nb")
333  CMSworkInProgress.AddText("CMS #bf{#it{Preliminary} ("+years_label+" pp collisions)}")
334  CMSworkInProgress.SetTextAlign(32) #right/bottom aligned
335  CMSworkInProgress.SetTextSize(0.04)
336  CMSworkInProgress.SetFillColor(10)
337  CMSworkInProgress.Draw()
338 
339  # vertical lines
340  #pixel local reco
341  line_pixels = {}
342  for since in pixelLocalRecos :
343  if showLumi :
344  run_index = findRunIndex(since,runs)
345  integrated_lumi = accumulatedLumiPerRun[runs[run_index]]
346  line_pixels[since] = ROOT.TLine(integrated_lumi, lower, integrated_lumi, upper)
347 
348  else :
349  line_pixels[since] = ROOT.TLine(since, lower, since, upper)
350 
351  line_pixels[since].SetLineColor(ROOT.kGray+1)
352  line_pixels[since].SetLineStyle(3)
353  line_pixels[since].Draw()
354 
355  # years
356  line_years = {}
357  box_years = {}
358  text_years = {}
359  if(len(years)>1 or (not showLumi) ) : # indicate begining of the year if more than one year to show or use run number
360  for year in years :
361  if showLumi :
362  #first run of the year
363  run_index = findRunIndex(runsPerYear[year][0],runs)
364  integrated_lumi = accumulatedLumiPerRun[runs[run_index]]
365  line_years[year] = ROOT.TLine(integrated_lumi, lower, integrated_lumi, upper)
366  text_years[year] = ROOT.TPaveText( integrated_lumi+0.01*width_, upper-range_*0.05,
367  integrated_lumi+0.05*width_, upper-range_*0.015, "nb")
368  box_years[year] = blackBox(integrated_lumi+0.005*width_, upper-range_*0.01, integrated_lumi+0.055*width_, upper-range_*0.055)
369  else :
370  line_years[year] = ROOT.TLine(runsPerYear[year][0], lower, runsPerYear[year][0], upper)
371  text_years[year] = ROOT.TPaveText( runsPerYear[year][0]+0.01*width_, upper-range_*0.05,
372  runsPerYear[year][0]+0.05*width_, upper-range_*0.015, "nb")
373  box_years[year] = blackBox(runsPerYear[year][0]+0.01*width_, upper-range_*0.015, runsPerYear[year][0]+0.05*width_, upper-range_*0.05)
374 
375 
376  box_years[year].Draw("L")
377  line_years[year].Draw()
378 
379  # Add TextBox at the beginning of each year
380  text_years[year].AddText(str(year))
381  text_years[year].SetTextAlign(22)
382  text_years[year].SetTextSize(0.025)
383  text_years[year].SetFillColor(10)
384  text_years[year].Draw()
385 
386  #legend.Draw()
387  can.Update()
388 
389  if(showLumi) :
390  can.SaveAs("baryCentre"+withPixelQuality+"_"+coord+"_"+substructure+"_"+years_label+"_IntegratedLumi.pdf")
391  can.SaveAs("baryCentre"+withPixelQuality+"_"+coord+"_"+substructure+"_"+years_label+"_IntegratedLumi.png")
392  else :
393  can.SaveAs("baryCentre"+withPixelQuality+"_"+coord+"_"+substructure+"_"+years_label+"_RunNumber.pdf")
394  can.SaveAs("baryCentre"+withPixelQuality+"_"+coord+"_"+substructure+"_"+years_label+"_RunNumber.png")
395 
396 
397 
398 
399 # main call
400 def Run():
401 
402  #ROOT.gSystem.Load("libFWCoreFWLite.so")
403  parser=parseOptions()
404  (options,args) = parser.parse_args()
405  sys.argv = grootargs
406 
407  inputFileName = options.inputFileName
408  if os.path.isfile(inputFileName) == False :
409  print ("File "+inputFileName+" not exist!")
410  return -1
411 
412  plotConfigFile = open(options.plotConfigFile)
413  plotConfigJson = json.load(plotConfigFile)
414  plotConfigFile.close()
415 
416  usePixelQuality = options.usePixelQuality
417  withPixelQuality = ""
418  if(usePixelQuality) :
419  withPixelQuality = "WithPixelQuality"
420  showLumi = options.showLumi
421  # order years from old to new
422  years = options.years
423  years.sort()
424 
425  # runs per year
426  runsPerYear = {}
427  for year in years :
428  runsPerYear[year] = []
429  # integrated lumi vs run
430  accumulatedLumiPerRun = {}
431 
432  run_index = 0
433  lastRun = 1
434 
435  # get lumi per IOV
436  CMSSW_Dir = os.getenv("CMSSW_BASE")
437  for year in years :
438  inputLumiFile = CMSSW_Dir + "/src/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)