ValidateOpDetReco.py
Go to the documentation of this file.
1 #!/usr/bin/python
2 from __future__ import print_function
3 from past.builtins import execfile
4 from builtins import range
5 from builtins import object
6 import sys, os
7 
8 
9 
10 
11 ###################
12 # Parse arguments #
13 ###################
14 
15 startup = False
16 if sys.argv[0] and "PYTHONSTARTUP" in os.environ:
17  startup = True
18 
19 from optparse import OptionParser
20 
21 usage = "usage: %prog -n <nominal file> -t <test file> [-o <dir>] [-s] [-d] [-e 0,1] [--opdets=0,1] "
22 parser = OptionParser(usage=usage)
23 parser.add_option("-n", "--nominal", dest="nominalfile", help="Nominal flashan file", metavar="F")
24 parser.add_option("-t", "--test", dest="testfile", help="Test flashan file", metavar="F")
25 parser.add_option("-o", "--outdir", dest="dir", help="Directory to output plots", default="plots")
26 parser.add_option( "--flash", dest="flash", help="Flash-by-flash compare", default=False, action="store_true")
27 parser.add_option( "--hit", dest="hit", help="Hit-by-hit compare", default=False, action="store_true")
28 parser.add_option( "--assoc", dest="assoc", help="Assosciation-by-assosciation compare", default=False, action="store_true")
29 parser.add_option( "--plots", dest="plots", help="Hit and flash comparison plots", default=False, action="store_true")
30 parser.add_option( "--rootdir", dest="rootdir", help="TDirectory in root file from analyzer (%default)", default="flashana")
31 
32 (options, args) = parser.parse_args()
33 
34 if not (options.nominalfile and options.testfile):
35  print("Both nominal file (-n) and test file (-t) required.")
36  sys.exit(1)
37 
38 if not (options.flash or options.hit or options.assoc or options.plots):
39  print("No plots to make. Specify at least one of --flash, --hit, --assoc, --plots.")
40  sys.exit(1)
41 
42 # Load libraries after parsing arguments
43 
44 if startup:
45  execfile(os.environ["PYTHONSTARTUP"])
46 
47 from ROOT import *
48 from HandyFuncs import VerticalRange, GetHists, pbloop
49 from collections import defaultdict
50 import copy
51 import progressbar as pb
52 
53 
54 ############################
55 # Define utility functions #
56 ############################
57 
58 def ApproxCompare(left, right, tolerance = 0.001):
59  try:
60  return ( abs(right / left - 1.) < tolerance )
61  except ZeroDivisionError:
62  return (right == 0)
63 
64 def CountFailures(left, right):
65  return len(ListFailures(left,right))
66 
67 def ListFailures(left, right):
68  if isinstance(left, Flash): return ListFailuresFlash(left, right)
69  if isinstance(left, Assoc): return ListFailuresAssoc(left, right)
70  if isinstance(left, Hit): return ListFailuresHit(left, right)
71 
72 def ListFailuresFlash(left, right):
73  failures = []
74  tolerance = 0.001
75  if left.InBeamFrame != right.InBeamFrame: failures += [ 'InBeamFrame']
76  if left.OnBeamTime != right.OnBeamTime: failures += [ 'OnBeamTime' ]
77  if not ApproxCompare(left.YCenter, right.YCenter, tolerance): failures += [ 'YCenter' ]
78  if not ApproxCompare(left.ZCenter, right.ZCenter, tolerance): failures += [ 'ZCenter' ]
79  if not ApproxCompare(left.YWidth, right.YWidth, tolerance): failures += [ 'YWidth' ]
80  if not ApproxCompare(left.ZWidth, right.ZWidth, tolerance): failures += [ 'YWidth' ]
81  if not ApproxCompare(left.FlashTime, right.FlashTime, tolerance): failures += [ 'FlashTime' ]
82  if not ApproxCompare(left.FlashFrame,right.FlashFrame,tolerance): failures += [ 'Frame' ]
83  if not ApproxCompare(left.AbsTime, right.AbsTime, tolerance): failures += [ 'AbsTime' ]
84  if not ApproxCompare(left.TotalPE, right.TotalPE, 0.5): failures += [ 'TotalPE' ]
85  return failures
86 
87 def ListFailuresAssoc(left, right):
88  failures = []
89  tolerance = 0.000001
90  if left.EventID != right.EventID: failures += [ 'EventID' ]
91  if left.HitFrame != right.HitFrame: failures += [ 'HitFrame' ]
92  if left.FlashFrame != right.FlashFrame: failures += [ 'FlashFrame' ]
93  #if left.FlashID != right.FlashID: failures += [ 'FlashID' ]
94  if not ApproxCompare(left.HitPeakTime, right.HitPeakTime, tolerance): failures += [ 'HitPeakTime' ]
95  if not ApproxCompare(left.HitPE, right.HitPE, tolerance): failures += [ 'HitPE' ]
96  if not ApproxCompare(left.FlashTime, right.FlashTime, tolerance): failures += [ 'FlashTime' ]
97  if not ApproxCompare(left.FlashPE, right.FlashPE, tolerance): failures += [ 'FlashPE' ]
98  return failures
99 
100 def ListFailuresHit(left, right):
101  failures = []
102  tolerance = 0.000000001
103  if left.Frame != right.Frame: failures += [ 'Frame' ]
104  if not ApproxCompare(left.PeakTimeAbs, right.PeakTimeAbs, tolerance): failures += [ 'PeakTimeAbs' ]
105  if not ApproxCompare(left.PeakTime, right.PeakTime, tolerance): failures += [ 'PeakTime' ]
106  if not ApproxCompare(left.Width, right.Width, tolerance): failures += [ 'Width' ]
107  if not ApproxCompare(left.Area, right.Area, tolerance): failures += [ 'Area' ]
108  if not ApproxCompare(left.Amplitude, right.Amplitude, tolerance): failures += [ 'Amplitude' ]
109  if not ApproxCompare(left.PE, right.PE, tolerance): failures += [ 'PE' ]
110  if not ApproxCompare(left.FastToTotal, right.FastToTotal, tolerance): failures += [ 'FastToTotal' ]
111  return failures
112 
113 
114 
115 ##################
116 # Define objects #
117 ##################
118 
119 class Flash(object):
120 
121  def __init__(self, tree):
122  self.EventID = tree.EventID
123  self.FlashID = tree.FlashID
124  self.YCenter = tree.YCenter
125  self.ZCenter = tree.ZCenter
126  self.YWidth = tree.YWidth
127  self.ZWidth = tree.ZWidth
128  self.FlashFrame = 0 #tree.FlashFrame
129  self.FlashTime = tree.FlashTime
130  self.AbsTime = tree.AbsTime
131  self.InBeamFrame = tree.InBeamFrame
132  self.OnBeamTime = tree.OnBeamTime
133  self.TotalPE = tree.TotalPE
134 
135  def __lt__(self, other):
136  if not isinstance(other, Flash):
137  return NotImplemented
138  return self.AbsTime < other.AbsTime
139 
140  def __le__(self, other):
141  if not isinstance(other, Flash):
142  return NotImplemented
143  return self.AbsTime <= other.AbsTime
144 
145  def __gt__(self, other):
146  if not isinstance(other, Flash):
147  return NotImplemented
148  return self.AbsTime > other.AbsTime
149 
150  def __ge__(self, other):
151  if not isinstance(other, Flash):
152  return NotImplemented
153  return self.AbsTime >= other.AbsTime
154 
155 
156  def __eq__(self, other):
157  if not isinstance(other, Flash):
158  return NotImplemented
159 
160  if self.EventID != other.EventID: return False
161 
162  failures = ListFailures(self, other)
163  if "AbsTime" in failures or "FlashTime" in failures: return False
164 
165  if len(failures) > 3:
166  return False
167 
168  return True
169 
170  def __ne__(self, other):
171  result = self.__eq__(other)
172  if result is NotImplemented:
173  return result
174  return not result
175 
176  def PrintStr(self):
177  return "t={0.AbsTime:9.3f} q={0.TotalPE:7.2f} FlashID={0.FlashID:2} Frame={0.FlashFrame:1}".format(self)
178 
179 
180 class Assoc(object):
181 
182  def __init__(self, tree):
183  self.EventID = tree.EventID
184  self.FlashID = tree.FlashID
185  self.HitID = tree.HitID
186  self.OpChannel = tree.OpChannel
187  self.HitPeakTimeAbs = tree.HitPeakTimeAbs
188  self.HitPeakTime = tree.HitPeakTime
189  self.HitPE = tree.HitPE
190  self.FlashPE = tree.FlashPE
191  self.FlashTimeAbs = tree.FlashTimeAbs
192  self.FlashTime = tree.FlashTime
193  self.HitFrame = tree.HitFrame
194  self.FlashFrame = tree.FlashFrame
195 
196  def __lt__(self, other):
197  if not isinstance(other, Assoc):
198  return NotImplemented
199  if self.HitPeakTimeAbs < other.HitPeakTimeAbs:
200  return true
201  if self.HitPeakTimeAbs == other.HitPeakTimeAbs and self.OpChannel < other.OpChannel:
202  return true
203  return False
204 
205  def __le__(self, other):
206  if not isinstance(other, Assoc):
207  return NotImplemented
208  if self < other:
209  return True
210  if self.HitPeakTimeAbs == other.HitPeakTimeAbs and self.OpChannel == other.OpChannel:
211  return true
212  return False
213 
214  def __gt__(self, other):
215  if not isinstance(other, Assoc):
216  return NotImplemented
217  return not (self <= other)
218 
219  def __ge__(self, other):
220  if not isinstance(other, Assoc):
221  return NotImplemented
222  return not (self < other)
223 
224  def __eq__(self, other):
225  if not isinstance(other, Assoc):
226  return NotImplemented
227  if self.EventID != other.EventID: return False
228  if self.OpChannel != other.OpChannel: return False
229  failures = ListFailures(self, other)
230  if "HitPeakTimeAbs" in failures \
231  or "HitPeakTime" in failures \
232  or "PE" in failures : return False
233  return True
234 
235  def __ne__(self, other):
236  result = self.__eq__(other)
237  if result is NotImplemented:
238  return result
239  return not result
240 
241  def PrintStr(self):
242  return "{0.OpChannel:2d} t={0.HitPeakTimeAbs:8.3f}/{0.FlashTimeAbs:8.3f} q={0.HitPE:7.2f}/{0.FlashPE:7.2f} frame={0.HitFrame:1}/{0.FlashFrame:1}".format(self)
243  #.OpChannel, self.HitPeakTimeAbs, self.HitPE, self.HitFrame, self.FlashFrame, self.FlashID)
244 
245 
246 
247 class Hit(object):
248 
249  def __init__(self, tree):
250  self.EventID = tree.EventID
251  self.OpChannel = tree.OpChannel
252  self.PeakTimeAbs = tree.PeakTimeAbs
253  self.PeakTime = tree.PeakTime
254  self.Frame = tree.Frame
255  self.Width = tree.Width
256  self.Area = tree.Area
257  self.Amplitude = tree.Amplitude
258  self.PE = tree.PE
259  self.FastToTotal = tree.FastToTotal
260 
261 
262  def __lt__(self, other):
263  if not isinstance(other, Hit):
264  return NotImplemented
265  return self.PeakTimeAbs < other.PeakTimeAbs
266 
267  def __le__(self, other):
268  if not isinstance(other, Hit):
269  return NotImplemented
270  return self.PeakTimeAbs <= other.PeakTimeAbs
271 
272  def __gt__(self, other):
273  if not isinstance(other, Hit):
274  return NotImplemented
275  return self.PeakTimeAbs > other.PeakTimeAbs
276 
277  def __ge__(self, other):
278  if not isinstance(other, Hit):
279  return NotImplemented
280  return self.PeakTimeAbs >= other.PeakTimeAbs
281 
282  def __eq__(self, other):
283  if not isinstance(other, Hit):
284  return NotImplemented
285  if self.EventID != other.EventID: return False
286  if self.OpChannel != other.OpChannel: return False
287  failures = ListFailures(self, other)
288  if "PeakTimeAbs" in failures \
289  or "PeakTime" in failures: return False
290  if len(failures) > 0: return False
291  return True
292 
293  def __ne__(self, other):
294  result = self.__eq__(other)
295  if result is NotImplemented:
296  return result
297  return not result
298 
299  def PrintStr(self):
300  return "{0:2d} t={1:9.3f} q={2:7.2f}".format(self.OpChannel, self.PeakTimeAbs, self.PE)
301 
302 
303 
304 
305 ################
306 # Shared setup #
307 ################
308 
309 versions = [ "nominal", "test" ]
310 S = versions[0]
311 R = versions[1]
312 
313 files = {}
314 files[S] = TFile(options.nominalfile)
315 files[R] = TFile(options.testfile)
316 
317 hittrees = {}
318 flashtrees = {}
319 assoctrees = {}
320 for v in versions:
321  hittrees[v] = files[v].Get(options.rootdir+"/PerOpHitTree")
322  flashtrees[v] = files[v].Get(options.rootdir+"/PerFlashTree")
323  assoctrees[v] = files[v].Get(options.rootdir+"/FlashHitMatchTree")
324 
325 
326 
327 
328 
329 ####################
330 # Flash Comparison #
331 ####################
332 
333 if options.flash:
334 
335  all = {}
336  for v in versions:
337  for e in range(flashtrees[v].GetEntries()):
338  flashtrees[v].GetEntry(e)
339  if flashtrees[v].EventID not in all:
340  all[flashtrees[v].EventID] = defaultdict(list)
341  all[flashtrees[v].EventID][v].append(Flash(flashtrees[v]))
342 
343  for EventID in sorted(all.keys()):
344  for v in versions:
345  all[EventID][v].sort()
346  print(EventID, ":", len(all[EventID][S]), len(all[EventID][R]))
347 
348  onlies = copy.deepcopy(all)
349 
350  for E in sorted(all.keys()):
351  iS = 0
352 
353  matches = []
354  failures = [0]*8
355 
356  while True:
357  #print iS, "/", len(onlies[E][S])
358  found = False
359  for iR in range(len(onlies[E][R])):
360  if onlies[E][S][iS] == onlies[E][R][iR]:
361  matches.append( { S: onlies[E][S].pop( iS ),
362  R: onlies[E][R].pop( iR ) } )
363  found = True
364  break
365  if not found:
366  iS += 1
367  if iS >= len(onlies[E][S]):
368  break
369 
370  print("Event", E)
371  print(" matches", len(matches))
372  for v in versions:
373  print(" only", v, len(onlies[E][v]))
374 
375  for v in versions:
376  if len(onlies[E][v]):
377  print(" Only in",v)
378  for flsh in onlies[E][v]:
379  index = all[E][v].index(flsh)
380  print(" ",flsh.PrintStr())#, " preceeded by ", all[E][v][index-1].PrintStr()
381 
382 
383  print(" Matches")
384  for flsh in matches:
385  failures_here = ListFailures(flsh[S],flsh[R])
386  if failures_here:
387  print(" ", S+":", flsh[S].PrintStr(), " ", R+":", flsh[R].PrintStr(), " ".join(failures_here))
388 
389 
390 
391 
392 
393 ##################
394 # Hit Comparison #
395 ##################
396 
397 if options.hit:
398 
399  onlies = {}
400  for v in versions:
401  for e in pbloop(list(range(hittrees[v].GetEntries()))):
402  hittrees[v].GetEntry(e)
403  if hittrees[v].EventID not in onlies:
404  onlies[hittrees[v].EventID]= defaultdict(list)
405  onlies[hittrees[v].EventID][v].append(Hit(hittrees[v]))
406 
407  for EventID in sorted(onlies.keys()):
408  for v in versions:
409  onlies[EventID][v].sort()
410  print(EventID, ":", len(onlies[EventID][S]), len(onlies[EventID][R]))
411 
412 
413  for E in sorted(onlies.keys()):
414  iS = 0
415 
416  matches = []
417  failures = [0]*8
418 
419 
420  maxval = len(onlies[E][S])
421  widgets = [ 'Entries: ',pb.Value(), '/', pb.Total(), ' ', pb.Percentage(), ' ',
422  pb.Bar(marker='=',left='[',right=']'),
423  ' ',pb.ETA() ]
424  pbar = pb.ProgressBar(widgets=widgets, maxval=maxval, term_width=100)
425  pbar.start()
426  while True:
427  pbar.update(maxval-len(onlies[E][S]))
428  #print iS, "/", len(onlies[E][S])
429  found = False
430  for iR in range(len(onlies[E][R])):
431  if onlies[E][S][iS] == onlies[E][R][iR]:
432  matches.append( { S: onlies[E][S].pop( iS ),
433  R: onlies[E][R].pop( iR ) } )
434  found = True
435  break
436  if not found:
437  iS += 1
438  if iS >= len(onlies[E][S]):
439  break
440  pbar.finish()
441  print("")
442 
443  print("Event", E)
444  print(" matches", len(matches))
445  for v in versions:
446  print(" only", v, len(onlies[E][v]))
447 
448  for v in versions:
449  if len(onlies[E][v]):
450  print(" Only in",v)
451  for flsh in onlies[E][v]:
452  print(" ",flsh.PrintStr())
453 
454  #print " Matches"
455  #for flsh in matches:
456  # print " ", S+":", flsh[S].PrintStr(), " ", R+":", flsh[R].PrintStr(), " ".join(ListFailures(flsh[S],flsh[R]))
457 
458 
459 
460 
461 
462 ####################
463 # Assoc Comparison #
464 ####################
465 
466 if options.assoc:
467 
468 
469  onlies = {}
470  for v in versions:
471  for e in pbloop(list(range(assoctrees[v].GetEntries()))):
472  assoctrees[v].GetEntry(e)
473  if assoctrees[v].EventID not in onlies:
474  onlies[assoctrees[v].EventID] = defaultdict(list)
475  onlies[assoctrees[v].EventID][v].append(Assoc(assoctrees[v]))
476 
477  for EventID in sorted(onlies.keys()):
478  for v in versions:
479  onlies[EventID][v].sort()
480  print(EventID, ":", len(onlies[EventID][S]), len(onlies[EventID][R]))
481 
482 
483  for E in sorted(onlies.keys()):
484  iS = 0
485 
486  matches = []
487  failures = [0]*8
488  print("Event", E)
489  print("Unmatched lengths", S, len(onlies[E][S]), R, len(onlies[E][R]))
490  maxval = len(onlies[E][S])
491  widgets = [ 'Event %i: '%E,pb.Value(), '/', pb.Total(), ' ', pb.Percentage(), ' ',
492  pb.Bar(marker='=',left='[',right=']'),
493  ' ',pb.ETA() ]
494  pbar = pb.ProgressBar(widgets=widgets, maxval=maxval, term_width=100)
495  pbar.start()
496  while onlies[E][S] and onlies[E][R]:
497  pbar.update(maxval-len(onlies[E][S]))
498  if onlies[E][S][0] == onlies[E][R][0]:
499  matches.append( { S: onlies[E][S].pop( 0 ),
500  R: onlies[E][R].pop( 0 ) } )
501  elif onlies[E][S][0] < onlies[E][R][0]:
502  matches.append( { S: onlies[E][S].pop( 0 ) } )
503  elif onlies[E][S][0] > onlies[E][R][0]:
504  matches.append( { R: onlies[E][R].pop( 0 ) } )
505  else: # Same time, unmatched
506  matches.append( { S: onlies[E][S].pop( 0 ) } )
507  matches.append( { R: onlies[E][R].pop( 0 ) } )
508  pbar.finish()
509  print("")
510  print("matched lengths ", S, len(onlies[E][S]), R, len(onlies[E][R]))
511 
512  while onlies[E][S]:
513  matches.append( { S: onlies[E][S].pop( 0 ) } )
514  while onlies[E][R]:
515  matches.append( { R: onlies[E][R].pop( 0 ) } )
516 
517  ## while True:
518  ## pbar.update(maxval-len(onlies[E][S]))
519  ## #print iS, "/", len(onlies[E][S])
520  ## found = False
521  ## for iR in range(len(onlies[E][R])):
522  ## if onlies[E][S][iS] == onlies[E][R][iR]:
523  ## matches.append( { S: onlies[E][S].pop( iS ),
524  ## R: onlies[E][R].pop( iR ) } )
525  ## found = True
526  ## break
527  ## if not found:
528  ## matches.append( { S:
529  ## iS += 1
530  ## if iS >= len(onlies[E][S]):
531  ## break
532  ## pbar.finish()
533  ## print ""
534 
535  #print "Event", E
536  #print " matches", len(matches)
537  #for v in versions:
538  # print " only", v, len(onlies[E][v])
539 
540  #for v in versions:
541  # if len(onlies[E][v]):
542  # print " Only in",v
543  # for flsh in onlies[E][v]:
544  # print " ",flsh.PrintStr()
545 
546  print(" Matches")
547  for hit in matches:
548  print("", end=' ')
549  if S in hit: print(S+":", hit[S].PrintStr(), end=' ')
550  else: print("{0:65}".format(""), end=' ')
551  print("", end=' ')
552  if R in hit: print(" ", R+":", hit[R].PrintStr(), end=' ')
553  else: print("{0:65}".format(""), end=' ')
554  print(" ", end=' ')
555  if S in hit and R in hit:
556  failures_here = ListFailures(hit[S],hit[R])
557  print(" ".join(failures_here))
558  else:
559  print()
560 
561 
562 
563 
564 
565 
566 
567 
568 
569 
570 #######################
571 # Flash and Hit Plots #
572 #######################
573 
574 if options.plots:
575  if not os.path.exists(options.dir):
576  os.makedirs(options.dir)
577 
578  color = { S:kBlack, R:kRed }
579  hstyle = "hist"
580  mstyle = 20
581  lstyle = 2
582 
583  nbins = 100
584 
585 
586  c1 = TCanvas("c1","c1")
587 
588  for var, name, select in [ ("EventID","EventID",""),
589  ("OpChannel","OpChannel",""),
590  ("PeakTimeAbs","PeakTimeAbs",""),
591  ("PeakTime","PeakTime",""),
592  ("Frame","Frame",""),
593  ("Width","Width","Width<1"),
594  ("TMath::Log10(Area)","Area",""),
595  ("TMath::Log10(Amplitude)","Amplitude",""),
596  ("TMath::Log10(PE)","PE",""),
597  ("FastToTotal","FastToTotal","")]:
598 
599  hittrees[S].Draw("{0}>>h{1}{2:d}({3:d})".format(var,name,1,nbins), select, "hist")
600  hittrees[R].Draw("{0}>>h{1}{2:d}({3:d})".format(var,name,2,nbins), select, hstyle+"same")
601  h1 = gROOT.FindObject("h"+name+"1")
602  h2 = gROOT.FindObject("h"+name+"2")
603  h1.SetLineColor(color[S])
604  h2.SetLineColor(color[R])
605  h2.SetLineStyle(2)
606  h2.SetMarkerColor(color[R])
607  h2.SetMarkerStyle(mstyle)
608  c1.Print(os.path.join(options.dir,"perhit_"+name+".png"))
609 
610  hRatio = h2.Clone("hRatio")
611  hRatio.Divide(h1)
612  hRatio.Draw("p")
613  #hRatio.GetYaxis().SetRangeUser(0.5,1.1)
614  VerticalRange([hRatio], ratio=True, forceOne=True, ignoreError=True)
615  gPad.Update()
616  l1 = TLine(gPad.GetUxmin(), 1, gPad.GetUxmax(), 1)
617  l1.SetLineWidth(1)
618  l1.SetLineColor(kBlack)
619  l1.Draw()
620  hRatio.Draw("psame")
621  c1.Print(os.path.join(options.dir,"perhit_"+name+"_ratio.png"))
622 
623 
624  for var, name, select in [("EventID","EventID",""),
625  ("FlashID","FlashID",""),
626  ("YCenter","YCenter",""),
627  ("ZCenter","ZCenter",""),
628  ("YWidth","YWidth",""),
629  ("ZWidth","ZWidth",""),
630  ("FlashTime","FlashTime",""),
631  ("AbsTime","AbsTime",""),
632  ("InBeamFrame","InBeamFrame",""),
633  ("OnBeamTime","OnBeamTime",""),
634  ("TMath::Log10(TotalPE)","TotalPE","") ]:
635 
636  flashtrees[S].Draw("{0}>>h{1}{2:d}({3:d})".format(var,name,1,nbins), select, "hist")
637  flashtrees[R].Draw("{0}>>h{1}{2:d}({3:d})".format(var,name,2,nbins), select, hstyle+"same")
638  h1 = gROOT.FindObject("h"+name+"1")
639  h2 = gROOT.FindObject("h"+name+"2")
640  h1.SetLineColor(color[S])
641  h2.SetLineColor(color[R])
642  h2.SetLineStyle(lstyle)
643  h2.SetMarkerColor(color[R])
644  h2.SetMarkerStyle(mstyle)
645  c1.Print(os.path.join(options.dir,"perflash_"+name+".png"))
646 
647  hRatio = h2.Clone("hRatio")
648  hRatio.Divide(h1)
649  hRatio.Draw("p")
650  #hRatio.GetYaxis().SetRangeUser(0.5,1.1)
651  VerticalRange([hRatio], ratio=True, forceOne=True, ignoreError=True)
652  gPad.Update()
653  l1 = TLine(gPad.GetUxmin(), 1, gPad.GetUxmax(), 1)
654  l1.Draw()
655  l1.SetLineWidth(1)
656  l1.SetLineColor(kBlack)
657  hRatio.Draw("psame")
658  c1.Print(os.path.join(options.dir,"perflash_"+name+"_ratio.png"))
659 
def __eq__(self, other)
def __ge__(self, other)
static bool format(QChar::Decomposition tag, QString &str, int index, int len)
Definition: qstring.cpp:11496
def ListFailures(left, right)
def ApproxCompare(left, right, tolerance=0.001)
Define utility functions #.
def __init__(self, tree)
def ListFailuresHit(left, right)
T abs(T value)
def __le__(self, other)
def __lt__(self, other)
def VerticalRange(hists, xrange=(0, 0), ratio=False, forceOne=True, ignoreError=False, maxerr=0.25, absMax=-999, absMin=-999, buffer=0.05)
Definition: HandyFuncs.py:36
void Draw(const char *plot, const char *title)
Definition: gXSecComp.cxx:580
def __gt__(self, other)
def ListFailuresFlash(left, right)
def pbloop(iterable, name="Entries")
Definition: HandyFuncs.py:209
def CountFailures(left, right)
def ListFailuresAssoc(left, right)
def __ne__(self, other)