ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/VHbb/python/stack_from_dc.py
Revision: 1.15
Committed: Fri Jan 25 16:18:00 2013 UTC (12 years, 3 months ago) by nmohr
Content type: text/x-python
Branch: MAIN
Changes since 1.14: +1 -1 lines
Log Message:
Restructuring, still to be validated, workspace writing missing

File Contents

# User Rev Content
1 nmohr 1.1 #!/usr/bin/env python
2     import pickle
3     import sys, os
4     from optparse import OptionParser
5 peller 1.14 from copy import copy,deepcopy
6     from math import sqrt
7     import math
8     from HiggsAnalysis.CombinedLimit.DatacardParser import *
9     from HiggsAnalysis.CombinedLimit.ShapeTools import *
10     import ROOT
11     from myutils import StackMaker, BetterConfigParser
12    
13     ROOT.gROOT.SetBatch(True)
14     ROOT.gSystem.Load("libHiggsAnalysisCombinedLimit.so")
15 nmohr 1.1
16     #CONFIGURE
17     argv = sys.argv
18     parser = OptionParser()
19     parser.add_option("-D", "--datacard", dest="dc", default="",
20     help="Datacard to be plotted")
21     parser.add_option("-B", "--bin", dest="bin", default="",
22     help="DC bin to plot")
23     parser.add_option("-M", "--mlfit", dest="mlfit", default="",
24     help="mlfit file for nuisances")
25     parser.add_option("-F", "--fitresult", dest="fit", default="s",
26     help="Fit result to be used, 's' (signal+background) or 'b' (background only), default is 's'")
27     parser.add_option("-C", "--config", dest="config", default=[], action="append",
28     help="configuration file")
29     (opts, args) = parser.parse_args(argv)
30    
31     def readBestFit(theFile):
32     file = ROOT.TFile(theFile)
33 nmohr 1.4 if file == None: raise RuntimeError, "Cannot open file %s" % theFile
34 nmohr 1.1 fit_s = file.Get("fit_s")
35     fit_b = file.Get("fit_b")
36     prefit = file.Get("nuisances_prefit")
37     if fit_s == None or fit_s.ClassName() != "RooFitResult": raise RuntimeError, "File %s does not contain the output of the signal fit 'fit_s'" % args[0]
38     if fit_b == None or fit_b.ClassName() != "RooFitResult": raise RuntimeError, "File %s does not contain the output of the background fit 'fit_b'" % args[0]
39     if prefit == None or prefit.ClassName() != "RooArgSet": raise RuntimeError, "File %s does not contain the prefit nuisances 'nuisances_prefit'" % args[0]
40    
41     isFlagged = {}
42     table = {}
43     fpf_b = fit_b.floatParsFinal()
44     fpf_s = fit_s.floatParsFinal()
45     nuiVariation = {}
46     for i in range(fpf_s.getSize()):
47     nuis_s = fpf_s.at(i)
48     name = nuis_s.GetName();
49     nuis_b = fpf_b.find(name)
50     nuis_p = prefit.find(name)
51     if nuis_p != None:
52     mean_p, sigma_p = (nuis_p.getVal(), nuis_p.getError())
53     for fit_name, nuis_x in [('b', nuis_b), ('s',nuis_s)]:
54     if nuis_p != None:
55     valShift = (nuis_x.getVal() - mean_p)/sigma_p
56     #sigShift = nuis_x.getError()/sigma_p
57     print fit_name, name
58     print valShift
59     nuiVariation['%s_%s'%(fit_name,name)] = valShift
60     #print valShift
61     return nuiVariation
62    
63 nmohr 1.6 def getBestFitShapes(procs,theShapes,shapeNui,theBestFit,DC,setup,opts,Dict):
64 nmohr 1.4 b = opts.bin
65     for p in procs:
66     counter = 0
67     nom = theShapes[p].Clone()
68     for (lsyst,nofloat,pdf,pdfargs,errline) in DC.systs:
69     if errline[b][p] == 0: continue
70 nmohr 1.11 if ("shape" in pdf):
71     if shapeNui[p+lsyst] > 0.:
72 nmohr 1.4 theVari = 'Up'
73     else:
74     theVari = 'Down'
75     bestNuiVar = theShapes[p+lsyst+theVari].Clone()
76     bestNuiVar.Add(nom,-1.)
77 nmohr 1.11 #print p,lsyst,abs(shapeNui[p+lsyst]),bestNuiVar.Integral()
78     bestNuiVar.Scale(abs(shapeNui[p+lsyst]))
79 nmohr 1.4 if counter == 0:
80     bestNui = bestNuiVar.Clone()
81     else:
82     bestNui.Add(bestNuiVar)
83     counter +=1
84 nmohr 1.10 nom.Add(bestNui)
85 nmohr 1.6 #nom.Scale(theBestFit[p])
86     nom.Scale(theShapes[p].Integral()/nom.Integral()*theBestFit[p])
87 nmohr 1.4 nBins = nom.GetNbinsX()
88     for bin in range(1,nBins+1):
89     nom.SetBinError(bin,theShapes[p].GetBinError(bin))
90     theShapes['%s_%s'%(opts.fit,p)] = nom.Clone()
91     histos = []
92     typs = []
93 nmohr 1.8 sigCount = 0
94 nmohr 1.4 for s in setup:
95 nmohr 1.8 if 'ZH' == s or 'WH' == s:
96     if sigCount ==0:
97     Overlay=copy(theShapes[Dict[s]])
98     else:
99     Overlay.Add(theShapes[Dict[s]])
100     sigCount += 1
101 nmohr 1.4 else:
102     histos.append(theShapes['%s_%s'%(opts.fit,Dict[s])])
103     typs.append(s)
104 nmohr 1.8 return histos,Overlay,typs
105 nmohr 1.4
106 nmohr 1.1
107     def drawFromDC():
108     config = BetterConfigParser()
109     config.read(opts.config)
110 nmohr 1.8 dataname = ''
111     if 'Zmm' in opts.bin: dataname = 'Zmm'
112     elif 'Zee' in opts.bin: dataname = 'Zee'
113 nmohr 1.9 elif 'Wmunu' in opts.bin: dataname = 'Wmn'
114     elif 'Wenu' in opts.bin: dataname = 'Wen'
115 nmohr 1.8 elif 'Znunu' in opts.bin: dataname = 'Znn'
116    
117     var = 'BDT'
118     if dataname == 'Zmm' or dataname == 'Zee': var = 'BDT_Zll'
119     elif dataname == 'Wmn' or dataname == 'Wen': var = 'BDT_Wln'
120     elif dataname == 'Znn':
121     if 'HighPt' in opts.bin: var = 'BDT_ZnnHighPt'
122     if 'LowPt' in opts.bin: var = 'BDT_ZnnLowPt'
123     if 'LowCSV' in opts.bin: var = 'BDT_ZnnLowCSV'
124     if dataname == '' or var == 'BDT': raise RuntimeError, "Did not recognise mode or var from %s" % opts.bin
125    
126 nmohr 1.1 region = 'BDT'
127     ws_var = config.get('plotDef:%s'%var,'relPath')
128 nmohr 1.12 ws_var = ROOT.RooRealVar(ws_var,ws_var,-1.,1.)
129 nmohr 1.1 blind = eval(config.get('Plot:%s'%region,'blind'))
130     Stack=StackMaker(config,var,region,True)
131    
132 nmohr 1.4 preFit = False
133 nmohr 1.6 addName = 'PostFit_%s' %(opts.fit)
134 nmohr 1.4 if not opts.mlfit:
135 nmohr 1.6 addName = 'PreFit'
136 nmohr 1.4 preFit = True
137    
138 nmohr 1.15 Stack.options['pdfName'] = '%s_%s_%s.pdf' %(var,opts.bin,addName)
139 nmohr 1.6
140 nmohr 1.1 log = eval(config.get('Plot:%s'%region,'log'))
141    
142     setup = config.get('Plot_general','setup').split(',')
143 nmohr 1.8 if dataname == 'Zmm' or dataname == 'Zee':
144     setup.remove('Wb')
145     setup.remove('Wlight')
146     setup.remove('WH')
147 nmohr 1.1 Dict = eval(config.get('LimitGeneral','Dict'))
148     lumi = eval(config.get('Plot_general','lumi'))
149    
150     options = copy(opts)
151     options.dataname = "data_obs"
152     options.mass = 0
153     options.format = "%8.3f +/- %6.3f"
154 nmohr 1.2 options.channel = opts.bin
155 nmohr 1.1 options.excludeSyst = []
156     options.norm = False
157     options.stat = False
158     options.bin = True # fake that is a binary output, so that we parse shape lines
159     options.out = "tmp.root"
160     options.fileName = args[0]
161     options.cexpr = False
162     options.fixpars = False
163     options.libs = []
164     options.verbose = 0
165     options.poisson = 0
166     options.nuisancesToExclude = []
167     options.noJMax = None
168 nmohr 1.12 theBinning = ROOT.RooFit.Binning(Stack.nBins,Stack.xMin,Stack.xMax)
169 nmohr 1.1
170     file = open(opts.dc, "r")
171     os.chdir(os.path.dirname(opts.dc))
172     DC = parseCard(file, options)
173     if not DC.hasShapes: DC.hasShapes = True
174     MB = ShapeBuilder(DC, options)
175     theShapes = {}
176     theSyst = {}
177 nmohr 1.4 nuiVar = {}
178 nmohr 1.1 if opts.mlfit:
179     nuiVar = readBestFit(opts.mlfit)
180 nmohr 1.8 if not opts.bin in DC.bins: raise RuntimeError, "Cannot open find %s in bins %s of %s" % (opts.bin,DC.bins,opts.dc)
181 nmohr 1.1 for b in DC.bins:
182     if options.channel != None and (options.channel != b): continue
183     exps = {}
184     expNui = {}
185     shapeNui = {}
186     for (p,e) in DC.exp[b].items(): # so that we get only self.DC.processes contributing to this bin
187     exps[p] = [ e, [] ]
188     expNui[p] = [ e, [] ]
189     for (lsyst,nofloat,pdf,pdfargs,errline) in DC.systs:
190     if pdf in ('param', 'flatParam'): continue
191     # begin skip systematics
192     skipme = False
193     for xs in options.excludeSyst:
194     if re.search(xs, lsyst):
195     skipme = True
196     if skipme: continue
197     # end skip systematics
198     counter = 0
199     for p in DC.exp[b].keys(): # so that we get only self.DC.processes contributing to this bin
200     if errline[b][p] == 0: continue
201 nmohr 1.7 if p == 'QCD': continue
202 nmohr 1.1 if pdf == 'gmN':
203     exps[p][1].append(1/sqrt(pdfargs[0]+1));
204     elif pdf == 'gmM':
205     exps[p][1].append(errline[b][p]);
206     elif type(errline[b][p]) == list:
207     kmax = max(errline[b][p][0], errline[b][p][1], 1.0/errline[b][p][0], 1.0/errline[b][p][1]);
208     exps[p][1].append(kmax-1.);
209     elif pdf == 'lnN':
210     exps[p][1].append(max(errline[b][p], 1.0/errline[b][p])-1.);
211     if not nuiVar.has_key('%s_%s'%(opts.fit,lsyst)):
212     nui = 0.
213     else:
214     nui= nuiVar['%s_%s'%(opts.fit,lsyst)]
215     expNui[p][1].append(abs(1-errline[b][p])*nui);
216 nmohr 1.11 elif ("shape" in pdf):
217 nmohr 1.7 #print 'shape %s %s: %s'%(pdf,p,lsyst)
218 nmohr 1.1 s0 = MB.getShape(b,p)
219     sUp = MB.getShape(b,p,lsyst+"Up")
220     sDown = MB.getShape(b,p,lsyst+"Down")
221     if (s0.InheritsFrom("RooDataHist")):
222 nmohr 1.12 s0 = ROOT.RooAbsData.createHistogram(s0,p,ws_var,theBinning)
223 nmohr 1.1 s0.SetName(p)
224 nmohr 1.12 sUp = ROOT.RooAbsData.createHistogram(sUp,p+lsyst+'Up',ws_var,theBinning)
225 nmohr 1.1 sUp.SetName(p+lsyst+'Up')
226 nmohr 1.12 sDown = ROOT.RooAbsData.createHistogram(sDown,p+lsyst+'Down',ws_var,theBinning)
227 nmohr 1.1 sDown.SetName(p+lsyst+'Down')
228     theShapes[p] = s0.Clone()
229     theShapes[p+lsyst+'Up'] = sUp.Clone()
230     theShapes[p+lsyst+'Down'] = sDown.Clone()
231     if not nuiVar.has_key('%s_%s'%(opts.fit,lsyst)):
232     nui = 0.
233     else:
234     nui= nuiVar['%s_%s'%(opts.fit,lsyst)]
235 nmohr 1.11 shapeNui[p+lsyst] = nui
236     if not 'CMS_vhbb_stat' in lsyst:
237     if counter == 0:
238     theSyst[lsyst] = s0.Clone()
239     theSyst[lsyst+'Up'] = sUp.Clone()
240     theSyst[lsyst+'Down'] = sDown.Clone()
241     else:
242     theSyst[lsyst].Add(s0)
243     theSyst[lsyst+'Up'].Add(sUp.Clone())
244     theSyst[lsyst+'Down'].Add(sDown.Clone())
245     counter += 1
246    
247 nmohr 1.1 procs = DC.exp[b].keys(); procs.sort()
248 nmohr 1.7 if 'QCD' in procs:
249     procs.remove('QCD')
250 nmohr 1.1 fmt = ("%%-%ds " % max([len(p) for p in procs]))+" "+options.format;
251     #Compute norm uncertainty and best fit
252     theNormUncert = {}
253     theBestFit = {}
254     for p in procs:
255     relunc = sqrt(sum([x*x for x in exps[p][1]]))
256     print fmt % (p, exps[p][0], exps[p][0]*relunc)
257     theNormUncert[p] = relunc
258     absBestFit = sum([x for x in expNui[p][1]])
259     theBestFit[p] = 1.+absBestFit
260    
261     histos = []
262     typs = []
263    
264     setup2=copy(setup)
265    
266     shapesUp = [[] for _ in range(0,len(setup2))]
267     shapesDown = [[] for _ in range(0,len(setup2))]
268    
269 nmohr 1.8 sigCount = 0
270 nmohr 1.1 for p in procs:
271 nmohr 1.2 b = opts.bin
272 nmohr 1.1 for s in setup:
273     if not Dict[s] == p: continue
274 nmohr 1.8 if 'ZH' == s or 'WH' == s:
275     if sigCount ==0:
276     Overlay=copy(theShapes[Dict[s]])
277     else:
278     Overlay.Add(theShapes[Dict[s]])
279     sigCount += 1
280 nmohr 1.1 else:
281     histos.append(theShapes[Dict[s]])
282     typs.append(s)
283     for (lsyst,nofloat,pdf,pdfargs,errline) in DC.systs:
284     if errline[b][p] == 0: continue
285 nmohr 1.7 if ("shape" in pdf) and not 'CMS_vhbb_stat' in lsyst:
286 nmohr 1.1 print 'syst %s'%lsyst
287     shapesUp[setup2.index(s)].append(theShapes[Dict[s]+lsyst+'Up'])
288     shapesDown[setup2.index(s)].append(theShapes[Dict[s]+lsyst+'Down'])
289    
290     #-------------
291     #Compute absolute uncertainty from shapes
292     counter = 0
293     for (lsyst,nofloat,pdf,pdfargs,errline) in DC.systs:
294 nmohr 1.11 sumErr = 0
295     for p in procs:
296     sumErr += errline[b][p]
297     if ("shape" in pdf) and not 'CMS_vhbb_stat' in lsyst and not sumErr == 0:
298 nmohr 1.1 theSystUp = theSyst[lsyst+'Up'].Clone()
299     theSystUp.Add(theSyst[lsyst].Clone(),-1.)
300     theSystUp.Multiply(theSystUp)
301     theSystDown = theSyst[lsyst+'Down'].Clone()
302     theSystDown.Add(theSyst[lsyst].Clone(),-1.)
303     theSystDown.Multiply(theSystDown)
304     if counter == 0:
305     theAbsSystUp = theSystUp.Clone()
306     theAbsSystDown = theSystDown.Clone()
307     else:
308     theAbsSystUp.Add(theSystUp.Clone())
309     theAbsSystDown.Add(theSystDown.Clone())
310     counter +=1
311    
312     #-------------
313     #Best fit for shapes
314 nmohr 1.4 if not preFit:
315 nmohr 1.8 histos, Overlay, typs = getBestFitShapes(procs,theShapes,shapeNui,theBestFit,DC,setup,opts,Dict)
316 nmohr 1.1
317     counter = 0
318     errUp=[]
319     total=[]
320     errDown=[]
321     nBins = histos[0].GetNbinsX()
322     print 'total bins %s'%nBins
323     Error = ROOT.TGraphAsymmErrors(histos[0])
324     theTotalMC = histos[0].Clone()
325     for h in range(1,len(histos)):
326     theTotalMC.Add(histos[h])
327    
328     total = [[]]*nBins
329     errUp = [[]]*nBins
330     errDown = [[]]*nBins
331     for bin in range(1,nBins+1):
332     binError = theTotalMC.GetBinError(bin)
333     if math.isnan(binError):
334     binError = 0.
335     total[bin-1]=theTotalMC.GetBinContent(bin)
336     #Stat uncertainty of the MC outline
337     errUp[bin-1] = [binError]
338     errDown[bin-1] = [binError]
339     #Relative norm uncertainty of the individual MC
340     for h in range(0,len(histos)):
341     errUp[bin-1].append(histos[h].GetBinContent(bin)*theNormUncert[histos[h].GetName()])
342     errDown[bin-1].append(histos[h].GetBinContent(bin)*theNormUncert[histos[h].GetName()])
343     #Shape uncertainty of the MC
344     for bin in range(1,nBins+1):
345     #print sqrt(theSystUp.GetBinContent(bin))
346     errUp[bin-1].append(sqrt(theAbsSystUp.GetBinContent(bin)))
347     errDown[bin-1].append(sqrt(theAbsSystDown.GetBinContent(bin)))
348    
349    
350     #Add all in quadrature
351     totErrUp=[sqrt(sum([x**2 for x in bin])) for bin in errUp]
352     totErrDown=[sqrt(sum([x**2 for x in bin])) for bin in errDown]
353    
354     #Make TGraph with errors
355     for bin in range(1,nBins+1):
356     if not total[bin-1] == 0:
357     point=histos[0].GetXaxis().GetBinCenter(bin)
358     Error.SetPoint(bin-1,point,1)
359     Error.SetPointEYlow(bin-1,totErrDown[bin-1]/total[bin-1])
360     print 'down %s'%(totErrDown[bin-1]/total[bin-1])
361     Error.SetPointEYhigh(bin-1,totErrUp[bin-1]/total[bin-1])
362     print 'up %s'%(totErrUp[bin-1]/total[bin-1])
363    
364     #-----------------------
365     #Read data
366 nmohr 1.2 data0 = MB.getShape(opts.bin,'data_obs')
367 nmohr 1.1 if (data0.InheritsFrom("RooDataHist")):
368 nmohr 1.12 data0 = ROOT.RooAbsData.createHistogram(data0,'data_obs',ws_var,theBinning)
369 nmohr 1.1 data0.SetName('data_obs')
370     datas=[data0]
371     datatyps = [None]
372     datanames=[dataname]
373    
374    
375     if blind:
376     for bin in range(10,datas[0].GetNbinsX()+1):
377     datas[0].SetBinContent(bin,0)
378    
379     histos.append(copy(Overlay))
380 nmohr 1.8 if 'ZH' in setup and 'WH' in setup:
381     typs.append('VH')
382     Stack.setup.remove('ZH')
383     Stack.setup.remove('WH')
384     Stack.setup.insert(0,'VH')
385     elif 'ZH' in setup:
386     typs.append('ZH')
387     elif 'WH' in setup:
388     typs.append('WH')
389 nmohr 1.1
390     Stack.histos = histos
391     Stack.typs = typs
392     Stack.datas = datas
393     Stack.datatyps = datatyps
394     Stack.datanames= datanames
395     Stack.overlay = Overlay
396     Stack.AddErrors=Error
397     Stack.lumi = lumi
398     Stack.doPlot()
399    
400     print 'i am done!\n'
401     #-------------------------------------------------
402    
403    
404     if __name__ == "__main__":
405     drawFromDC()
406     sys.exit(0)