ATLAS Offline Software
Loading...
Searching...
No Matches
validator.py
Go to the documentation of this file.
1# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
2
3"""This script compares two given root files and saves plots where they differ
4as pdfs.
5
6author: Felix Socher <Felix.Socher@cern.ch>"""
7
8
9import ROOT
10from ROOT import *
11import sys
12import argparse
13import re
14import os
15import math
16
17LABELS = []
18
19def GoToDirectory(directory):
20 cwd = os.getcwd()
21 print os.getcwd()
22 newdir = cwd + "/" + directory
23 if not os.path.isdir( newdir ):
24 print "Creating folder " + newdir
25 os.makedirs( newdir )
26 os.chdir(newdir)
27
28
29def SameHist(refHist, testHist):
30 chi2 = 0
31 for x in range(refHist.GetNbinsX()):
32 for y in range(refHist.GetNbinsY()):
33 for z in range(refHist.GetNbinsZ()):
34 if refHist.GetBinContent(x,y,z) != testHist.GetBinContent(x,y,z): return False
35 return True
36
37def SimilarHist(refHist, testHist):
38 for x in range(refHist.GetNbinsX()):
39 for y in range(refHist.GetNbinsY()):
40 for z in range(refHist.GetNbinsZ()):
41 if abs(refHist.GetBinContent(x,y,z) - testHist.GetBinContent(x,y,z)) > 0.01: return False
42 return True
43
44
45
46
48 """docstring for Validator"""
49 def __init__(self, structDirs, exclude, compareFunc, normalization):
50 super(Validator, self).__init__()
51 self.structDirs = structDirs
52 #self.excludedStrings = exclude.split("|")
53 #print self.excludedStrings
54 self.CompareFunc = compareFunc
55 self.DoNormalization = normalization
56
57 def CompareFiles(self, fileNames, dirName):
58 openedFiles = [ TFile.Open(f) for f in fileNames ]
59 self.CompareDirectories(openedFiles, dirName)
60
61 def CompareDirectories(self, dirs, dirName):
62 if (self.structDirs): GoToDirectory(dirName)
63 refDir = dirs[0]
64 newRefDir = refDir.GetDirectory(dirName)
65 for testDir in dirs:
66 if testDir == refDir: continue
67 if not testDir:
68 print 'ERROR --------- test dir not found: ', dirName, testDir
69 return
70
71 newTestDirs = [ testDir.GetDirectory(dirName) for testDir in dirs ]
72
73 theDir = newRefDir
74 # if not newRefDir:
75 # print 'ERROR --------- reference dir not found: ', dirName
76 # theDir = newTestDir
77
78 for key in theDir.GetListOfKeys():
79
80 obj = key.ReadObj()
81
82 #2D histograms cannot be compared; skip
83 if obj.IsA().InheritsFrom(ROOT.TH2.Class()):
84 continue
85
86 if obj.IsA().InheritsFrom(ROOT.TH1.Class()):
87 print key.GetName()
88 #testHist = newTestDir.Get(key.GetName())
89 testHists = [ newTestDir.Get(key.GetName()) for newTestDir in newTestDirs ]
90 self.CompareHistograms( testHists, newRefDir.GetPath())
91 elif obj.IsA().InheritsFrom(ROOT.TDirectory.Class()):
92 self.CompareDirectories( newTestDirs, obj.GetName())
93 if (self.structDirs): os.chdir("..")
94
95 def CompareHistograms(self, hists, path):
96 # print self.excludedStrings, refHist.GetName()
97 # if any(exString in refHist.GetName() for exString in self.excludedStrings):
98 # print "Skipped " + path + "/" + refHist.GetName()
99 # return
100 #@@@if self.CompareFunc(refHist, testHist): print path + refHist.GetName() + " looks ok"
101 #else:
102 #self.MakeComparisonPlot(refHist, testHist, path)
103 self.MakeComparisonPlot(hists, path)
104
105 #def MakeComparisonPlot(self,refHist, testHist, path):
106 def MakeComparisonPlot(self, hists, path):
107 def SetBounds(hists, ymin=0, ymax=0):
108 if (ymin==0 and ymax==0):
109 ymin = min( [ h.GetMinimum() for h in hists ] )
110 ymax = min( [ h.GetMaximum() for h in hists ] )
111 if ymin>0 and ymax>0:
112 ymin = 0
113 else:
114 ymin = ymin - 0.15*abs(ymin)
115 ymax = ymax+ 0.15*ymax
116 # if ymin<0 and ymax>0:
117 # if ymax>0 and abs(minimum)>ymax:
118 # ymax = -minimum
119 hists[0].SetMinimum(ymin)
120 hists[0].SetMaximum(ymax)
121 return hists[0]
122 ################################## end SetBounds
123
124 # try:
125 # refHist.Scale(1.0/refHist.Integral())
126 # testHist.Scale(1.0/testHist.Integral())
127 # except:
128 # return
129 canvas = ROOT.TCanvas( "", "", 900, 900 )
130 padMain = ROOT.TPad( 'padMain', 'padMain', 0, 0.3, 1, 1 )
131 padMain.SetBottomMargin( 0.02 )
132 padMain.Draw()
133 #padMain.SetLogy(1) #@@@
134 padRatio = ROOT.TPad( 'padRatio', 'padRatio', 0, 0, 1, 0.3 )
135 padRatio.SetTopMargin( 0.01 )
136 padRatio.SetBottomMargin( 0.25 )
137 padRatio.Draw()
138 ROOT.TLine()
139 padMain.cd()
140
141 leg = ROOT.TLegend(0.82,0.78,0.96,0.94)
142 #leg = ROOT.TLegend(0.52,0.76,0.96,0.94)
143 #leg.SetFillColor(ROOT.kWhite)
144 leg.SetFillStyle(0)
145 leg.SetBorderSize(0)
146 leg.SetTextFont(43)
147 leg.SetTextSizePixels(32)
148
149 refHist = hists[0]
150 refHist.SetLineColor(17)
151 #refHist.SetFillColor(30)
152
153 ## @@@ Legend!!!
154 #leg.AddEntry(hists[0], 'ref', 'lp')
155 #leg.AddEntry(hists[1], 'test', 'lp')
156 #if len(hists)>2:
157 # for i in range(2,len(hists)):
158 # leg.AddEntry(hists[i], 'test{0}'.format(i), 'lp')
159 for i in range(0,len(hists)):
160 leg.AddEntry(hists[i], LABELS[i], 'lp')
161
162 if self.DoNormalization and not "_Eff_" in refHist.GetName() and not "_eff" in refHist.GetName() and not "_Eff" in refHist.GetName():
163 for h in hists:
164 n = h.Integral()
165 if n>0:
166 h.Scale(1./n)
167
168 refHist = SetBounds(hists)
169
170 ref_textsize = 32./(padMain.GetWh()*padMain.GetAbsHNDC())
171 refHist.GetYaxis().SetLabelSize( ref_textsize )
172 refHist.GetXaxis().SetLabelSize( 0 )
173 refHist.GetXaxis().SetTitleSize( 0 )
174 refHist.GetYaxis().SetTitleSize( 1.3*ref_textsize )
175 refHist.GetYaxis().SetTitleOffset(1)
176 refHist.GetYaxis().SetTitleColor( kAzure )
177
178 # testHist.GetYaxis().SetTextFont(43)
179 # testHist.GetYaxis().SetTextSizePixels(20)
180 refHist.SetMarkerSize(0)
181 refHist.SetLineColor(ROOT.kRed)
182 #refHist.GetYaxis().SetRangeUser(0.00001,refHist.GetMaximum()*5) ##@@@
183
184 #testHist.Rebin(2)
185 #refHist.Rebin(2);
186 histmax = refHist
187 histmax.DrawCopy('e')
188 # for h in hists:
189 # if h.GetMaximum() > refHist.GetMaximum():
190 # histmax = h
191 # if histmax == refHist:
192 # histmax.DrawCopy("e")
193 # else:
194 # histmax.DrawCopy("ehist")
195 nh=0
196 for h in hists:
197 if h is not histmax:
198 if h==refHist:
199 h.DrawCopy('histsame')
200 else:
201 nh=nh+1
202 if nh>1:
203 h.SetMarkerStyle(0)
204 h.SetMarkerColor(0)
205 h.SetLineColor(8) # green
206 h.SetLineStyle(ROOT.kDashed)
207 h.DrawCopy('ehistsame')
208 # if refHist.GetMaximum()>histmax.GetMaximum():
209 # refHist.DrawCopy("e")
210 # testHist.DrawCopy("ehistsame")
211 # refHist.DrawCopy("ehistsame")
212 # else:
213 # testHist.DrawCopy("ehist")
214 # refHist.DrawCopy("ehistsame")
215
216 leg.Draw()
217 padRatio.cd()
218
219 for h in hists:
220 if h is refHist: continue
221 ratioHist = h.Clone()
222 ratioHist.Divide(refHist)
223 ratioHist = SetBounds( [ratioHist, ratioHist], 0.84,1.16) # 0.941,1.059
224 for i in range(ratioHist.GetNbinsX()):
225 nref = refHist.GetBinContent(i)
226 ntest = h.GetBinContent(i)
227 if nref == 0 or ntest == 0:
228 ratioHist.SetBinError(i, 0)
229 else:
230 #error = nref/ntest*math.sqrt((refHist.GetBinError(i)/nref)**2 + (testHist.GetBinError(i)/ntest)**2)
231 error = nref/ntest* max(refHist.GetBinError(i)/nref, h.GetBinError(i)/ntest)
232 ratioHist.SetBinError(i, error)
233
234 ratioHist_textsize = 32./(padRatio.GetWh()*padRatio.GetAbsHNDC())
235 ratioHist.GetYaxis().SetLabelSize( ratioHist_textsize )
236 ratioHist.GetXaxis().SetLabelSize( ratioHist_textsize )
237 ratioHist.GetXaxis().SetTitleSize( 1.2*ratioHist_textsize )
238 ratioHist.GetXaxis().SetTitleOffset(0.75)
239 ratioHist.GetXaxis().SetTitleColor(kAzure)
240 ratioHist.GetYaxis().SetTitleSize( ratioHist_textsize )
241 ratioHist.GetYaxis().SetTitleOffset(0.6)
242
243
244 ratioHist.SetLineColor(ROOT.kBlack)
245 ratioHist.SetMarkerStyle(24)
246 ratioHist.SetYTitle("test / ref")
247 if h == hists[1]:
248 ratioHist.DrawCopy("p")
249 lineRatio = ROOT.TLine( ratioHist.GetXaxis().GetXmin(), 1,
250 ratioHist.GetXaxis().GetXmax(), 1 )
251 lineRatio.SetLineColor( ROOT.kRed )
252 lineRatio.SetLineWidth( 2 )
253 lineRatio.Draw("same")
254 else:
255 ratioHist.SetMarkerStyle(25)
256 ratioHist.SetMarkerColor(8)
257 ratioHist.SetLineColor(8)
258 ratioHist.DrawCopy("psame")
259
260 npath = ""
261 if not self.structDirs:
262 npath = path[path.find(":/")+2:] + "/"
263 npath = re.sub(r"[:,./]", "_", npath+"/")
264
265 canvas.cd()
266 t = ROOT.TLatex();
267 t.SetNDC()
268 t.SetTextColor(1)
269 t.SetTextSize(0.03);
270 t.DrawLatex(0.,0.97,refHist.GetName()) #@@@
271
272 canvas.SaveAs(npath + refHist.GetName() + ".pdf")
273 canvas.Close()
274
275#======================================================================
276def main( argv ):
277 """
278 Main function to be executed when starting the code.
279 """
280
281 parser = argparse.ArgumentParser( description = 'Distribution Plotter' )
282 parser.add_argument( '-s', '--structDirs', default = True, action = "store_true", help = ' if true, it creates directories following the same structure as in the root file to store the pdf plots')
283 parser.add_argument( '-r', '--reference', help = 'The reference' )
284 parser.add_argument( '-t', '--test', help = 'The test' )
285 parser.add_argument( '-t2', '--test2', default ='', help = 'The additional test' )
286 parser.add_argument( '-d', '--directory', default = "/", help = 'Print cutflow fror systematic variations' )
287 parser.add_argument( '-e', '--exclude', default = "_bin_", help = 'histograms whose names contain the provided strings are not examined')
288 parser.add_argument( '-n', '--normalize', default = False, action = "store_true", help = 'normalize histograms with larger stats for better comparison')
289 parser.add_argument( '-l', '--labels', default ='', help = 'Add text to legend for ref/test/test2, split with commas' )
290
291 args = parser.parse_args()
292
293
294 #ROOT.gROOT.Macro("rootlogon.C")
295 ROOT.gROOT.SetBatch()
296 #ROOT.gROOT.LoadMacro("./AtlasUtils.C")
297 ROOT.gROOT.LoadMacro("./AtlasStyle.C")
298 ROOT.TH1.SetDefaultSumw2(ROOT.kTRUE)
299
300 SetAtlasStyle()
301
302 LABELS = []
303 if args.labels is '':
304 LABELS = [ 'Ref','Test' ]
305 if args.test2 is not '':
306 LABELS.append( 'Test2' )
307 else:
308 LABELS = args.labels.split(",")
309 #print LABELS
310
311 # if you want to pass labels to legend directly from the file name...:
312 #LABELS.append( args.test.split('.')[2]+' '+args.test.split('.')[3] )
313 #
314
315 validator = Validator( args.structDirs, args.exclude, SameHist, args.normalize )
316 if args.test2 == '':
317 allFiles = [ os.path.abspath(args.reference), os.path.abspath(args.test) ]
318 else:
319 allFiles = [ os.path.abspath(args.reference), os.path.abspath(args.test), os.path.abspath(args.test2) ]
320 #======================================================================
321
322if __name__ == "__main__":
323 """
324 Here the code should appear that is executed when running the plotter directly
325 (and not import it in another python file via 'import Plotter')
326 """
327
328 # start main program
329 main( sys.argv[1:] )
330
SimilarHist(refHist, testHist)
Definition validator.py:37
GoToDirectory(directory)
Definition validator.py:19
SameHist(refHist, testHist)
Definition validator.py:29