def rooFit510(): print ">>> create and fill workspace..." workspace = RooWorkspace("workspace") # RooWorkspace fillWorkspace(workspace) print ">>>\n>>> retrieve model from workspace..." # Exploit convention encoded in named set "parameters" and "observables" # to use workspace contents w/o need for introspected model = workspace.pdf("model") # RooAbsPdf print ">>> generate and fit data in given observables" data = model.generate(workspace.set("observables"), 1000) # RooDataSet model.fitTo(data) print ">>> plot model and data of first observables..." frame1 = workspace.set("observables").first().frame() # RooPlot data.plotOn(frame1, Name("data"), Binning(50)) model.plotOn(frame1, Name("model")) print ">>> overlay plots with reference parameters as stored in snapshots..." workspace.loadSnapshot("reference_fit") model.plotOn(frame1, LineColor(kRed), Name("model_ref")) workspace.loadSnapshot("reference_fit_bkgonly") model.plotOn(frame1, LineColor(kRed), LineStyle(kDashed), Name("bkg_ref")) print "\n>>> draw on canvas..." canvas = TCanvas("canvas", "canvas", 100, 100, 800, 600) legend = TLegend(0.2, 0.8, 0.4, 0.6) legend.SetTextSize(0.032) legend.SetBorderSize(0) legend.SetFillStyle(0) gPad.SetLeftMargin(0.15) gPad.SetRightMargin(0.02) frame1.GetYaxis().SetLabelOffset(0.008) frame1.GetYaxis().SetTitleOffset(1.5) frame1.GetYaxis().SetTitleSize(0.045) frame1.GetXaxis().SetTitleSize(0.045) frame1.Draw() legend.AddEntry("data", "data", 'LEP') legend.AddEntry("model", "model", 'L') legend.AddEntry("model_ref", "model fit", 'L') legend.AddEntry("bkg_ref", "background only fit", 'L') legend.Draw() canvas.SaveAs("rooFit510.png") # Print workspace contents workspace.Print() # Workspace will remain in memory after macro finishes gDirectory.Add(workspace)
def rooFit511(compact=kFALSE): workspace = RooWorkspace("workspace") print ">>> creating and adding basic pdfs..." # Remake example pdf of tutorial rf502_wspacewrite.C: # # Basic pdf construction: ClassName::ObjectName(constructor arguments) # Variable construction: VarName[x,xlo,xhi], VarName[xlo,xhi], VarName[x] # pdf addition: SUM::ObjectName(coef1*pdf1,...coefM*pdfM,pdfN) if not compact: # Use object factory to build pdf of tutorial rooFit502_wspacewrite workspace.factory("Gaussian::sig1(x[-10,10],mean[5,0,10],0.5)") workspace.factory("Gaussian::sig2(x,mean,1)") workspace.factory("Chebychev::bkg(x,{a0[0.5,0.,1],a1[-0.2,0.,1.]})") workspace.factory("SUM::sig(sig1frac[0.8,0.,1.]*sig1,sig2)") workspace.factory("SUM::model(bkgfrac[0.5,0.,1.]*bkg,sig)") else: # Use object factory to build pdf of tutorial rf502_wspacewrite but # - Contracted to a single line recursive expression, # - Omitting explicit names for components that are not referred to explicitly later workspace.factory("SUM::model(bkgfrac[0.5,0.,1.]*Chebychev::bkg(x[-10,10],{a0[0.5,0.,1],a1[-0.2,0.,1.]}),"+\ "SUM(sig1frac[0.8,0.,1.]*Gaussian(x,mean[5,0,10],0.5),Gaussian(x,mean,1)))") print ">>> advanced pdf constructor arguments..." # pdf constructor arguments may by any type of RooAbsArg, but also the follow conversion are made: # Double_t --> RooConst(...) # {a,b,c} --> RooArgSet() or RooArgList() depending on required ctor arg # dataset name --> RooAbsData reference for any dataset residing in the workspace # enum --> any enum label that belongs to an enum defined in the (base) class print ">>> generate a dummy dataset from 'model' pdf and import it in the workspace..." data = workspace.pdf("model").generate(RooArgSet(workspace.var("x")), 1000) # RooDataSet getattr(workspace, "import")(data, Rename("data")) print ">>> construct keys pdf..." # Construct a KEYS pdf passing a dataset name and an enum type defining the # mirroring strategy workspace.factory("KeysPdf::k(x,data,NoMirror,0.2)") print ">>> workspace contents:" workspace.Print() print ">>> save workspace in memory (gDirectory)..." gDirectory.Add(workspace)
def main(options, args): gROOT.Reset() #load our super special Polarization PDF gROOT.ProcessLine('.L RooPolarizationPdf.cxx+') gROOT.ProcessLine('.L RooPolarizationConstraint.cxx+') #setup integration intConf = ROOT.RooAbsReal.defaultIntegratorConfig() #intConf.Print('v') # intConf.method1D().setLabel('RooAdaptiveGaussKronrodIntegrator1D') intConf.setEpsAbs(1e-13) intConf.setEpsRel(1e-13) print intConf.epsAbs() print intConf.epsRel() # intConf.method2D().setLabel('RooMCIntegrator') # intConf.methodND().setLabel('RooMCIntegrator') output = TFile.Open(options.workspaceName + '.root', 'RECREATE') theWS = RooWorkspace(options.workspaceName, 1) #save the polarization PDF code in the RooWorkspace theWS.importClassCode('RooPolarization*', True) buildDataAndCategories(theWS, options, args) buildMassAndLifetimePDF(theWS) # if options.fitFrame is not None: # buildPolarizationPDF(theWS,options) #root is stupid output.cd() theWS.Print('v') ROOT.RooMsgService.instance().Print() doFit(theWS, options) theWS.Write() output.Close()
def rooFit502(): print ">>> setup model components..." x = RooRealVar("x", "x", 0, 10) mean = RooRealVar("mean", "mean of gaussians", 5, 0, 10) sigma1 = RooRealVar("sigma1", "width of gaussians", 0.5) sigma2 = RooRealVar("sigma2", "width of gaussians", 1) sig1 = RooGaussian("sig1", "Signal component 1", x, mean, sigma1) sig2 = RooGaussian("sig2", "Signal component 2", x, mean, sigma2) a0 = RooRealVar("a0", "a0", 0.5, 0., 1.) a1 = RooRealVar("a1", "a1", -0.2, 0., 1.) bkg = RooChebychev("bkg", "Background", x, RooArgList(a0, a1)) print ">>> sum model components..." sig1frac = RooRealVar("sig1frac", "fraction of component 1 in signal", 0.8, 0., 1.) sig = RooAddPdf("sig", "Signal", RooArgList(sig1, sig2), RooArgList(sig1frac)) bkgfrac = RooRealVar("bkgfrac", "fraction of background", 0.5, 0., 1.) model = RooAddPdf("model", "g1+g2+a", RooArgList(bkg, sig), RooArgList(bkgfrac)) print ">>> generate data..." data = model.generate(RooArgSet(x), 1000) # RooDataSet print ">>> create workspace, import data and model..." workspace = RooWorkspace("workspace", "workspace") # empty RooWorkspace getattr(workspace, 'import')(model) # import model and all its components getattr(workspace, 'import')(data) # import data #workspace.import(model) # causes synthax error in python #workspace.import(data) # causes synthax error in python print "\n>>> print workspace contents:" workspace.Print() print "\n>>> save workspace in file..." workspace.writeToFile("rooFit502_workspace.root") print ">>> save workspace in memory (gDirectory)..." gDirectory.Add(workspace)
key_COMB = [] hist_COMB = [] for i, bin in enumerate(decaytime_binnning): if i == 0: continue start = datetime.now() dataset_COMB_CORR_dtb_init = RooDataSet("dataset_COMB_CORR_dtb_init","Decaytime bin"+str(i),dataset_COMB_CORR,varset_small,"Dst_DTF_D0_CTAU>"+str(bin[0]*ctau)+"&&Dst_DTF_D0_CTAU<"+str(bin[1]*ctau)) dataset_COMB_CORR_dtb = Subtract_Distribution(dataset_COMB_CORR_dtb_init, DTF_D0sPi_M, LOG_D0_IPCHI2_OWNPV, str(i)+"_comb", True) dataset_COMB_CORR_dtb.SetName("dataset_COMB_CORR_dtb") print "Background substraction from combinatorial tool "+str(datetime.now()-start)+" \n" hist_COMB.append(RooDataHist("hist_COMB"+str(i),"hist_COMB", RooArgSet(LOG_D0_IPCHI2_OWNPV), dataset_COMB_CORR_dtb)) key_COMB.append(RooKeysPdf("key_COMB_"+str(i), "key_COMB", LOG_D0_IPCHI2_OWNPV, dataset_COMB_CORR_dtb)) #We store shapes of Log(IPCHI2) for mathced candidates in for each decay time bins here. wspace_2 = RooWorkspace("wspace_key_shapes") wspace_2.Print("t") wsfile = TFile("/afs/cern.ch/user/"+prefix+"/"+user+"/eos/lhcb/user/"+prefix+"/"+user+"/WrongSign/2015/Secondary_Key_Shapes.root", "recreate") for k in key_COMB: wspace_2.rfimport(k) wspace_2.Write("wspace") wspace_3 = RooWorkspace("wspace_hist_shapes") wspace_3.Print("t") wsfile = TFile("/afs/cern.ch/user/"+prefix+"/"+user+"/eos/lhcb/user/"+prefix+"/"+user+"/WrongSign/2015/Secondary_Hist_Shapes.root", "recreate") for s in hist_COMB: wspace_3.rfimport(s) wspace_3.Write("wspace")
def main(): # usage description usage = "Example: ./scripts/createDatacards.py --inputData inputs/rawhistV7_Run2015D_scoutingPFHT_UNBLINDED_649_838_JEC_HLTplusV7_Mjj_cor_smooth.root --dataHistname mjj_mjjcor_gev --inputSig inputs/ResonanceShapes_gg_13TeV_Scouting_Spring15.root -f gg -o datacards -l 1866 --lumiUnc 0.027 --massrange 1000 1500 50 --runFit --p1 5 --p2 7 --p3 0.4 --massMin 838 --massMax 2037 --fitStrategy 2" # input parameters parser = ArgumentParser( description= 'Script that creates combine datacards and corresponding RooFit workspaces', epilog=usage) parser.add_argument("--inputData", dest="inputData", required=True, help="Input data spectrum", metavar="INPUT_DATA") parser.add_argument("--dataHistname", dest="dataHistname", required=True, help="Data histogram name", metavar="DATA_HISTNAME") parser.add_argument("--inputSig", dest="inputSig", required=True, help="Input signal shapes", metavar="INPUT_SIGNAL") parser.add_argument("-f", "--final_state", dest="final_state", required=True, help="Final state (e.g. qq, qg, gg)", metavar="FINAL_STATE") parser.add_argument("-f2", "--type", dest="atype", required=True, help="Type (e.g. hG, lG, hR, lR)") parser.add_argument( "-o", "--output_path", dest="output_path", required=True, help="Output path where datacards and workspaces will be stored", metavar="OUTPUT_PATH") parser.add_argument( "-l", "--lumi", dest="lumi", required=True, default=1000., type=float, help="Integrated luminosity in pb-1 (default: %(default).1f)", metavar="LUMI") parser.add_argument( "--massMin", dest="massMin", default=500, type=int, help= "Lower bound of the mass range used for fitting (default: %(default)s)", metavar="MASS_MIN") parser.add_argument( "--massMax", dest="massMax", default=1200, type=int, help= "Upper bound of the mass range used for fitting (default: %(default)s)", metavar="MASS_MAX") parser.add_argument( "--p1", dest="p1", default=5.0000e-03, type=float, help="Fit function p1 parameter (default: %(default)e)", metavar="P1") parser.add_argument( "--p2", dest="p2", default=9.1000e+00, type=float, help="Fit function p2 parameter (default: %(default)e)", metavar="P2") parser.add_argument( "--p3", dest="p3", default=5.0000e-01, type=float, help="Fit function p3 parameter (default: %(default)e)", metavar="P3") parser.add_argument( "--lumiUnc", dest="lumiUnc", required=True, type=float, help="Relative uncertainty in the integrated luminosity", metavar="LUMI_UNC") parser.add_argument("--jesUnc", dest="jesUnc", type=float, help="Relative uncertainty in the jet energy scale", metavar="JES_UNC") parser.add_argument( "--jerUnc", dest="jerUnc", type=float, help="Relative uncertainty in the jet energy resolution", metavar="JER_UNC") parser.add_argument( "--sqrtS", dest="sqrtS", default=13000., type=float, help="Collision center-of-mass energy (default: %(default).1f)", metavar="SQRTS") parser.add_argument("--fixP3", dest="fixP3", default=False, action="store_true", help="Fix the fit function p3 parameter") parser.add_argument("--runFit", dest="runFit", default=False, action="store_true", help="Run the fit") parser.add_argument("--fitBonly", dest="fitBonly", default=False, action="store_true", help="Run B-only fit") parser.add_argument("--fixBkg", dest="fixBkg", default=False, action="store_true", help="Fix all background parameters") parser.add_argument("--decoBkg", dest="decoBkg", default=False, action="store_true", help="Decorrelate background parameters") parser.add_argument("--fitStrategy", dest="fitStrategy", type=int, default=1, help="Fit strategy (default: %(default).1f)") parser.add_argument("--debug", dest="debug", default=False, action="store_true", help="Debug printout") parser.add_argument( "--postfix", dest="postfix", default='', help="Postfix for the output file names (default: %(default)s)") parser.add_argument("--pyes", dest="pyes", default=False, action="store_true", help="Make files for plots") parser.add_argument("--jyes", dest="jyes", default=False, action="store_true", help="Make files for JES/JER plots") parser.add_argument( "--pdir", dest="pdir", default='testarea', help="Name a directory for the plots (default: %(default)s)") parser.add_argument("--chi2", dest="chi2", default=False, action="store_true", help="Compute chi squared") parser.add_argument("--widefit", dest="widefit", default=False, action="store_true", help="Fit with wide bin hist") mass_group = parser.add_mutually_exclusive_group(required=True) mass_group.add_argument( "--mass", type=int, nargs='*', default=1000, help= "Mass can be specified as a single value or a whitespace separated list (default: %(default)i)" ) mass_group.add_argument( "--massrange", type=int, nargs=3, help="Define a range of masses to be produced. Format: min max step", metavar=('MIN', 'MAX', 'STEP')) mass_group.add_argument("--masslist", help="List containing mass information") args = parser.parse_args() if args.atype == 'hG': fstr = "bbhGGBB" in2 = 'bcorrbin/binmodh.root' elif args.atype == 'hR': fstr = "bbhRS" in2 = 'bcorrbin/binmodh.root' elif args.atype == 'lG': fstr = "bblGGBB" in2 = 'bcorrbin/binmodl.root' else: fstr = "bblRS" in2 = 'bcorrbin/binmodl.root' # check if the output directory exists if not os.path.isdir(os.path.join(os.getcwd(), args.output_path)): os.mkdir(os.path.join(os.getcwd(), args.output_path)) # mass points for which resonance shapes will be produced masses = [] if args.massrange != None: MIN, MAX, STEP = args.massrange masses = range(MIN, MAX + STEP, STEP) elif args.masslist != None: # A mass list was provided print "Will create mass list according to", args.masslist masslist = __import__(args.masslist.replace(".py", "")) masses = masslist.masses else: masses = args.mass # sort masses masses.sort() # import ROOT stuff from ROOT import gStyle, TFile, TH1F, TH1D, TGraph, kTRUE, kFALSE, TCanvas, TLegend, TPad, TLine from ROOT import RooHist, RooRealVar, RooDataHist, RooArgList, RooArgSet, RooAddPdf, RooFit, RooGenericPdf, RooWorkspace, RooMsgService, RooHistPdf, RooExtendPdf if not args.debug: RooMsgService.instance().setSilentMode(kTRUE) RooMsgService.instance().setStreamStatus(0, kFALSE) RooMsgService.instance().setStreamStatus(1, kFALSE) # input data file inputData = TFile(args.inputData) # input data histogram hData = inputData.Get(args.dataHistname) inData2 = TFile(in2) hData2 = inData2.Get('h_data') # input sig file inputSig = TFile(args.inputSig) sqrtS = args.sqrtS # mass variable mjj = RooRealVar('mjj', 'mjj', float(args.massMin), float(args.massMax)) # integrated luminosity and signal cross section lumi = args.lumi signalCrossSection = 1. # set to 1. so that the limit on r can be interpreted as a limit on the signal cross section for mass in masses: print ">> Creating datacard and workspace for %s resonance with m = %i GeV..." % ( args.final_state, int(mass)) # get signal shape hSig = inputSig.Get("h_" + args.final_state + "_" + str(int(mass))) # normalize signal shape to the expected event yield (works even if input shapes are not normalized to unity) hSig.Scale( signalCrossSection * lumi / hSig.Integral() ) # divide by a number that provides roughly an r value of 1-10 rooSigHist = RooDataHist('rooSigHist', 'rooSigHist', RooArgList(mjj), hSig) print 'Signal acceptance:', (rooSigHist.sumEntries() / hSig.Integral()) signal = RooHistPdf('signal', 'signal', RooArgSet(mjj), rooSigHist) signal_norm = RooRealVar('signal_norm', 'signal_norm', 0, -1e+05, 1e+05) signal_norm2 = RooRealVar('signal_norm2', 'signal_norm2', 0, -1e+05, 1e+05) signal_norm3 = RooRealVar('signal_norm3', 'signal_norm3', 0, -1e+05, 1e+05) signal_norm4 = RooRealVar('signal_norm4', 'signal_norm4', 0, -1e+05, 1e+05) signal_norm5 = RooRealVar('signal_norm5', 'signal_norm5', 0, -1e+05, 1e+05) if args.fitBonly: signal_norm.setConstant() signal_norm2.setConstant() signal_norm3.setConstant() signal_norm4.setConstant() signal_norm5.setConstant() p1 = RooRealVar('p1', 'p1', args.p1, 0., 100.) p2 = RooRealVar('p2', 'p2', args.p2, 0., 60.) p3 = RooRealVar('p3', 'p3', args.p3, -10., 10.) p4 = RooRealVar('p4', 'p4', 5.6, -50., 50.) p5 = RooRealVar('p5', 'p5', 10., -50., 50.) p6 = RooRealVar('p6', 'p6', .016, -50., 50.) p7 = RooRealVar('p7', 'p7', 8., -50., 50.) p8 = RooRealVar('p8', 'p8', .22, -50., 50.) p9 = RooRealVar('p9', 'p9', 14.1, -50., 50.) p10 = RooRealVar('p10', 'p10', 8., -50., 50.) p11 = RooRealVar('p11', 'p11', 4.8, -50., 50.) p12 = RooRealVar('p12', 'p12', 7., -50., 50.) p13 = RooRealVar('p13', 'p13', 7., -50., 50.) p14 = RooRealVar('p14', 'p14', 7., -50., 50.) p15 = RooRealVar('p15', 'p15', 1., -50., 50.) p16 = RooRealVar('p16', 'p16', 9., -50., 50.) p17 = RooRealVar('p17', 'p17', 0.6, -50., 50.) if args.fixP3: p3.setConstant() background = RooGenericPdf( 'background', '(pow(1-@0/%.1f,@1)/pow(@0/%.1f,@2+@3*log(@0/%.1f)))' % (sqrtS, sqrtS, sqrtS), RooArgList(mjj, p1, p2, p3)) dataInt = hData.Integral(hData.GetXaxis().FindBin(float(args.massMin)), hData.GetXaxis().FindBin(float(args.massMax))) background_norm = RooRealVar('background_norm', 'background_norm', dataInt, 0., 1e+08) background2 = RooGenericPdf( 'background2', '(pow(@0/%.1f,-@1)*pow(1-@0/%.1f,@2))' % (sqrtS, sqrtS), RooArgList(mjj, p4, p5)) dataInt2 = hData.Integral( hData.GetXaxis().FindBin(float(args.massMin)), hData.GetXaxis().FindBin(float(args.massMax))) background2_norm = RooRealVar('background2_norm', 'background2_norm', dataInt2, 0., 1e+08) background3 = RooGenericPdf('background3', '(1/pow(@1+@0/%.1f,@2))' % (sqrtS), RooArgList(mjj, p6, p7)) dataInt3 = hData.Integral( hData.GetXaxis().FindBin(float(args.massMin)), hData.GetXaxis().FindBin(float(args.massMax))) background3_norm = RooRealVar('background3_norm', 'background3_norm', dataInt3, 0., 1e+08) background4 = RooGenericPdf( 'background4', '(1/pow(@1+@2*@0/%.1f+pow(@0/%.1f,2),@3))' % (sqrtS, sqrtS), RooArgList(mjj, p8, p9, p10)) dataInt4 = hData.Integral( hData.GetXaxis().FindBin(float(args.massMin)), hData.GetXaxis().FindBin(float(args.massMax))) background4_norm = RooRealVar('background4_norm', 'background4_norm', dataInt4, 0., 1e+08) background5 = RooGenericPdf( 'background5', '(pow(@0/%.1f,-@1)*pow(1-pow(@0/%.1f,1/3),@2))' % (sqrtS, sqrtS), RooArgList(mjj, p11, p12)) dataInt5 = hData.Integral( hData.GetXaxis().FindBin(float(args.massMin)), hData.GetXaxis().FindBin(float(args.massMax))) background5_norm = RooRealVar('background5_norm', 'background5_norm', dataInt5, 0., 1e+08) background6 = RooGenericPdf( 'background6', '(pow(@0/%.1f,2)+@1*@0/%.1f+@2)' % (sqrtS, sqrtS), RooArgList(mjj, p13, p14)) dataInt6 = hData.Integral( hData.GetXaxis().FindBin(float(args.massMin)), hData.GetXaxis().FindBin(float(args.massMax))) background_norm6 = RooRealVar('background_norm6', 'background_norm6', dataInt6, 0., 1e+08) background7 = RooGenericPdf( 'background7', '((-1+@1*@0/%.1f)*pow(@0/%.1f,@2+@3*log(@0/%.1f)))' % (sqrtS, sqrtS, sqrtS), RooArgList(mjj, p15, p16, p17)) dataInt7 = hData.Integral( hData.GetXaxis().FindBin(float(args.massMin)), hData.GetXaxis().FindBin(float(args.massMax))) background_norm7 = RooRealVar('background_norm7', 'background_norm7', dataInt7, 0., 1e+08) #Extend PDFs exts = RooExtendPdf('extsignal', 'Extended Signal Pdf', signal, signal_norm) extb = RooExtendPdf('extbackground', 'Extended Background Pdf', background, background_norm) exts2 = RooExtendPdf('extsignal2', 'Extended Signal Pdf2', signal, signal_norm2) extb2 = RooExtendPdf('extbackground2', 'Extended Background Pdf2', background2, background2_norm) exts3 = RooExtendPdf('extsignal3', 'Extended Signal Pdf3', signal, signal_norm3) extb3 = RooExtendPdf('extbackground3', 'Extended Background Pdf3', background3, background3_norm) exts4 = RooExtendPdf('extsignal4', 'Extended Signal Pdf4', signal, signal_norm4) extb4 = RooExtendPdf('extbackground4', 'Extended Background Pdf4', background4, background4_norm) exts5 = RooExtendPdf('extsignal5', 'Extended Signal Pdf5', signal, signal_norm5) extb5 = RooExtendPdf('extbackground5', 'Extended Background Pdf5', background5, background5_norm) # S+B model model = RooAddPdf("model", "s+b", RooArgList(extb, exts)) model2 = RooAddPdf("model2", "s+b2", RooArgList(extb2, exts2)) model3 = RooAddPdf("model3", "s+b3", RooArgList(extb3, exts3)) model4 = RooAddPdf("model4", "s+b4", RooArgList(extb4, exts4)) model5 = RooAddPdf("model5", "s+b5", RooArgList(extb5, exts5)) #model6 = RooAddPdf("model6","s+b6",RooArgList(background6,signal),RooArgList(background_norm6,signal_norm)) #model7 = RooAddPdf("model7","s+b7",RooArgList(background7,signal),RooArgList(background_norm7,signal_norm)) rooDataHist = RooDataHist('rooDatahist', 'rooDathist', RooArgList(mjj), hData) if args.runFit: mframe = mjj.frame() rooDataHist.plotOn(mframe, ROOT.RooFit.Name("setonedata")) res = model.fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Extended(kTRUE), RooFit.Strategy(args.fitStrategy)) model.plotOn(mframe, ROOT.RooFit.Name("model1"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kRed)) res2 = model2.fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Extended(kTRUE), RooFit.Strategy(args.fitStrategy)) # model2.plotOn(mframe, ROOT.RooFit.Name("model2"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kOrange)) res3 = model3.fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Extended(kTRUE), RooFit.Strategy(args.fitStrategy)) # model3.plotOn(mframe, ROOT.RooFit.Name("model3"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kGreen)) res4 = model4.fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Extended(kTRUE), RooFit.Strategy(args.fitStrategy)) # model4.plotOn(mframe, ROOT.RooFit.Name("model4"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kBlue)) res5 = model5.fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Extended(kTRUE), RooFit.Strategy(args.fitStrategy)) # model5.plotOn(mframe, ROOT.RooFit.Name("model5"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kViolet)) # res6 = model6.fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Strategy(args.fitStrategy)) # model6.plotOn(mframe, ROOT.RooFit.Name("model6"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kPink)) # res7 = model7.fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Strategy(args.fitStrategy)) # model7.plotOn(mframe, ROOT.RooFit.Name("model7"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kAzure)) rooDataHist2 = RooDataHist('rooDatahist2', 'rooDathist2', RooArgList(mjj), hData2) # rooDataHist2.plotOn(mframe, ROOT.RooFit.Name("data")) if args.pyes: c = TCanvas("c", "c", 800, 800) mframe.SetAxisRange(300., 1300.) c.SetLogy() # mframe.SetMaximum(10) # mframe.SetMinimum(1) mframe.Draw() fitname = args.pdir + '/5funcfit_m' + str(mass) + fstr + '.pdf' c.SaveAs(fitname) # cpull = TCanvas("cpull","cpull",800,800) # pulls = mframe.pullHist("data","model1") # pulls.Draw("ABX") # pullname = args.pdir+'/pull_m'+str(mass)+fstr+'.pdf' # cpull.SaveAs(pullname) # cpull2 = TCanvas("cpull2","cpull2",800,800) # pulls2 = mframe.pullHist("setonedata","model1") # pulls2.Draw("ABX") # pull2name = args.pdir+'/pull2_m'+str(mass)+fstr+'.pdf' # cpull2.SaveAs(pull2name) if args.widefit: mframew = mjj.frame() rooDataHist2.plotOn(mframew, ROOT.RooFit.Name("data")) res6 = model.fitTo(rooDataHist2, RooFit.Save(kTRUE), RooFit.Strategy(args.fitStrategy)) model.plotOn(mframew, ROOT.RooFit.Name("model1"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kRed)) res7 = model2.fitTo(rooDataHist2, RooFit.Save(kTRUE), RooFit.Strategy(args.fitStrategy)) model2.plotOn(mframew, ROOT.RooFit.Name("model2"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kOrange)) res8 = model3.fitTo(rooDataHist2, RooFit.Save(kTRUE), RooFit.Strategy(args.fitStrategy)) model3.plotOn(mframew, ROOT.RooFit.Name("model3"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kGreen)) res9 = model4.fitTo(rooDataHist2, RooFit.Save(kTRUE), RooFit.Strategy(args.fitStrategy)) model4.plotOn(mframew, ROOT.RooFit.Name("model4"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kBlue)) res10 = model5.fitTo(rooDataHist2, RooFit.Save(kTRUE), RooFit.Strategy(args.fitStrategy)) model5.plotOn(mframew, ROOT.RooFit.Name("model5"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.LineWidth(1), ROOT.RooFit.LineColor(ROOT.EColor.kViolet)) if args.pyes: c = TCanvas("c", "c", 800, 800) mframew.SetAxisRange(300., 1300.) c.SetLogy() # mframew.SetMaximum(10) # mframew.SetMinimum(1) mframew.Draw() fitname = args.pdir + '/5funcfittowide_m' + str( mass) + fstr + '.pdf' c.SaveAs(fitname) cpull = TCanvas("cpull", "cpull", 800, 800) pulls = mframew.pullHist("data", "model1") pulls.Draw("ABX") pullname = args.pdir + '/pullwidefit_m' + str( mass) + fstr + '.pdf' cpull.SaveAs(pullname) if args.chi2: fullInt = model.createIntegral(RooArgSet(mjj)) norm = dataInt / fullInt.getVal() chi1 = 0. fullInt2 = model2.createIntegral(RooArgSet(mjj)) norm2 = dataInt2 / fullInt2.getVal() chi2 = 0. fullInt3 = model3.createIntegral(RooArgSet(mjj)) norm3 = dataInt3 / fullInt3.getVal() chi3 = 0. fullInt4 = model4.createIntegral(RooArgSet(mjj)) norm4 = dataInt4 / fullInt4.getVal() chi4 = 0. fullInt5 = model5.createIntegral(RooArgSet(mjj)) norm5 = dataInt5 / fullInt5.getVal() chi5 = 0. for i in range(args.massMin, args.massMax): new = 0 new2 = 0 new3 = 0 new4 = 0 new5 = 0 height = hData.GetBinContent(i) xLow = hData.GetXaxis().GetBinLowEdge(i) xUp = hData.GetXaxis().GetBinLowEdge(i + 1) obs = height * (xUp - xLow) mjj.setRange("intrange", xLow, xUp) integ = model.createIntegral( RooArgSet(mjj), ROOT.RooFit.NormSet(RooArgSet(mjj)), ROOT.RooFit.Range("intrange")) exp = integ.getVal() * norm new = pow(exp - obs, 2) / exp chi1 = chi1 + new integ2 = model2.createIntegral( RooArgSet(mjj), ROOT.RooFit.NormSet(RooArgSet(mjj)), ROOT.RooFit.Range("intrange")) exp2 = integ2.getVal() * norm2 new2 = pow(exp2 - obs, 2) / exp2 chi2 = chi2 + new2 integ3 = model3.createIntegral( RooArgSet(mjj), ROOT.RooFit.NormSet(RooArgSet(mjj)), ROOT.RooFit.Range("intrange")) exp3 = integ3.getVal() * norm3 new3 = pow(exp3 - obs, 2) / exp3 chi3 = chi3 + new3 integ4 = model4.createIntegral( RooArgSet(mjj), ROOT.RooFit.NormSet(RooArgSet(mjj)), ROOT.RooFit.Range("intrange")) exp4 = integ4.getVal() * norm4 if exp4 != 0: new4 = pow(exp4 - obs, 2) / exp4 else: new4 = 0 chi4 = chi4 + new4 integ5 = model5.createIntegral( RooArgSet(mjj), ROOT.RooFit.NormSet(RooArgSet(mjj)), ROOT.RooFit.Range("intrange")) exp5 = integ5.getVal() * norm5 new5 = pow(exp5 - obs, 2) / exp5 chi5 = chi5 + new5 print "chi1 %d " % (chi1) print "chi2 %d " % (chi2) print "chi3 %d " % (chi3) print "chi4 %d " % (chi4) print "chi5 %d " % (chi5) if not args.decoBkg: print " " res.Print() res2.Print() res3.Print() res4.Print() res5.Print() # res6.Print() # res7.Print() # decorrelated background parameters for Bayesian limits if args.decoBkg: signal_norm.setConstant() res = model.fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Strategy(args.fitStrategy)) res.Print() ## temp workspace for the PDF diagonalizer w_tmp = RooWorkspace("w_tmp") deco = PdfDiagonalizer("deco", w_tmp, res) # here diagonalizing only the shape parameters since the overall normalization is already decorrelated background_deco = deco.diagonalize(background) print "##################### workspace for decorrelation" w_tmp.Print("v") print "##################### original parameters" background.getParameters(rooDataHist).Print("v") print "##################### decorrelated parameters" # needed if want to evaluate limits without background systematics if args.fixBkg: w_tmp.var("deco_eig1").setConstant() w_tmp.var("deco_eig2").setConstant() if not args.fixP3: w_tmp.var("deco_eig3").setConstant() background_deco.getParameters(rooDataHist).Print("v") print "##################### original pdf" background.Print() print "##################### decorrelated pdf" background_deco.Print() # release signal normalization signal_norm.setConstant(kFALSE) # set the background normalization range to +/- 5 sigma bkg_val = background_norm.getVal() bkg_error = background_norm.getError() background_norm.setMin(bkg_val - 5 * bkg_error) background_norm.setMax(bkg_val + 5 * bkg_error) background_norm.Print() # change background PDF names background.SetName("background_old") background_deco.SetName("background") # needed if want to evaluate limits without background systematics if args.fixBkg: background_norm.setConstant() p1.setConstant() p2.setConstant() p3.setConstant() # ----------------------------------------- # dictionaries holding systematic variations of the signal shape hSig_Syst = {} hSig_Syst_DataHist = {} sigCDF = TGraph(hSig.GetNbinsX() + 1) # JES and JER uncertainties if args.jesUnc != None or args.jerUnc != None: sigCDF.SetPoint(0, 0., 0.) integral = 0. for i in range(1, hSig.GetNbinsX() + 1): x = hSig.GetXaxis().GetBinLowEdge(i + 1) integral = integral + hSig.GetBinContent(i) sigCDF.SetPoint(i, x, integral) if args.jesUnc != None: hSig_Syst['JESUp'] = copy.deepcopy(hSig) hSig_Syst['JESDown'] = copy.deepcopy(hSig) if args.jerUnc != None: hSig_Syst['JERUp'] = copy.deepcopy(hSig) hSig_Syst['JERDown'] = copy.deepcopy(hSig) # reset signal histograms for key in hSig_Syst.keys(): hSig_Syst[key].Reset() hSig_Syst[key].SetName(hSig_Syst[key].GetName() + '_' + key) # produce JES signal shapes if args.jesUnc != None: for i in range(1, hSig.GetNbinsX() + 1): xLow = hSig.GetXaxis().GetBinLowEdge(i) xUp = hSig.GetXaxis().GetBinLowEdge(i + 1) jes = 1. - args.jesUnc xLowPrime = jes * xLow xUpPrime = jes * xUp hSig_Syst['JESUp'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) jes = 1. + args.jesUnc xLowPrime = jes * xLow xUpPrime = jes * xUp hSig_Syst['JESDown'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) hSig_Syst_DataHist['JESUp'] = RooDataHist('hSig_JESUp', 'hSig_JESUp', RooArgList(mjj), hSig_Syst['JESUp']) hSig_Syst_DataHist['JESDown'] = RooDataHist( 'hSig_JESDown', 'hSig_JESDown', RooArgList(mjj), hSig_Syst['JESDown']) if args.jyes: c2 = TCanvas("c2", "c2", 800, 800) mframe2 = mjj.frame(ROOT.RooFit.Title("JES One Sigma Shifts")) mframe2.SetAxisRange(args.massMin, args.massMax) hSig_Syst_DataHist['JESUp'].plotOn( mframe2, ROOT.RooFit.Name("JESUP"), ROOT.RooFit.DrawOption("L"), ROOT.RooFit.DataError(2), ROOT.RooFit.LineStyle(1), ROOT.RooFit.MarkerColor(ROOT.EColor.kRed), ROOT.RooFit.LineColor(ROOT.EColor.kRed)) hSig_Syst_DataHist['JESDown'].plotOn( mframe2, ROOT.RooFit.Name("JESDOWN"), ROOT.RooFit.DrawOption("L"), ROOT.RooFit.DataError(2), ROOT.RooFit.LineStyle(1), ROOT.RooFit.MarkerColor(ROOT.EColor.kBlue), ROOT.RooFit.LineColor(ROOT.EColor.kBlue)) rooSigHist.plotOn(mframe2, ROOT.RooFit.DataError(2), ROOT.RooFit.Name("SIG"), ROOT.RooFit.DrawOption("L"), ROOT.RooFit.LineStyle(1), ROOT.RooFit.MarkerColor(ROOT.EColor.kGreen), ROOT.RooFit.LineColor(ROOT.EColor.kGreen)) mframe2.Draw() mframe2.GetXaxis().SetTitle("Dijet Mass (GeV)") leg = TLegend(0.7, 0.8, 0.9, 0.9) leg.SetFillColor(0) leg.AddEntry(mframe2.findObject("SIG"), "Signal Model", "l") leg.AddEntry(mframe2.findObject("JESUP"), "+1 Sigma", "l") leg.AddEntry(mframe2.findObject("JESDOWN"), "-1 Sigma", "l") leg.Draw() jesname = args.pdir + '/jes_m' + str(mass) + fstr + '.pdf' c2.SaveAs(jesname) # produce JER signal shapes if args.jesUnc != None: for i in range(1, hSig.GetNbinsX() + 1): xLow = hSig.GetXaxis().GetBinLowEdge(i) xUp = hSig.GetXaxis().GetBinLowEdge(i + 1) jer = 1. - args.jerUnc xLowPrime = jer * (xLow - float(mass)) + float(mass) xUpPrime = jer * (xUp - float(mass)) + float(mass) hSig_Syst['JERUp'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) jer = 1. + args.jerUnc xLowPrime = jer * (xLow - float(mass)) + float(mass) xUpPrime = jer * (xUp - float(mass)) + float(mass) hSig_Syst['JERDown'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) hSig_Syst_DataHist['JERUp'] = RooDataHist('hSig_JERUp', 'hSig_JERUp', RooArgList(mjj), hSig_Syst['JERUp']) hSig_Syst_DataHist['JERDown'] = RooDataHist( 'hSig_JERDown', 'hSig_JERDown', RooArgList(mjj), hSig_Syst['JERDown']) if args.jyes: c3 = TCanvas("c3", "c3", 800, 800) mframe3 = mjj.frame(ROOT.RooFit.Title("JER One Sigma Shifts")) mframe3.SetAxisRange(args.massMin, args.massMax) hSig_Syst_DataHist['JERUp'].plotOn( mframe3, ROOT.RooFit.Name("JERUP"), ROOT.RooFit.DrawOption("L"), ROOT.RooFit.DataError(2), ROOT.RooFit.LineStyle(1), ROOT.RooFit.MarkerColor(ROOT.EColor.kRed), ROOT.RooFit.LineColor(ROOT.EColor.kRed)) hSig_Syst_DataHist['JERDown'].plotOn( mframe3, ROOT.RooFit.Name("JERDOWN"), ROOT.RooFit.DrawOption("L"), ROOT.RooFit.DataError(2), ROOT.RooFit.LineStyle(1), ROOT.RooFit.MarkerColor(ROOT.EColor.kBlue), ROOT.RooFit.LineColor(ROOT.EColor.kBlue)) rooSigHist.plotOn(mframe3, ROOT.RooFit.DrawOption("L"), ROOT.RooFit.Name("SIG"), ROOT.RooFit.DataError(2), ROOT.RooFit.LineStyle(1), ROOT.RooFit.MarkerColor(ROOT.EColor.kGreen), ROOT.RooFit.LineColor(ROOT.EColor.kGreen)) mframe3.Draw() mframe3.GetXaxis().SetTitle("Dijet Mass (GeV)") leg = TLegend(0.7, 0.8, 0.9, 0.9) leg.SetFillColor(0) leg.AddEntry(mframe3.findObject("SIG"), "Signal Model", "l") leg.AddEntry(mframe3.findObject("JERUP"), "+1 Sigma", "l") leg.AddEntry(mframe3.findObject("JERDOWN"), "-1 Sigma", "l") leg.Draw() jername = args.pdir + '/jer_m' + str(mass) + fstr + '.pdf' c3.SaveAs(jername) # ----------------------------------------- # create a datacard and corresponding workspace postfix = (('_' + args.postfix) if args.postfix != '' else '') dcName = 'datacard_' + args.final_state + '_m' + str( mass) + postfix + '.txt' wsName = 'workspace_' + args.final_state + '_m' + str( mass) + postfix + '.root' w = RooWorkspace('w', 'workspace') getattr(w, 'import')(rooSigHist, RooFit.Rename("signal")) if args.jesUnc != None: getattr(w, 'import')(hSig_Syst_DataHist['JESUp'], RooFit.Rename("signal__JESUp")) getattr(w, 'import')(hSig_Syst_DataHist['JESDown'], RooFit.Rename("signal__JESDown")) if args.jerUnc != None: getattr(w, 'import')(hSig_Syst_DataHist['JERUp'], RooFit.Rename("signal__JERUp")) getattr(w, 'import')(hSig_Syst_DataHist['JERDown'], RooFit.Rename("signal__JERDown")) if args.decoBkg: getattr(w, 'import')(background_deco, ROOT.RooCmdArg()) else: getattr(w, 'import')(background, ROOT.RooCmdArg(), RooFit.Rename("background")) getattr(w, 'import')(background2, ROOT.RooCmdArg(), RooFit.Rename("background2")) getattr(w, 'import')(background3, ROOT.RooCmdArg(), RooFit.Rename("background3")) getattr(w, 'import')(background4, ROOT.RooCmdArg(), RooFit.Rename("background4")) getattr(w, 'import')(background5, ROOT.RooCmdArg(), RooFit.Rename("background5")) getattr(w, 'import')(background_norm, ROOT.RooCmdArg(), RooFit.Rename("background_norm")) getattr(w, 'import')(background2_norm, ROOT.RooCmdArg(), RooFit.Rename("background2_norm")) getattr(w, 'import')(background3_norm, ROOT.RooCmdArg(), RooFit.Rename("background3_norm")) getattr(w, 'import')(background4_norm, ROOT.RooCmdArg(), RooFit.Rename("background4_norm")) getattr(w, 'import')(background5_norm, ROOT.RooCmdArg(), RooFit.Rename("background5_norm")) getattr(w, 'import')(res) getattr(w, 'import')(res2) getattr(w, 'import')(res3) getattr(w, 'import')(res4) getattr(w, 'import')(res5) getattr(w, 'import')(background_norm, ROOT.RooCmdArg()) getattr(w, 'import')(signal_norm, ROOT.RooCmdArg()) getattr(w, 'import')(rooDataHist, RooFit.Rename("data_obs")) w.Print() w.writeToFile(os.path.join(args.output_path, wsName)) beffUnc = 0.3 boffUnc = 0.06 datacard = open(os.path.join(args.output_path, dcName), 'w') datacard.write('imax 1\n') datacard.write('jmax 1\n') datacard.write('kmax *\n') datacard.write('---------------\n') if args.jesUnc != None or args.jerUnc != None: datacard.write('shapes * * ' + wsName + ' w:$PROCESS w:$PROCESS__$SYSTEMATIC\n') else: datacard.write('shapes * * ' + wsName + ' w:$PROCESS\n') datacard.write('---------------\n') datacard.write('bin 1\n') datacard.write('observation -1\n') datacard.write('------------------------------\n') datacard.write('bin 1 1\n') datacard.write('process signal background\n') datacard.write('process 0 1\n') datacard.write('rate -1 1\n') datacard.write('------------------------------\n') datacard.write('lumi lnN %f -\n' % (1. + args.lumiUnc)) datacard.write('beff lnN %f -\n' % (1. + beffUnc)) datacard.write('boff lnN %f -\n' % (1. + boffUnc)) datacard.write('bkg lnN - 1.03\n') if args.jesUnc != None: datacard.write('JES shape 1 -\n') if args.jerUnc != None: datacard.write('JER shape 1 -\n') # flat parameters --- flat prior datacard.write('background_norm flatParam\n') if args.decoBkg: datacard.write('deco_eig1 flatParam\n') datacard.write('deco_eig2 flatParam\n') if not args.fixP3: datacard.write('deco_eig3 flatParam\n') else: datacard.write('p1 flatParam\n') datacard.write('p2 flatParam\n') if not args.fixP3: datacard.write('p3 flatParam\n') datacard.close() print '>> Datacards and workspaces created and stored in %s/' % ( os.path.join(os.getcwd(), args.output_path))
def DataFit(free=True, sim=True): w = RooWorkspace('w_data', 'w_data') samples = ['b0g', 'b0pi0', 'bsg', 'bspi0'] # create the category w.factory('cat[%s]' % (','.join(samples))) files = { 'b0g': path + "B0gamma/9_B2DstKpi_Dst2DgammTuple_BestCut.root", 'b0pi0': path + "B0pi0/9_B2Dstpi0Tuple_BestCut.root", 'bsg': path + "Bsgamma/9_Bs2DstKpi_Dst2DgammaTuple_BestCut.root", 'bspi0': path + "Bspi0/9_Bs2Dstpi0Tuple_BestCut.root" } # Make the dsets w.factory("B_DTFDict_D0_B_M[5100,5900]") w.var("B_DTFDict_D0_B_M").setBins(80) for samp in samples: assert (os.path.exists(files[samp])) tf = TFile(files[samp]) t = tf.Get('DecayTree') t.SetBranchStatus("*", 0) t.SetBranchStatus("B_DTFDict_D0_B_M", 1) dset = RooDataSet("data_%s" % (samp), "", t, RooArgSet(w.var("B_DTFDict_D0_B_M"))) getattr(w, 'import')(dset) tf.Close() # Make the total pdf # First try and merge the different bits from the different workspaces ImportMCShapes(w) # Then make combinatorial shape in each cateogry # let these be independent for now for samp in samples: w.factory("comb_mc_%s_p0[-0.001,-0.1,0.]" % samp) w.factory( "Exponential::comb_mc_pdf_%s( B_DTFDict_D0_B_M, comb_mc_%s_p0 )" % (samp, samp)) w.factory("%s_comb_y[3000,0,12000]" % samp) # Now need to figure out what yields to restrict # sig yield first (require b0 / bs ratio consistent between g and pi0) w.factory("b0g_sig_y[3000,0,12000]") w.factory("b0pi0_sig_y[800,0,4000]") w.factory("bs2b0_rat[2.5,1.,4.]") w.factory("prod::bsg_sig_y(b0g_sig_y, bs2b0_rat)") w.factory("prod::bspi0_sig_y(b0pi0_sig_y, bs2b0_rat)") # now mis rec yield (ratio of this to sig should be the same for b0 and bs but will be different for g vs pi0) w.factory("misrec_to_sig_rat_g[0.2,0.001,0.6]") w.factory("misrec_to_sig_rat_pi0[0.2,0.001,0.6]") w.factory("prod::b0g_misrec_y( misrec_to_sig_rat_g, b0g_sig_y )") w.factory("prod::b0pi0_misrec_y( misrec_to_sig_rat_pi0, b0pi0_sig_y )") w.factory("prod::bsg_misrec_y( misrec_to_sig_rat_g, bsg_sig_y )") w.factory("prod::bspi0_misrec_y( misrec_to_sig_rat_pi0, bspi0_sig_y )") # the cases of B->D*pipi, B->D*KK, Lb->D*ph all involve a misID so will # be different for B0 and Bs (as they differ with a K or pi misID) however # for all of these the ratio of g -> pi0 should be the same # there is also Bs->D*KK which should scale the same for g and pi0 modes w.factory("misid_g2pi0_rat[0.1,0.0001,10.]") w.factory("b0g_bdstpp_y[1000,0,12000]") w.factory("bsg_bdstpp_y[1000,0,12000]") w.factory("prod::b0pi0_bdstpp_y( misid_g2pi0_rat, b0g_bdstpp_y )") w.factory("prod::bspi0_bdstpp_y( misid_g2pi0_rat, bsg_bdstpp_y )") w.factory("b0g_bdstkk_y[1000,0,12000]") w.factory("bsg_bdstkk_y[1000,0,12000]") w.factory("prod::b0pi0_bdstkk_y( misid_g2pi0_rat, b0g_bdstkk_y )") w.factory("prod::bspi0_bdstkk_y( misid_g2pi0_rat, bsg_bdstkk_y )") w.factory("b0g_lbdstph_y[1000,0,12000]") w.factory("bsg_lbdstph_y[1000,0,12000]") w.factory("prod::b0pi0_lbdstph_y( misid_g2pi0_rat, b0g_lbdstph_y )") w.factory("prod::bspi0_lbdstph_y( misid_g2pi0_rat, bsg_lbdstph_y )") w.factory("bsdstkk_to_bdstkk_rat[1.,0.1,2.]") w.factory("prod::b0g_bsdstkk_y( bsdstkk_to_bdstkk_rat, b0g_bdstkk_y )") w.factory("prod::b0pi0_bsdstkk_y( bsdstkk_to_bdstkk_rat, b0pi0_bdstkk_y )") w.factory("prod::bsg_bsdstkk_y( bsdstkk_to_bdstkk_rat, bsg_bdstkk_y )") w.factory("prod::bspi0_bsdstkk_y( bsdstkk_to_bdstkk_rat, bspi0_bdstkk_y )") # B -> DKpi same logic as misrec w.factory("bdkp_to_sig_rat_g[0.2,0.001,0.6]") w.factory("bdkp_to_sig_rat_pi0[0.2,0.001,0.6]") w.factory("prod::b0g_bdkp_y( bdkp_to_sig_rat_g, b0g_sig_y )") w.factory("prod::b0pi0_bdkp_y( bdkp_to_sig_rat_pi0, b0pi0_sig_y )") w.factory("prod::bsg_bdkp_y( bdkp_to_sig_rat_g, bsg_sig_y )") w.factory("prod::bspi0_bdkp_y( bdkp_to_sig_rat_pi0, bspi0_sig_y )") # B -> D* K / B -> D* pi (adding random pi- to B0 and random K- to Bs0) # so ratio to signal should be same for both g and pi0 modes but # different for B0 -> Bs w.factory("bdsth_to_sig_rat_addpi[0.2,0.001,0.6]") w.factory("bdsth_to_sig_rat_addk[0.2,0.001,0.6]") w.factory("prod::b0g_bdsth_y( bdsth_to_sig_rat_addpi, b0g_sig_y )") w.factory("prod::b0pi0_bdsth_y( bdsth_to_sig_rat_addpi, b0pi0_sig_y )") w.factory("prod::bsg_bdsth_y( bdsth_to_sig_rat_addk, bsg_sig_y )") w.factory("prod::bspi0_bdsth_y( bdsth_to_sig_rat_addk, bspi0_sig_y )") # Lb -> Dph (mid-ID k for p and pi for p and add random g or pi0) so will be different for all 4 really # express this ratio to the Lb -> D*ph one (they should be similar in magnitude?) w.factory("lbdph_to_lbdstph_b0g[1.,0.5,2.]") w.factory("lbdph_to_lbdstph_b0pi0[1.,0.5,2.]") w.factory("lbdph_to_lbdstph_bsg[1.,0.5,2.]") w.factory("lbdph_to_lbdstph_bspi0[1.,0.5,2.]") w.factory("prod::b0g_lbdph_y( lbdph_to_lbdstph_b0g, b0g_lbdstph_y )") w.factory("prod::b0pi0_lbdph_y( lbdph_to_lbdstph_b0pi0, b0pi0_lbdstph_y )") w.factory("prod::bsg_lbdph_y( lbdph_to_lbdstph_bsg, bsg_lbdstph_y )") w.factory("prod::bspi0_lbdph_y( lbdph_to_lbdstph_bspi0, bspi0_lbdstph_y )") # Part reco shape should have same Bs / B0 ratio w.factory("partrec_to_sig_rat_g[0.2,0.001,0.6]") w.factory("partrec_to_sig_rat_pi0[0.2,0.001,0.6]") w.factory("prod::b0g_partrec_y( partrec_to_sig_rat_g, b0g_sig_y )") w.factory("prod::b0pi0_partrec_y( partrec_to_sig_rat_pi0, b0pi0_sig_y )") w.factory("prod::bsg_partrec_y( partrec_to_sig_rat_g, bsg_sig_y )") w.factory("prod::bspi0_partrec_y( partrec_to_sig_rat_pi0, bspi0_sig_y )") components = [ 'sig', 'misrec', 'bdstpp', 'bdstkk', 'bsdstkk', 'bdkp', 'bdsth', 'partrec', 'lbdph', 'lbdstph', 'comb' ] for samp in samples: fact_str = "SUM::data_pdf_%s(" % samp for comp in components: fact_str += "%s_%s_y*%s_mc_pdf_%s," % (samp, comp, comp, samp) fact_str = fact_str[:-1] + ")" w.factory(fact_str) w.pdf('data_pdf_%s' % samp).Print('v') CreateSimPdf(w, 'data') CreateSimData(w, 'data') # Now fix appropriate parameters # To start with we'll fix all shape parameters from MC and just float the yields (and exponential slope) for comp in components: if comp == 'comb': continue # no pre-defined shape for combinatorial if comp == 'bsdstkk': continue # this params for this piece are covered by bdstkk w.set('%s_mc_sim_pdf_pars' % comp).setAttribAll("Constant") # Now relax the constraints on a few important params w.var("b0g_mean").setConstant(False) w.var("b0g_sigma").setConstant(False) #w.var("dm_b02bs").setConstant(False) #w.var("dm_g2pi0").setConstant(False) #w.var("ssig_b02bs").setConstant(False) #w.var("ssig_g2pi0").setConstant(False) #w.var("b0g_misrec_mean").setConstant(False) #w.var("b0g_misrec_sigma").setConstant(False) #w.var("dm_missg2addg").setConstant(False) #w.var("ssig_missg2addg").setConstant(False) w.Print('v') w.pdf('data_sim_pdf').Print('v') w.data('data_sim_data').Print('v') # free fit first if free: for i, samp in enumerate(samples): pdfname = 'data_pdf_%s' % (samp) dsetname = 'data_%s' % (samp) w.pdf(pdfname).fitTo( w.data(dsetname)) # nothing to fit in this case pars = w.pdf(pdfname).getParameters( RooArgSet(w.var("B_DTFDict_D0_B_M"))) w.saveSnapshot('data_free_fit_%s' % samp, pars) if sim: pdfname = 'data_sim_pdf' dsetname = 'data_sim_data' w.pdf(pdfname).fitTo(w.data(dsetname)) pars = w.pdf(pdfname).getParameters( RooArgSet(w.var("B_DTFDict_D0_B_M"))) w.saveSnapshot('data_sim_fit', pars) w.writeToFile('files/w_data.root')
# dataHist.Print() # dataHist.Draw('colz') # gPad.Update() # gPad.WaitPrimitive() theWS = RooWorkspace() theWS.factory('%s[%f,%f]' % (params.var[0], params.varRanges[params.var[0]][1], params.varRanges[params.var[0]][2])) theWS.factory('%s[%f,%f]' % (params.var[1], params.varRanges[params.var[1]][1], params.varRanges[params.var[1]][2])) theWS.defineSet('obsSet', ','.join(params.var)) #theWS.Print() # utils.Hist2Pdf(dataHist, "H250SignalHist", theWS) #theWS.Print() # dataset = utils.File2Dataset(params.MCDirectory + \ # 'RD_mu_HWWMH250_CMSSW525_private.root', # "H250SignalData", theWS) # dataset.Print() print for model in range(10): utils.analyticPdf(theWS, params.var[0], model, 'pdf_%i' % model, '%i_%s' % (model, params.var[0])) theWS.Print()
class MjjFit: def __init__(self, mass_range=[0., 2000.]): self.data_histogram_ = None self.data_roohistogram_ = None self.luminosity_ = 0. self.collision_energy_ = 8000. self.signal_histograms_ = {} self.signal_roohistograms_ = {} self.signal_names_ = [] # Fit storage self.simple_fit_ = None self.mjj_ = RooRealVar('mjj','mjj',float(mass_range[0]),float(mass_range[1])) self.workspace_ = None def add_data(self, data_histogram): print "[MjFit.add_data] INFO : Adding data histogram" # Add a data histogram self.data_histogram_ = data_histogram.Clone() self.data_histogram_.SetDirectory(0) self.data_roohistogram_ = RooDataHist('data_roohistogram','data_roohistogram',RooArgList(self.mjj_),self.data_histogram_) self.data_roohistogram_.Print() def add_signal(self, signal_name, signal_histogram): print "[MjjFit.add_signal] INFO : Adding signal histogram " + signal_name # Add a signal histogram. # Scale to sigma=1 (in whatever units the data luminosity is given in), so the 'r' parameter corresponds to the limit on the cross section. if self.luminosity_ == 0: print "[MjjFit.add_signal] ERROR : Please set luminosity first (MjjFit.set_luminosity(###))." sys.exit(1) self.signal_names_.append(signal_name) self.signal_histograms_[signal_name] = signal_histogram.Clone() self.signal_histograms_[signal_name].SetDirectory(0) self.signal_histograms_[signal_name].Scale(1. * self.luminosity_ / self.signal_histograms_[signal_name].Integral()) self.signal_roohistograms_[signal_name] = RooDataHist(signal_histogram.GetName() + "_rdh", signal_histogram.GetName() + "_rdh", RooArgList(self.mjj_), signal_histograms[signal_name]) self.signal_roohistograms_[signal_name].Print() def simple_fit_B(self, fit_range=None): # Run a simple ROOT fit (B only) # - No S+B equivalent. This is done with RooFit. if fit_range: fit_min = fit_range[0] fit_max = fit_range[1] else: fit_min = data_histogram.GetXaxis().GetXmin() fit_max = data_histogram.GetXaxis().GetXmax() fit = TF1(data_histogram.GetName() + "_fit_B", BackgroundFit, fit_min, fit_max, 4) fit.SetParameter(0, 2.e-4) fit.SetParameter(1, 3) fit.SetParameter(2, 10) fit.SetParameter(3, 1) fit.SetParLimits(0, 1.e-6, 1.e2) fit.SetParLimits(1, -25., 25.) fit.SetParLimits(2, -25., 25.) fit.SetParLimits(3, -5., 5.) data_histogram.Fit(fit, "ER0I") fit_ratio = self.make_fit_pull_histogram(data_histogram, fit) print "Fit chi2/ndf = " + str(fit.GetChisquare()) + " / " + str(fit.GetNDF()) + " = " + str(fit.GetChisquare() / fit.GetNDF()) self.simple_fit_ = {"fit":fit, "fit_ratio":fit_ratio} return self.simple_fit_ def make_fit_pull_histogram(self, hist, fit): #print "Fit xmin = " + str(fit.GetXmin()) hist_ratio = hist.Clone() hist_ratio.SetName(hist.GetName() + "_fit_ratio") for bin in xrange(1, hist_ratio.GetNbinsX() + 1): xmin = hist_ratio.GetXaxis().GetBinLowEdge(bin) xmax = hist_ratio.GetXaxis().GetBinUpEdge(bin) if xmax < fit.GetXmin() or xmin > fit.GetXmax(): hist_ratio.SetBinContent(bin, 0.) hist_ratio.SetBinError(bin, 0.) continue fit_integral = fit.Integral(xmin, xmax) if hist.GetBinError(bin) > 0: hist_ratio.SetBinContent(bin, (hist.GetBinContent(bin) * hist.GetBinWidth(bin) - fit_integral) / (hist.GetBinError(bin) * hist.GetBinWidth(bin))) hist_ratio.SetBinError(bin, 0.) else: hist_ratio.SetBinContent(bin, 0.) hist_ratio.SetBinError(bin, 0.) return hist_ratio def fit(self, save_to, signal_name=None, fix_p3=False, fit_range=[300., 1200.], fit_strategy=1): # Run a RooFit fit # Create background PDF p1 = RooRealVar('p1','p1',args.p1,0.,100.) p2 = RooRealVar('p2','p2',args.p2,0.,60.) p3 = RooRealVar('p3','p3',args.p3,-10.,10.) if args.fix_p3: p3.setConstant() background_pdf = RooGenericPdf('background_pdf','(pow(1-@0/%.1f,@1)/pow(@0/%.1f,@2+@3*log(@0/%.1f)))'%(self.collision_energy,self.collision_energy,self.collision_energy),RooArgList(self.mjj_,p1,p2,p3)) background_pdf.Print() data_integral = data_histogram.Integral(data_histogram.GetXaxis().FindBin(float(fit_range[0])),data_histogram.GetXaxis().FindBin(float(fit_range[1]))) background_norm = RooRealVar('background_norm','background_norm',data_integral,0.,1e+08) background_norm.Print() # Create signal PDF and fit model if signal_name: signal_pdf = RooHistPdf('signal_pdf', 'signal_pdf', RooArgSet(self.mjj_), self.signal_roohistograms_[signal_name]) signal_pdf.Print() signal_norm = RooRealVar('signal_norm','signal_norm',0,-1e+05,1e+05) signal_norm.Print() model = RooAddPdf("model","s+b",RooArgList(background_pdf,signal_pdf),RooArgList(background_norm,signal_norm)) else: model = RooAddPdf("model","b",RooArgList(background_pdf),RooArgList(background_norm)) # Run fit res = model.fitTo(data_, RooFit.Save(kTRUE), RooFit.Strategy(fit_strategy)) # Save to workspace self.workspace_ = RooWorkspace('w','workspace') #getattr(w,'import')(background,ROOT.RooCmdArg()) getattr(self.workspace_,'import')(background_pdf,RooFit.Rename("background")) getattr(self.workspace_,'import')(background_norm,ROOT.RooCmdArg()) getattr(self.workspace_,'import')(self.data_roohistogram_,RooFit.Rename("data_obs")) getattr(self.workspace_, 'import')(model, RooFit.Rename("model")) if signal_name: getattr(self.workspace_,'import')(signal_roohistogram,RooFit.Rename("signal")) getattr(self.workspace_,'import')(signal_pdf,RooFit.Rename("signal_pdf")) getattr(self.workspace_,'import')(signal_norm,ROOT.RooCmdArg()) self.workspace_.Print() self.workspace_.writeToFile(save_to) if signal_name: roofit_results[signal_name] = save_to else: roofit_results["background"] = save_to # fitted_signal_shapes = list of fitted S(+B) shapes to plot. # expected_signal_shapes = list of S shapes to plot, scaled to cross sections taken from configuration file def plot(self, save_tag, fitted_signal_shapes=None, expected_signal_shapes=None, log=False, x_range=None): c = TCanvas("c_" + save_tag, "c_" + save_tag, 800, 1600) l = TLegend(0.55, 0.6, 0.88, 0.88) l.SetFillColor(0) l.SetBorderSize(0) top = TPad("top", "top", 0., 0.5, 1., 1.) top.SetBottomMargin(0.03) top.Draw() if log: top.SetLogy() c.cd() bottom = TPad("bottom", "bottom", 0., 0., 1., 0.5) bottom.SetTopMargin(0.02) bottom.SetBottomMargin(0.2) bottom.Draw() ROOT.SetOwnership(c, False) ROOT.SetOwnership(top, False) ROOT.SetOwnership(bottom, False) top.cd() # Frame from background fit if not roofit_results.has_key("background"): print "[MjjFit.plot] ERROR : Please run background-only fit before plotting (e.g. MjjFit.plot(\"bkgd_file.root\"))" f_background = TFile(roofit_results["background"], "READ") w_background = f_background.Get("w") data_rdh = w_background.data("data_obs") if x_range: x_min = x_range[0] x_max = x_range[1] else: x_min = self.mjj_.GetMin() x_max = self.mjj_.GetMax() frame_top = self.mjj_.frame(x_min, x_max) frame_top.GetYaxis().SetTitle("Events / " + str(int(data_histogram.GetXaxis().GetBinWidth(1))) + " GeV") frame_top.GetXaxis().SetTitleSize(0) frame_top.GetXaxis().SetLabelSize(0) #if log: # frame_top.SetMaximum(y_max * 10.) # frame_top.SetMinimum(y_min / 100.) #else: # frame_top.SetMaximum(y_max * 1.3) # frame_top.SetMinimum(0.) frame_top.Draw() data_rdh.plotOn(frame_top, RooFit.Name("Data")) l.AddEntry(frame_top.findObject("Data"), "Data", "pl") background_pdf = w_background.pdf("background") background_pdf.plotOn(frame_top, RooFit.Name("Background Fit"), RooFit.LineColor(seaborn.GetColorRoot("default", 0)), RooFit.LineStyle(1), RooFit.LineWidth(2)) style_counter = 1 if fitted_signal_shapes: for signal_name in fitted_signal_shapes: # Load from workspace if not roofit_results.has_key(signal_name): print "[MjjFit.plot] ERROR : Signal name " + signal_name + " does not exist in roofit_results. Did you run the fit first?" sys.exit(1) f_in = TFile(roofit_results[signal_name], "READ") w = f_in.Get("workspace") fit_pdf = w.pdf("model") fit_pdf_name = "Fit (" + signal_name + ")" fit_pdf.SetName(fit_pdf_name) fit_pdf.plotOn(frame_top, RooFit.Name(fit_pdf_name), RooFit.LineColor(seaborn.GetColorRoot("default", style_counter)), RooFit.LineStyle(1), RooFit.LineWidth(2)) l.AddEntry(frame_top.findObject(signal_name), signal_name, "l") style_counter += 1 f_in.Close() if expected_signal_shapes: for signal_name in expected_signal_shapes: self.signal_roohistograms_[signal_name].plotOn(frame_top, RooFit.Name(signal_name), RooFit.Rescale(cross_section * self.luminosity_ / self.signal_roohistograms_[signal_name].sum()), RooFit.LineColor(seaborn.GetColorRoot("pastel", style_counter)), RooFit.LineStyle(2), RooFit.LineWidth(2)) l.AddEntry(frame_top.findObject(signal_name), signal_name, "l") style_counter += 1 frame_top.Draw() l.Draw() # Pull histogram c.cd() bottom.cd() pull_histogram = frame_top.pullHist("Data", "Background Fit") frame_bottom = self.mjj_.frame(x_min, x_max) pull_histogram.plotOn(frame_bottom, RooFit.Name(fit_pdf_name)) frame_bottom.GetXaxis().SetTitle("m_{jj} [GeV]") frame_bottom.GetYaxis().SetTitle("#frac{Data - Fit}{#sigma(Fit)}") frame_bottom.Draw() c.cd() c.SaveAs("/uscms/home/dryu/Dijets/data/EightTeeEeVeeBee/Results/figures/c_" + save_tag + ".pdf")
def shapeCards( process, isData, datahistosFile, histosFile, signalHistosFile, signalSample, hist, signalMass, minMass, maxMass, jesValue, jerValue, lumiUnc, outputName ): """function to run Roofit and save workspace for RooStats""" warnings.filterwarnings( action='ignore', category=RuntimeWarning, message='.*class stack<RooAbsArg\*,deque<RooAbsArg\*> >' ) hSignal = signalHistosFile.Get(hist+'_'+signalSample) hSignal.Rebin(10) htmpSignal = hSignal.Clone() #htmpSignal.Scale(100) signalXS = search(dictXS, 'RPVStopStopToJets_UDD312_M-'+str(signalMass) ) #hSignal.Scale( lumi*signalXS / hSignal.Integral()) massAve = RooRealVar( 'massAve', 'massAve', minMass, maxMass ) rooSigHist = RooDataHist( 'rooSigHist', 'rooSigHist', RooArgList(massAve), hSignal ) rooSigHist.Print() signal = RooHistPdf('signal','signal',RooArgSet(massAve),rooSigHist) signal.Print() signal_norm = RooRealVar('signal_norm','signal_norm',0,-1e+04,1e+04) #if args.fitBonly: signal_norm.setConstant() signal_norm.Print() hBkg = datahistosFile.Get('massAve_prunedMassAsymVsdeltaEtaDijet_DATA_ABCDProj') #hBkg = histosFile.Get(hist+'_QCDPtAll_BCD') bkgAcc = round(hBkg.Integral( hBkg.GetXaxis().FindBin( minMass ), hBkg.GetXaxis().FindBin( maxMass ))) #hBkg.Scale(1/hBkg.Integral()) hPseudo = hBkg.Clone() hPseudo.Reset() #background_norm = RooRealVar('background_norm','background_norm',bkgAcc,0.,1e+07) background_norm = RooRealVar('background_norm','background_norm',1.,0.,1e+07) background_norm.Print() if 'template' in process: rooBkgHist = RooDataHist( 'rooBkgHist', 'rooBkgHist', RooArgList(massAve), hBkg ) rooBkgHist.Print() background = RooHistPdf('background','background',RooArgSet(massAve),rooBkgHist) background.Print() else: p1 = RooRealVar('p1','p1', 1 ,0.,100.) p2 = RooRealVar('p2','p2', 1 ,0.,60.) p3 = RooRealVar('p3','p3', 1 , -10.,10.) background = RooGenericPdf('background','(pow(1-@0/%.1f,@1)/pow(@0/%.1f,@2+@3*log(@0/%.1f)))'%(1300,1300,1300),RooArgList(massAve,p1,p2,p3)) background.Print() ### S+B model if not isData: newNumEvents = random.randint( bkgAcc-round(TMath.Sqrt(bkgAcc)), bkgAcc+round(TMath.Sqrt(bkgAcc)) ) print 'Events in MC:', bkgAcc, ', in PseudoExperiment:', newNumEvents hPseudo.FillRandom( hBkg, newNumEvents ) #hPseudo.Scale(1/hPseudo.Integral()) #hData = histosFile.Get('massAve_prunedMassAsymVsdeltaEtaDijet_ABCDProj') hData = datahistosFile.Get('massAve_prunedMassAsymVsdeltaEtaDijet_DATA_ABCDProj') #hData = histosFile.Get(hist+'_QCDPtAll_A') #hData.Add(htmpSignal) #hData.Scale(1/hData.Integral()) rooDataHist = RooDataHist('rooDatahist','rooDatahist',RooArgList(massAve), hData if isData else hPseudo ) rooDataHist.Print() #model = RooAddPdf("model","s+b",RooArgList(background,signal),RooArgList(background_norm,signal_norm)) #res = model.fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Strategy(0)) #res.Print() ############# JES and JER uncertainties hSigSyst = {} hSigSystDataHist = {} signalCDF = TGraph(hSignal.GetNbinsX()+1) # JES and JER uncertainties if args.jesUnc or args.jerUnc: signalCDF.SetPoint(0,0.,0.) integral = 0. for i in range(1, hSignal.GetNbinsX()+1): x = hSignal.GetXaxis().GetBinLowEdge(i+1) integral = integral + hSignal.GetBinContent(i) signalCDF.SetPoint(i,x,integral) if args.jesUnc: print ' |---> Adding JES' hSigSyst['JESUp'] = hSignal.Clone() hSigSyst['JESDown'] = hSignal.Clone() if args.jerUnc: print ' |---> Adding JER' hSigSyst['JERUp'] = hSignal.Clone() hSigSyst['JERDown'] = hSignal.Clone() # reset signal histograms for key in hSigSyst: hSigSyst[key].Reset() hSigSyst[key].SetName(hSigSyst[key].GetName() + '_' + key) # produce JES signal shapes if args.jesUnc: for q in range(1, hSignal.GetNbinsX()+1): xLow = hSignal.GetXaxis().GetBinLowEdge(q) xUp = hSignal.GetXaxis().GetBinLowEdge(q+1) jes = 1. - jesValue xLowPrime = jes*xLow xUpPrime = jes*xUp hSigSyst['JESUp'].SetBinContent(q, signalCDF.Eval(xUpPrime) - signalCDF.Eval(xLowPrime)) jes = 1. + jesValue xLowPrime = jes*xLow xUpPrime = jes*xUp hSigSyst['JESDown'].SetBinContent(q, signalCDF.Eval(xUpPrime) - signalCDF.Eval(xLowPrime)) hSigSystDataHist['JESUp'] = RooDataHist('hSignalJESUp','hSignalJESUp',RooArgList(massAve),hSigSyst['JESUp']) hSigSystDataHist['JESDown'] = RooDataHist('hSignalJESDown','hSignalJESDown',RooArgList(massAve),hSigSyst['JESDown']) # produce JER signal shapes if args.jerUnc: for i in range(1, hSignal.GetNbinsX()+1): xLow = hSignal.GetXaxis().GetBinLowEdge(i) xUp = hSignal.GetXaxis().GetBinLowEdge(i+1) jer = 1. - jerValue xLowPrime = jer*(xLow-float(signalMass))+float(signalMass) xUpPrime = jer*(xUp-float(signalMass))+float(signalMass) hSigSyst['JERUp'].SetBinContent(i, signalCDF.Eval(xUpPrime) - signalCDF.Eval(xLowPrime)) jer = 1. + jerValue xLowPrime = jer*(xLow-float(signalMass))+float(signalMass) xUpPrime = jer*(xUp-float(signalMass))+float(signalMass) hSigSyst['JERDown'].SetBinContent(i, signalCDF.Eval(xUpPrime) - signalCDF.Eval(xLowPrime)) hSigSystDataHist['JERUp'] = RooDataHist('hSignalJERUp','hSignalJERUp',RooArgList(massAve),hSigSyst['JERUp']) hSigSystDataHist['JERDown'] = RooDataHist('hSignalJERDown','hSignalJERDown',RooArgList(massAve),hSigSyst['JERDown']) myWS = RooWorkspace("myWS") getattr(myWS,'import')(rooSigHist,RooFit.Rename("signal")) getattr(myWS,'import')(rooBkgHist,RooFit.Rename("background")) #getattr(myWS,'import')(signal_norm) getattr(myWS,'import')(background_norm) if args.jesUnc: getattr(myWS,'import')(hSigSystDataHist['JESUp'],RooFit.Rename("signal__JESUp")) getattr(myWS,'import')(hSigSystDataHist['JESDown'],RooFit.Rename("signal__JESDown")) if args.jerUnc: getattr(myWS,'import')(hSigSystDataHist['JERUp'],RooFit.Rename("signal__JERUp")) getattr(myWS,'import')(hSigSystDataHist['JERDown'],RooFit.Rename("signal__JERDown")) getattr(myWS,'import')(rooDataHist,RooFit.Rename("data_obs")) myWS.Print() outputRootFile = currentDir+'/Rootfiles/workspace_'+outputName+'.root' myWS.writeToFile(outputRootFile, True) print ' |----> Workspace created in root file:\n', outputRootFile # ----------------------------------------- # write a datacard dataCardName = currentDir+'/Datacards/datacard_'+outputName+'.txt' datacard = open( dataCardName ,'w') datacard.write('imax 1\n') datacard.write('jmax 1\n') datacard.write('kmax *\n') datacard.write('---------------\n') if args.jesUnc or args.jerUnc or args.lumiUnc or args.normUnc or args.unc: datacard.write('shapes * * '+outputRootFile+' myWS:$PROCESS myWS:$PROCESS__$SYSTEMATIC\n') else: datacard.write("shapes * * "+outputRootFile+" myWS:$PROCESS \n") datacard.write('---------------\n') datacard.write('bin 1\n') datacard.write('observation -1\n') datacard.write('------------------------------\n') datacard.write('bin 1 1\n') datacard.write('process signal background\n') datacard.write('process 0 1\n') datacard.write('rate -1 -1\n') datacard.write('------------------------------\n') if args.lumiUnc: datacard.write('lumi lnN %f -\n'%(lumiUnc)) if args.jesUnc: datacard.write('JES shape 1 -\n') if args.jerUnc: datacard.write('JER shape 1 -\n') #flat parameters --- flat prior if args.normUnc: datacard.write('background_norm flatParam\n') #datacard.write('p1 flatParam\n') datacard.close() print ' |----> Datacard created:\n', dataCardName
def main(): # usage description usage = "Example: ./scripts/createDatacards.py --inputData inputs/rawhistV7_Run2015D_scoutingPFHT_UNBLINDED_649_838_JEC_HLTplusV7_Mjj_cor_smooth.root --dataHistname mjj_mjjcor_gev --inputSig inputs/ResonanceShapes_gg_13TeV_Scouting_Spring15.root -f gg -o datacards -l 1866 --lumiUnc 0.027 --massrange 1000 1500 50 --runFit --p1 5 --p2 7 --p3 0.4 --massMin 838 --massMax 2037 --fitStrategy 2" # input parameters parser = ArgumentParser( description= 'Script that creates combine datacards and corresponding RooFit workspaces', epilog=usage) parser.add_argument("analysis", type=str, help="Analysis name") parser.add_argument("model", type=str, help="Model (Hbb, RSG)") #parser.add_argument("--inputData", dest="inputData", required=True, # help="Input data spectrum", # metavar="INPUT_DATA") parser.add_argument("--dataHistname", dest="dataHistname", type=str, default="h_data", help="Data histogram name", metavar="DATA_HISTNAME") #parser.add_argument("--inputSig", dest="inputSig", required=True, # help="Input signal shapes", # metavar="INPUT_SIGNAL") parser.add_argument("-f", "--final_state", dest="final_state", default="qq", help="Final state (e.g. qq, qg, gg)", metavar="FINAL_STATE") parser.add_argument("--fit_functions", dest="fit_functions", default="f1,f2,f3,f4,f5", help="List of fit functions") #parser.add_argument("-f2", "--type", dest="atype", required=True, help="Type (e.g. hG, lG, hR, lR)") parser.add_argument( "-o", "--output_path", dest="output_path", help= "Output path where datacards and workspaces will be stored. If not specified, this is derived from limit_configuration.", metavar="OUTPUT_PATH") parser.add_argument("--correctTrigger", dest="correctTrigger", action='store_true', help="Include trigger correction in PDF") parser.add_argument( "-l", "--lumi", dest="lumi", default=19700., type=float, help="Integrated luminosity in pb-1 (default: %(default).1f)", metavar="LUMI") parser.add_argument( "--massMin", dest="massMin", default=500, type=int, help= "Lower bound of the mass range used for fitting (default: %(default)s)", metavar="MASS_MIN") parser.add_argument( "--massMax", dest="massMax", default=1200, type=int, help= "Upper bound of the mass range used for fitting (default: %(default)s)", metavar="MASS_MAX") parser.add_argument( "--fitSignal", action="store_true", help= "Use signal fitted shapes (CB+Voigtian) instead of histogram templates" ) #parser.add_argument("--lumiUnc", dest="lumiUnc", # required=True, type=float, # help="Relative uncertainty in the integrated luminosity", # metavar="LUMI_UNC") #parser.add_argument("--jesUnc", dest="jesUnc", # type=float, # help="Relative uncertainty in the jet energy scale", # metavar="JES_UNC") #parser.add_argument("--jerUnc", dest="jerUnc", # type=float, # help="Relative uncertainty in the jet energy resolution", # metavar="JER_UNC") parser.add_argument( "--sqrtS", dest="sqrtS", default=8000., type=float, help="Collision center-of-mass energy (default: %(default).1f)", metavar="SQRTS") parser.add_argument("--fixP3", dest="fixP3", default=False, action="store_true", help="Fix the fit function p3 parameter") parser.add_argument("--runFit", dest="runFit", default=False, action="store_true", help="Run the fit") parser.add_argument("--fitBonly", dest="fitBonly", default=False, action="store_true", help="Run B-only fit") parser.add_argument("--fixBkg", dest="fixBkg", default=False, action="store_true", help="Fix all background parameters") parser.add_argument("--decoBkg", dest="decoBkg", default=False, action="store_true", help="Decorrelate background parameters") parser.add_argument("--fitStrategy", dest="fitStrategy", type=int, default=1, help="Fit strategy (default: %(default).1f)") parser.add_argument("--debug", dest="debug", default=False, action="store_true", help="Debug printout") parser.add_argument( "--postfix", dest="postfix", default='', help="Postfix for the output file names (default: %(default)s)") parser.add_argument("--pyes", dest="pyes", default=False, action="store_true", help="Make files for plots") parser.add_argument("--jyes", dest="jyes", default=False, action="store_true", help="Make files for JES/JER plots") parser.add_argument( "--pdir", dest="pdir", default='testarea', help="Name a directory for the plots (default: %(default)s)") parser.add_argument("--chi2", dest="chi2", default=False, action="store_true", help="Compute chi squared") parser.add_argument("--widefit", dest="widefit", default=False, action="store_true", help="Fit with wide bin hist") mass_group = parser.add_mutually_exclusive_group(required=True) mass_group.add_argument( "--mass", type=int, nargs='*', default=1000, help= "Mass can be specified as a single value or a whitespace separated list (default: %(default)i)" ) mass_group.add_argument( "--massrange", type=int, nargs=3, help="Define a range of masses to be produced. Format: min max step", metavar=('MIN', 'MAX', 'STEP')) mass_group.add_argument("--masslist", help="List containing mass information") args = parser.parse_args() fit_functions = args.fit_functions.split(",") # mass points for which resonance shapes will be produced masses = [] if args.fitBonly: masses.append(750) else: if args.massrange != None: MIN, MAX, STEP = args.massrange masses = range(MIN, MAX + STEP, STEP) elif args.masslist != None: # A mass list was provided print "Will create mass list according to", args.masslist masslist = __import__(args.masslist.replace(".py", "")) masses = masslist.masses else: masses = args.mass # sort masses masses.sort() # import ROOT stuff from ROOT import gStyle, TFile, TH1F, TH1D, TGraph, kTRUE, kFALSE, TCanvas, TLegend, TPad, TLine from ROOT import RooHist, RooRealVar, RooDataHist, RooArgList, RooArgSet, RooAddPdf, RooProdPdf, RooEffProd, RooFit, RooGenericPdf, RooWorkspace, RooMsgService, RooHistPdf, RooExtendPdf if not args.debug: RooMsgService.instance().setSilentMode(kTRUE) RooMsgService.instance().setStreamStatus(0, kFALSE) RooMsgService.instance().setStreamStatus(1, kFALSE) # input data file #inputData = TFile(limit_config.get_data_input(args.analysis)) # input data histogram #hData = inputData.Get(args.dataHistname) #hData.SetDirectory(0) data_file = TFile( analysis_config.get_b_histogram_filename(args.analysis, "BJetPlusX_2012")) hData = data_file.Get("BHistograms/h_pfjet_mjj") hData.SetDirectory(0) # input sig file if not args.fitSignal: print "[create_datacards] INFO : Opening resonance shapes file at " + limit_config.get_resonance_shapes( args.analysis, args.model) inputSig = TFile( limit_config.get_resonance_shapes(args.analysis, args.model), "READ") sqrtS = args.sqrtS # mass variable mjj = RooRealVar('mjj', 'mjj', float(args.massMin), float(args.massMax)) # integrated luminosity and signal cross section lumi = args.lumi signalCrossSection = 1. # set to 1. so that the limit on r can be interpreted as a limit on the signal cross section if args.correctTrigger: trigger_efficiency_pdf = trigger_efficiency.get_pdf(args.analysis, mjj) trigger_efficiency_formula = trigger_efficiency.get_formula( args.analysis, mjj) else: trigger_efficiency_pdf = trigger_efficiency.get_trivial_pdf(mjj) trigger_efficiency_formula = trigger_efficiency.get_trivial_formula( mjj) for mass in masses: print ">> Creating datacard and workspace for %s resonance with m = %i GeV..." % ( args.final_state, int(mass)) rooDataHist = RooDataHist('rooDatahist', 'rooDathist', RooArgList(mjj), hData) if not args.fitSignal: hSig = inputSig.Get("h_" + args.final_state + "_" + str(int(mass))) if not hSig: raise Exception("Couldn't find histogram " + "h_" + args.final_state + "_" + str(int(mass)) + " in file " + limit_config.get_resonance_shapes( args.analysis, args.model)) # normalize signal shape to the expected event yield (works even if input shapes are not normalized to unity) hSig.Scale( signalCrossSection * lumi / hSig.Integral() ) # divide by a number that provides roughly an r value of 1-10 rooSigHist = RooDataHist('rooSigHist', 'rooSigHist', RooArgList(mjj), hSig) print 'Signal acceptance:', (rooSigHist.sumEntries() / hSig.Integral()) # If using fitted signal shapes, load the signal PDF if args.fitSignal: print "[create_datacards] Loading fitted signal PDFs from " + analysis_config.get_signal_fit_file( args.analysis, args.model, mass, "bukin", interpolated=(not mass in analysis_config.simulation.simulated_masses)) f_signal_pdfs = TFile( analysis_config.get_signal_fit_file( args.analysis, args.model, mass, "bukin", interpolated=( not mass in analysis_config.simulation.simulated_masses)), "READ") w_signal = f_signal_pdfs.Get("w_signal") input_parameters = signal_fits.get_parameters( w_signal.pdf("signal")) # Make a new PDF with nuisance parameters signal_pdf_notrig, signal_vars = signal_fits.make_signal_pdf_systematic( "bukin", mjj, mass=mass) signal_pdf_name = signal_pdf_notrig.GetName() signal_pdf_notrig.SetName(signal_pdf_name + "_notrig") #signal_pdf = RooProdPdf(signal_pdf_name, signal_pdf_name, signal_pdf_notrig, trigger_efficiency_pdf) signal_pdf = RooEffProd(signal_pdf_name, signal_pdf_name, signal_pdf_notrig, trigger_efficiency_formula) # Copy input parameter values signal_vars["xp_0"].setVal(input_parameters["xp"][0]) signal_vars["xp_0"].setError(input_parameters["xp"][1]) signal_vars["xp_0"].setConstant() signal_vars["sigp_0"].setVal(input_parameters["sigp"][0]) signal_vars["sigp_0"].setError(input_parameters["sigp"][1]) signal_vars["sigp_0"].setConstant() signal_vars["xi_0"].setVal(input_parameters["xi"][0]) signal_vars["xi_0"].setError(input_parameters["xi"][1]) signal_vars["xi_0"].setConstant() signal_vars["rho1_0"].setVal(input_parameters["rho1"][0]) signal_vars["rho1_0"].setError(input_parameters["rho1"][1]) signal_vars["rho1_0"].setConstant() signal_vars["rho2_0"].setVal(input_parameters["rho2"][0]) signal_vars["rho2_0"].setError(input_parameters["rho2"][1]) signal_vars["rho2_0"].setConstant() f_signal_pdfs.Close() signal_parameters = {} signal_pdfs_notrig = {} signal_pdfs = {} signal_norms = {} background_pdfs = {} background_pdfs_notrig = {} background_parameters = {} background_norms = {} signal_epdfs = {} background_epdfs = {} models = {} fit_results = {} for fit_function in fit_functions: print "[create_datacards] INFO : On fit function {}".format( fit_function) if args.fitSignal: # Make a copy of the signal PDF, so that each fitTo call uses its own copy. # The copy should have all variables set constant. #signal_pdfs[fit_function], signal_parameters[fit_function] = signal_fits.copy_signal_pdf("bukin", signal_pdf, mjj, tag=fit_function, include_systematics=True) signal_pdfs_notrig[fit_function] = ROOT.RooBukinPdf( signal_pdf_notrig, signal_pdf_notrig.GetName() + "_" + fit_function) signal_pdfs[fit_function] = RooEffProd( signal_pdf.GetName() + "_" + fit_function, signal_pdf.GetName() + "_" + fit_function, signal_pdfs_notrig[fit_function], trigger_efficiency_formula) #signal_pdfs[fit_function] = RooProdPdf(signal_pdf.GetName() + "_" + fit_function, signal_pdf.GetName() + "_" + fit_function, signal_pdfs_notrig[fit_function], trigger_efficiency_pdf) iterator = signal_pdfs_notrig[fit_function].getVariables( ).createIterator() this_parameter = iterator.Next() while this_parameter: this_parameter.setConstant() this_parameter = iterator.Next() else: signal_pdfs[fit_function] = RooHistPdf( 'signal_' + fit_function, 'signal_' + fit_function, RooArgSet(mjj), rooSigHist) signal_norms[fit_function] = RooRealVar( 'signal_norm_' + fit_function, 'signal_norm_' + fit_function, 0., 0., 1e+05) if args.fitBonly: signal_norms[fit_function].setConstant() background_pdfs_notrig[fit_function], background_parameters[ fit_function] = make_background_pdf(fit_function, mjj, collision_energy=8000.) background_pdf_name = background_pdfs_notrig[fit_function].GetName( ) background_pdfs_notrig[fit_function].SetName(background_pdf_name + "_notrig") background_pdfs[fit_function] = RooEffProd( background_pdf_name, background_pdf_name, background_pdfs_notrig[fit_function], trigger_efficiency_formula) #background_pdfs[fit_function] = RooProdPdf(background_pdf_name, background_pdf_name, background_pdfs_notrig[fit_function], trigger_efficiency_pdf) #background_pdfs[fit_function] = background_pdfs_notrig[fit_function] #background_pdfs[fit_function].SetName(background_pdf_name) # Initial values if "trigbbh" in args.analysis: if fit_function == "f3": background_parameters[fit_function]["p1"].setVal(55.) background_parameters[fit_function]["p1"].setMin(20.) background_parameters[fit_function]["p2"].setVal(8.) elif fit_function == "f4": background_parameters[fit_function]["p1"].setVal(28.) background_parameters[fit_function]["p2"].setVal(-22.) background_parameters[fit_function]["p3"].setVal(10.) elif "trigbbl" in args.analysis: if fit_function == "f3": background_parameters[fit_function]["p1"].setVal(82.) background_parameters[fit_function]["p1"].setMin(60.) background_parameters[fit_function]["p2"].setVal(8.) elif fit_function == "f4": background_parameters[fit_function]["p1"].setVal(41.) background_parameters[fit_function]["p2"].setVal(-45.) background_parameters[fit_function]["p3"].setVal(10.) data_integral = hData.Integral( hData.GetXaxis().FindBin(float(args.massMin)), hData.GetXaxis().FindBin(float(args.massMax))) background_norms[fit_function] = RooRealVar( 'background_' + fit_function + '_norm', 'background_' + fit_function + '_norm', data_integral, 0., 1.e8) signal_epdfs[fit_function] = RooExtendPdf( 'esignal_' + fit_function, 'esignal_' + fit_function, signal_pdfs[fit_function], signal_norms[fit_function]) background_epdfs[fit_function] = RooExtendPdf( 'ebackground_' + fit_function, 'ebackground_' + fit_function, background_pdfs[fit_function], background_norms[fit_function]) models[fit_function] = RooAddPdf( 'model_' + fit_function, 's+b', RooArgList(background_epdfs[fit_function], signal_epdfs[fit_function])) if args.runFit: print "[create_datacards] INFO : Starting fit with function {}".format( fit_function) fit_results[fit_function] = models[fit_function].fitTo( rooDataHist, RooFit.Save(kTRUE), RooFit.Extended(kTRUE), RooFit.Strategy(args.fitStrategy), RooFit.Verbose(0)) print "[create_datacards] INFO : Done with fit {}. Printing results.".format( fit_function) fit_results[fit_function].Print() print "[create_datacards] DEBUG : End args.runFit if block." # needed if want to evaluate limits without background systematics if args.fixBkg: background_norms[fit_function].setConstant() for par_name, par in background_parameters[ fit_function].iteritems(): par.setConstant() # ----------------------------------------- #signal_pdfs_syst = {} # JES and JER uncertainties if args.fitSignal: print "[create_datacards] INFO : Getting signal PDFs from " + analysis_config.get_signal_fit_file( args.analysis, args.model, mass, "bukin", interpolated=(not mass in analysis_config.simulation.simulated_masses)) f_signal_pdfs = TFile( analysis_config.get_signal_fit_file( args.analysis, args.model, mass, "bukin", interpolated=( not mass in analysis_config.simulation.simulated_masses))) w_signal = f_signal_pdfs.Get("w_signal") if "jes" in systematics: xp_central = signal_vars["xp_0"].getVal() #print w_signal.pdf("signal__JESUp") #print signal_fits.get_parameters(w_signal.pdf("signal__JESUp")) xp_up = signal_fits.get_parameters( w_signal.pdf("signal__JESUp"))["xpJESUp"][0] xp_down = signal_fits.get_parameters( w_signal.pdf("signal__JESDown"))["xpJESDown"][0] signal_vars["dxp"].setVal( max(abs(xp_up - xp_central), abs(xp_down - xp_central))) if signal_vars["dxp"].getVal() > 2 * mass * 0.1: print "[create_datacards] WARNING : Large dxp value. dxp = {}, xp_down = {}, xp_central = {}, xp_up = {}".format( signal_vars["dxp"].getVal(), xp_down, xp_central, xp_up) signal_vars["alpha_jes"].setVal(0.) signal_vars["alpha_jes"].setConstant(False) else: signal_vars["dxp"].setVal(0.) signal_vars["alpha_jes"].setVal(0.) signal_vars["alpha_jes"].setConstant() signal_vars["dxp"].setError(0.) signal_vars["dxp"].setConstant() if "jer" in systematics: sigp_central = signal_vars["sigp_0"].getVal() sigp_up = signal_fits.get_parameters( w_signal.pdf("signal__JERUp"))["sigpJERUp"][0] sigp_down = signal_fits.get_parameters( w_signal.pdf("signal__JERDown"))["sigpJERDown"][0] signal_vars["dsigp"].setVal( max(abs(sigp_up - sigp_central), abs(sigp_down - sigp_central))) signal_vars["alpha_jer"].setVal(0.) signal_vars["alpha_jer"].setConstant(False) else: signal_vars["dsigp"].setVal(0.) signal_vars["alpha_jer"].setVal(0.) signal_vars["alpha_jer"].setConstant() signal_vars["dsigp"].setError(0.) signal_vars["dsigp"].setConstant() #for variation in ["JERUp", "JERDown"]: # signal_pdfs_syst[variation] = w_signal.pdf("signal__" + variation) #for variation, pdf in signal_pdfs_syst.iteritems(): # signal_parameters = pdf.getVariables() # iter = signal_parameters.createIterator() # var = iter.Next() # while var: # var.setConstant() # var = iter.Next() f_signal_pdfs.Close() else: # dictionaries holding systematic variations of the signal shape hSig_Syst = {} hSig_Syst_DataHist = {} sigCDF = TGraph(hSig.GetNbinsX() + 1) if "jes" in systematics or "jer" in systematics: sigCDF.SetPoint(0, 0., 0.) integral = 0. for i in range(1, hSig.GetNbinsX() + 1): x = hSig.GetXaxis().GetBinLowEdge(i + 1) integral = integral + hSig.GetBinContent(i) sigCDF.SetPoint(i, x, integral) if "jes" in systematics: hSig_Syst['JESUp'] = copy.deepcopy(hSig) hSig_Syst['JESDown'] = copy.deepcopy(hSig) if "jer" in systematics: hSig_Syst['JERUp'] = copy.deepcopy(hSig) hSig_Syst['JERDown'] = copy.deepcopy(hSig) # reset signal histograms for key in hSig_Syst.keys(): hSig_Syst[key].Reset() hSig_Syst[key].SetName(hSig_Syst[key].GetName() + '_' + key) # produce JES signal shapes if "jes" in systematics: for i in range(1, hSig.GetNbinsX() + 1): xLow = hSig.GetXaxis().GetBinLowEdge(i) xUp = hSig.GetXaxis().GetBinLowEdge(i + 1) jes = 1. - systematics["jes"] xLowPrime = jes * xLow xUpPrime = jes * xUp hSig_Syst['JESUp'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) jes = 1. + systematics["jes"] xLowPrime = jes * xLow xUpPrime = jes * xUp hSig_Syst['JESDown'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) hSig_Syst_DataHist['JESUp'] = RooDataHist( 'hSig_JESUp', 'hSig_JESUp', RooArgList(mjj), hSig_Syst['JESUp']) hSig_Syst_DataHist['JESDown'] = RooDataHist( 'hSig_JESDown', 'hSig_JESDown', RooArgList(mjj), hSig_Syst['JESDown']) # produce JER signal shapes if "jer" in systematics: for i in range(1, hSig.GetNbinsX() + 1): xLow = hSig.GetXaxis().GetBinLowEdge(i) xUp = hSig.GetXaxis().GetBinLowEdge(i + 1) jer = 1. - systematics["jer"] xLowPrime = jer * (xLow - float(mass)) + float(mass) xUpPrime = jer * (xUp - float(mass)) + float(mass) hSig_Syst['JERUp'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) jer = 1. + systematics["jer"] xLowPrime = jer * (xLow - float(mass)) + float(mass) xUpPrime = jer * (xUp - float(mass)) + float(mass) hSig_Syst['JERDown'].SetBinContent( i, sigCDF.Eval(xUpPrime) - sigCDF.Eval(xLowPrime)) hSig_Syst_DataHist['JERUp'] = RooDataHist( 'hSig_JERUp', 'hSig_JERUp', RooArgList(mjj), hSig_Syst['JERUp']) hSig_Syst_DataHist['JERDown'] = RooDataHist( 'hSig_JERDown', 'hSig_JERDown', RooArgList(mjj), hSig_Syst['JERDown']) # ----------------------------------------- # create a datacard and corresponding workspace postfix = (('_' + args.postfix) if args.postfix != '' else '') wsName = 'workspace_' + args.final_state + '_m' + str( mass) + postfix + '.root' w = RooWorkspace('w', 'workspace') if args.fitSignal: signal_pdf.SetName("signal") getattr(w, 'import')(signal_pdf, RooFit.Rename("signal")) # Create a norm variable "signal_norm" which normalizes the PDF to unity. norm = args.lumi #signal_norm = ROOT.RooRealVar("signal_norm", "signal_norm", 1. / norm, 0.1 / norm, 10. / norm) #if args.analysis == "trigbbh_CSVTM" and mass >= 1100: signal_norm = ROOT.RooRealVar("signal_norm", "signal_norm", norm / 100., norm / 100. / 10., norm * 10.) #else: # signal_norm = ROOT.RooRealVar("signal_norm", "signal_norm", norm, norm / 10., norm * 10.) print "[create_datacards] INFO : Set signal norm to {}".format( signal_norm.getVal()) signal_norm.setConstant() getattr(w, 'import')(signal_norm, ROOT.RooCmdArg()) #if "jes" in systematics: # getattr(w,'import')(signal_pdfs_syst['JESUp'],RooFit.Rename("signal__JESUp")) # getattr(w,'import')(signal_pdfs_syst['JESDown'],RooFit.Rename("signal__JESDown")) #if "jer" in systematics: # getattr(w,'import')(signal_pdfs_syst['JERUp'],RooFit.Rename("signal__JERUp")) # getattr(w,'import')(signal_pdfs_syst['JERDown'],RooFit.Rename("signal__JERDown")) else: getattr(w, 'import')(rooSigHist, RooFit.Rename("signal")) if "jes" in systematics: getattr(w, 'import')(hSig_Syst_DataHist['JESUp'], RooFit.Rename("signal__JESUp")) getattr(w, 'import')(hSig_Syst_DataHist['JESDown'], RooFit.Rename("signal__JESDown")) if "jer" in systematics: getattr(w, 'import')(hSig_Syst_DataHist['JERUp'], RooFit.Rename("signal__JERUp")) getattr(w, 'import')(hSig_Syst_DataHist['JERDown'], RooFit.Rename("signal__JERDown")) if args.decoBkg: getattr(w, 'import')(background_deco, ROOT.RooCmdArg()) else: for fit_function in fit_functions: print "Importing background PDF" print background_pdfs[fit_function] background_pdfs[fit_function].Print() getattr(w, 'import')(background_pdfs[fit_function], ROOT.RooCmdArg(), RooFit.Rename("background_" + fit_function), RooFit.RecycleConflictNodes()) w.pdf("background_" + fit_function).Print() getattr(w, 'import')(background_norms[fit_function], ROOT.RooCmdArg(), RooFit.Rename("background_" + fit_function + "_norm")) getattr(w, 'import')(fit_results[fit_function]) getattr(w, 'import')(signal_norms[fit_function], ROOT.RooCmdArg()) if args.fitBonly: getattr(w, 'import')(models[fit_function], ROOT.RooCmdArg(), RooFit.RecycleConflictNodes()) getattr(w, 'import')(rooDataHist, RooFit.Rename("data_obs")) w.Print() print "Starting save" if args.output_path: if not os.path.isdir(os.path.join(os.getcwd(), args.output_path)): os.mkdir(os.path.join(os.getcwd(), args.output_path)) print "[create_datacards] INFO : Writing workspace to file {}".format( os.path.join(args.output_path, wsName)) w.writeToFile(os.path.join(args.output_path, wsName)) else: print "[create_datacards] INFO : Writing workspace to file {}".format( limit_config.get_workspace_filename( args.analysis, args.model, mass, fitBonly=args.fitBonly, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) w.writeToFile( limit_config.get_workspace_filename( args.analysis, args.model, mass, fitBonly=args.fitBonly, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) # Clean up for name, obj in signal_norms.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_pdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_pdfs_notrig.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_norms.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_pdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_pdfs_notrig.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in signal_epdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in background_epdfs.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in fit_results.iteritems(): if obj: obj.IsA().Destructor(obj) for name, dict_l2 in background_parameters.iteritems(): for name2, obj in dict_l2.iteritems(): if obj: obj.IsA().Destructor(obj) for name, obj in models.iteritems(): if obj: obj.IsA().Destructor(obj) rooDataHist.IsA().Destructor(rooDataHist) w.IsA().Destructor(w) # Make datacards only if S+B fitted if not args.fitBonly: beffUnc = 0.3 boffUnc = 0.06 for fit_function in fit_functions: if args.output_path: dcName = 'datacard_' + args.final_state + '_m' + str( mass) + postfix + '_' + fit_function + '.txt' print "[create_datacards] INFO : Writing datacard to file {}".format( os.path.join(args.output_path, dcName)) datacard = open(os.path.join(args.output_path, dcName), 'w') else: print "[create_datacards] INFO : Writing datacard to file {}".format( limit_config.get_datacard_filename( args.analysis, args.model, mass, fit_function, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) datacard = open( limit_config.get_datacard_filename( args.analysis, args.model, mass, fit_function, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger), 'w') datacard.write('imax 1\n') datacard.write('jmax 1\n') datacard.write('kmax *\n') datacard.write('---------------\n') if ("jes" in systematics or "jer" in systematics) and not args.fitSignal: if args.output_path: datacard.write('shapes * * ' + wsName + ' w:$PROCESS w:$PROCESS__$SYSTEMATIC\n') else: datacard.write('shapes * * ' + os.path.basename( limit_config.get_workspace_filename( args.analysis, args.model, mass, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) + ' w:$PROCESS w:$PROCESS__$SYSTEMATIC\n') else: if args.output_path: datacard.write('shapes * * ' + wsName + ' w:$PROCESS\n') else: datacard.write('shapes * * ' + os.path.basename( limit_config.get_workspace_filename( args.analysis, args.model, mass, fitSignal=args.fitSignal, correctTrigger=args.correctTrigger)) + ' w:$PROCESS\n') datacard.write('---------------\n') datacard.write('bin 1\n') datacard.write('observation -1\n') datacard.write('------------------------------\n') datacard.write('bin 1 1\n') datacard.write('process signal background_' + fit_function + '\n') datacard.write('process 0 1\n') if args.fitSignal: datacard.write('rate 1 1\n') else: datacard.write('rate -1 1\n') datacard.write('------------------------------\n') datacard.write('lumi lnN %f -\n' % (1. + systematics["luminosity"])) datacard.write('beff lnN %f -\n' % (1. + beffUnc)) datacard.write('boff lnN %f -\n' % (1. + boffUnc)) #datacard.write('bkg lnN - 1.03\n') if args.fitSignal: if "jes" in systematics: datacard.write("alpha_jes param 0.0 1.0\n") if "jer" in systematics: datacard.write("alpha_jer param 0.0 1.0\n") else: if "jes" in systematics: datacard.write('JES shape 1 -\n') if "jer" in systematics: datacard.write('JER shape 1 -\n') # flat parameters --- flat prior datacard.write('background_' + fit_function + '_norm flatParam\n') if args.decoBkg: datacard.write('deco_eig1 flatParam\n') datacard.write('deco_eig2 flatParam\n') else: for par_name, par in background_parameters[ fit_function].iteritems(): datacard.write(fit_function + "_" + par_name + ' flatParam\n') datacard.close() print "[create_datacards] INFO : Done with this datacard" #print '>> Datacards and workspaces created and stored in %s/'%( os.path.join(os.getcwd(),args.output_path) ) print "All done."
def shapeCards(datahistosFile, histosFile, signalFile, signalSample, hist, signalMass, minMass, maxMass, outputName, outputFileTheta): """function to run Roofit and save workspace for RooStats""" warnings.filterwarnings( action='ignore', category=RuntimeWarning, message='.*class stack<RooAbsArg\*,deque<RooAbsArg\*> >') ############################################################# DATA #hData = histosFile.Get('massAve_deltaEtaDijet_QCDPtAll') #hData = datahistosFile.Get('massAve_prunedMassAsymVsdeltaEtaDijet_DATA_ABCDProj') dataFile = TFile(datahistosFile) hData = dataFile.Get(hist + '_DATA') hData.Rebin(args.reBin) #hData = hData.Rebin( len( boostedMassAveBins )-1, hData.GetName(), boostedMassAveBins ) #hData = histosFile.Get(hist+'_QCDPtAll_A') #hData.Add(htmpSignal) #hData.Scale(1/hData.Integral()) #maxMass = boostedMassAveBins[ hData.FindLastBinAbove( 0, 1) ] #minMass = signalMass-30 #maxMass = signalMass+30 massAve = RooRealVar('massAve', 'massAve', minMass, maxMass) #massAveData = RooRealVar( 'massAveData', 'massAveData', minMass, maxMass ) rooDataHist = RooDataHist('rooDatahist', 'rooDatahist', RooArgList(massAve), hData) # if isData else hPseudo ) rooDataHist.Print() ############################################################################################ ####################### Signal if 'gaus' in args.job: hSignal = TH1F('massAve_RPVStop', 'massAve_RPVStop', maxMass / args.reBin, minMass, maxMass) for q in range(hSignal.GetNbinsX() + 1): gausEval = signalFile.Eval(hSignal.GetXaxis().GetBinCenter(q)) hSignal.SetBinContent(q, gausEval) #meanSig = RooRealVar( 'meanSig', 'mean of signal', sigGaus.GetParameter( 1 ) ) #sigmaSig = RooRealVar( 'sigmaSig', 'sigma of signal', sigGaus.GetParameter( 2 ) ) #signalPdf = RooGaussian( 'signal', 'signal', massAve, meanSig, sigmaSig ) #signalPdf.Print() else: signalHistosFile = TFile(signalFile) hSignal = signalHistosFile.Get(hist + '_' + signalSample) hSignal.Rebin(args.reBin) hSignal.Scale(twoProngSF) signalXS = search(dictXS, 'RPVStopStopToJets_UDD312_M-' + str(signalMass)) rooSigHist = RooDataHist('rooSigHist', 'rooSigHist', RooArgList(massAve), hSignal) sigAcc = rooSigHist.sumEntries( ) #round(hSignal.Integral( hSignal.GetXaxis().FindBin( minMass ), hSignal.GetXaxis().FindBin( maxMass )), 2) rooSigHist.Print() #signal = RooHistPdf('signal','signal',RooArgSet(massAve),rooSigHist) #signal.Print() #signal_norm = RooRealVar('signal_norm','signal_norm',0,-1e+04,1e+04) #if args.fitBonly: signal_norm.setConstant() #signal_norm.Print() ##################################################################### hSigSyst = signalUnc(hSignal, signalMass) hSigSystDataHist = {} if args.jesUnc: hSigSystDataHist['JESUp'] = RooDataHist('hSignalJESUp', 'hSignalJESUp', RooArgList(massAve), hSigSyst['JESUp']) hSigSystDataHist['JESDown'] = RooDataHist('hSignalJESDown', 'hSignalJESDown', RooArgList(massAve), hSigSyst['JESDown']) if args.jerUnc: hSigSystDataHist['JERUp'] = RooDataHist('hSignalJERUp', 'hSignalJERUp', RooArgList(massAve), hSigSyst['JERUp']) hSigSystDataHist['JERDown'] = RooDataHist('hSignalJERDown', 'hSignalJERDown', RooArgList(massAve), hSigSyst['JERDown']) #################################### Background if args.altBkg: newBkgHistoFile = datahistosFile.replace('DATA', 'DATA_ABCDBkg') newBkgFile = TFile(newBkgHistoFile) htmpBkg = newBkgFile.Get( 'massAve_prunedMassAsymVsdeltaEtaDijet_DATA_ABCDProj') if (htmpBkg.GetBinWidth(1) != args.reBin): print '|----- Bin size in DATA_C histogram is different than rest.' sys.exit(0) else: htmpBkg = dataFile.Get( 'massAve_prunedMassAsymVsdeltaEtaDijet_DATA_ABCDProj') htmpBkg.Rebin(args.reBin) #hBkg = histosFile.Get('massAve_prunedMassAsymVsdeltaEtaDijet_QCDPtAll_ABCDProj') #hBkg = histosFile.Get(hist+'_QCDPtAll_BCD') #htmpBkg = htmpBkg.Rebin( len( boostedMassAveBins )-1, htmpBkg.GetName(), boostedMassAveBins ) hBkg = htmpBkg.Clone() hBkg.Reset() for ibin in range(htmpBkg.GetNbinsX()): binCont = htmpBkg.GetBinContent(ibin) binErr = htmpBkg.GetBinError(ibin) if binCont == 0: hBkg.SetBinContent(ibin, 0) hBkg.SetBinError(ibin, 1.8) else: hBkg.SetBinContent(ibin, binCont) hBkg.SetBinError(ibin, binErr) #hBkg.Scale(1/hBkg.Integral()) hPseudo = createPseudoExperiment(hBkg, bkgAcc) ###### Adding statistical uncertanty hBkgStatUncUp = hBkg.Clone() hBkgStatUncUp.Reset() hBkgStatUncDown = hBkg.Clone() hBkgStatUncDown.Reset() for i in range(hBkg.GetNbinsX() + 1): cont = hBkg.GetBinContent(i) contErr = hBkg.GetBinError(i) hBkgStatUncUp.SetBinContent(i, cont + (1 * contErr)) hBkgStatUncDown.SetBinContent(i, cont - (1 * contErr)) hBkgStatUncUpDataHist = RooDataHist('hBkgStatUncUp', 'hBkgStatUncUp', RooArgList(massAve), hBkgStatUncUp) hBkgStatUncDownDataHist = RooDataHist('hBkgStatUncDown', 'hBkgStatUncDown', RooArgList(massAve), hBkgStatUncDown) if 'template' in args.job: rooBkgHist = RooDataHist('rooBkgHist', 'rooBkgHist', RooArgList(massAve), hBkg) bkgAcc = rooBkgHist.sumEntries() rooBkgHist.Print() background = RooHistPdf('background', 'background', RooArgSet(massAve), rooBkgHist) background.Print() else: massAveBkg = RooRealVar('massAveBkg', 'massAveBkg', minMass, maxMass) p1 = RooRealVar('p1', 'p1', 1, 0., 100.) p2 = RooRealVar('p2', 'p2', 1, 0., 60.) p3 = RooRealVar('p3', 'p3', 1, -10., 10.) bkgAcc = round( hBkg.Integral(hBkg.GetXaxis().FindBin(minMass), hBkg.GetXaxis().FindBin(maxMass)), 2) background = RooGenericPdf( 'background', '(pow(1-@0/%.1f,@1)/pow(@0/%.1f,@2+@3*log(@0/%.1f)))' % (1300, 1300, 1300), RooArgList(massAveBkg, p1, p2, p3)) background.Print() hBkgSyst = {} hBkgSystDataHist = {} if args.bkgUnc: print ' |---> Adding bkg unc' hBkgSyst['BkgUncUp'] = hBkg.Clone() hBkgSyst['BkgUncDown'] = hBkg.Clone() for key in hBkgSyst: hBkgSyst[key].Reset() hBkgSyst[key].SetName(hBkgSyst[key].GetName() + '_' + key) for q in range(0, hBkg.GetNbinsX()): binCont = hBkg.GetBinContent(q) bkgUncUp = 1. + (args.bkgUncValue / 100.) hBkgSyst['BkgUncUp'].SetBinContent(q, binCont * bkgUncUp) bkgUncDown = 1. - (args.bkgUncValue / 100.) hBkgSyst['BkgUncDown'].SetBinContent(q, binCont * bkgUncDown) hBkgSystDataHist['BkgUncUp'] = RooDataHist('hBkgBkgUncUp', 'hBkgBkgUncUp', RooArgList(massAve), hBkgSyst['BkgUncUp']) hBkgSystDataHist['BkgUncDown'] = RooDataHist('hBkgBkgUncDown', 'hBkgBkgUncDown', RooArgList(massAve), hBkgSyst['BkgUncDown']) ############################################################################################ #model = RooAddPdf("model","s+b",RooArgList(background,signal),RooArgList(background_norm,signal_norm)) #res = model.fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Strategy(0)) #res.Print() ############################ Create Workspace myWS = RooWorkspace("myWS") getattr(myWS, 'import')(rooBkgHist, RooFit.Rename("background")) #getattr(myWS,'import')(background,RooFit.Rename("background")) #getattr(myWS,'import')(signal_norm) #getattr(myWS,'import')(background_norm) ''' if 'gaus' in args.job: getattr(myWS,'import')(signalPdf,RooFit.Rename("signal")) if args.jesUnc: getattr(myWS,'import')(signalPdfJESUp,RooFit.Rename("signal__JESUp")) getattr(myWS,'import')(signalPdfJESDown,RooFit.Rename("signal__JESDown")) else: ''' getattr(myWS, 'import')(rooSigHist, RooFit.Rename("signal")) if args.jesUnc: getattr(myWS, 'import')(hSigSystDataHist['JESUp'], RooFit.Rename("signal__JESUp")) getattr(myWS, 'import')(hSigSystDataHist['JESDown'], RooFit.Rename("signal__JESDown")) if args.jerUnc: getattr(myWS, 'import')(hSigSystDataHist['JERUp'], RooFit.Rename("signal__JERUp")) getattr(myWS, 'import')(hSigSystDataHist['JERDown'], RooFit.Rename("signal__JERDown")) if args.bkgUnc: getattr(myWS, 'import')(hBkgSystDataHist['BkgUncUp'], RooFit.Rename("background__BkgUncUp")) getattr(myWS, 'import')(hBkgSystDataHist['BkgUncDown'], RooFit.Rename("background__BkgUncDown")) getattr(myWS, 'import')(hBkgStatUncUpDataHist, RooFit.Rename("background__BkgStatUncUp")) getattr(myWS, 'import')(hBkgStatUncDownDataHist, RooFit.Rename("background__BkgStatUncDown")) getattr(myWS, 'import')(rooDataHist, RooFit.Rename("data_obs")) myWS.Print() outputRootFile = currentDir + '/Rootfiles/workspace_' + outputName + '.root' myWS.writeToFile(outputRootFile, True) print ' |----> Workspace created in root file:\n', outputRootFile ''' c1 = TCanvas('c1', 'c1', 10, 10, 750, 500 ) # c1.SetLogy() xframe = myWS.var("massAve").frame() signalPdf.plotOn( xframe ) xframe.Draw() c1.SaveAs('test.png') del c1 ''' ############################################################################################ ######################### write a datacard dataCardName = currentDir + '/Datacards/datacard_' + outputName + '.txt' datacard = open(dataCardName, 'w') datacard.write('imax 1\n') datacard.write('jmax 1\n') datacard.write('kmax *\n') datacard.write('---------------\n') if args.jesUnc or args.jerUnc or args.lumiUnc or args.bkgUnc or args.unc: datacard.write('shapes * * ' + outputRootFile + ' myWS:$PROCESS myWS:$PROCESS__$SYSTEMATIC\n') else: datacard.write("shapes * * " + outputRootFile + " myWS:$PROCESS \n") datacard.write('---------------\n') datacard.write('bin ' + signalSample + '\n') datacard.write('observation -1\n') datacard.write('------------------------------\n') datacard.write('bin ' + signalSample + ' ' + signalSample + '\n') datacard.write('process signal background\n') datacard.write('process 0 1\n') #datacard.write('rate -1 -1\n') datacard.write('rate ' + str(sigAcc) + ' ' + str(bkgAcc) + '\n') datacard.write('------------------------------\n') if args.lumiUnc: datacard.write('lumi lnN %f -\n' % (lumiValue)) if args.puUnc: datacard.write('pu lnN %f -\n' % (puValue)) if args.jesUnc: datacard.write('JES shape 1 -\n') if args.jerUnc: datacard.write('JER shape 1 -\n') #flat parameters --- flat prior #if args.bkgUnc: datacard.write('BkgUnc shape - '+str( round( 1/ (args.bkgUncValue/34.1), 2 ) )+'\n') if args.bkgUnc: datacard.write('BkgUnc shape - 1 \n') #NcombineUnc = ( 1 / TMath.Sqrt( args.bkgUncValue / 100. ) ) - 1 #datacard.write('background_norm gmN '+str(int(round(NcombineUnc)))+' - '+str( round(bkgAcc/NcombineUnc,2) )+'\n') #datacard.write('p1 flatParam\n') datacard.write('BkgStatUnc shape - 1 \n') datacard.close() print ' |----> Datacard created:\n', dataCardName ############################################################################################ ########## Theta if args.theta: print ' |----> Creating Theta file\n', outputFileTheta outFile = TFile(outputFileTheta, 'update') tmpName = 'rpvstopjj' + str(signalMass) hSignal.SetName('massAve__' + tmpName) hSignal.Write() hSigSyst['JESDown'].SetName('massAve__' + tmpName + '__jes__down') hSigSyst['JESDown'].Write() hSigSyst['JESUp'].SetName('massAve__' + tmpName + '__jes__up') hSigSyst['JESUp'].Write() hSigSyst['JERDown'].SetName('massAve__' + tmpName + '__jer__down') hSigSyst['JERDown'].Write() hSigSyst['JERUp'].SetName('massAve__' + tmpName + '__jer__up') hSigSyst['JERUp'].Write() if (signalMass == 100): #or (signalMass == 170): hBkg.SetName('massAve__background') hBkg.Write() hBkgSyst['BkgUncDown'].SetName('massAve__background__unc__down') hBkgSyst['BkgUncDown'].Write() hBkgSyst['BkgUncUp'].SetName('massAve__background__unc__up') hBkgSyst['BkgUncUp'].Write() hData.SetName('massAve__DATA') hData.Write() outFile.Close()
class Wjj2DFitter: def __init__ (self, pars): self.pars = pars self.ws = RooWorkspace('wjj2dfitter') self.utils = Wjj2DFitterUtils(self.pars) self.useImportPars = False self.rangeString = None obs = [] for v in self.pars.var: try: vName = self.pars.varNames[v] except AttributeError: vName = v obs.append(vName) var1 = self.ws.factory('%s[%f,%f]' % (vName, self.pars.varRanges[v][1], self.pars.varRanges[v][2]) ) var1.setUnit('GeV') try: var1.SetTitle(self.pars.varTitles[v]) except AttributeError: var1.SetTitle('m_{jj}') var1.setPlotLabel(var1.GetTitle()) if len(self.pars.varRanges[v][3]) > 1: vbinning = RooBinning(len(self.pars.varRanges[v][3]) - 1, array('d', self.pars.varRanges[v][3]), '%sBinning' % vName) var1.setBinning(vbinning) else: var1.setBins(self.pars.varRanges[v][0]) var1.Print() if v in self.pars.exclude: var1.setRange('signalRegion', self.pars.exclude[v][0], self.pars.exclude[v][1]) var1.setRange('lowSideband', var1.getMin(), self.pars.exclude[v][0]) var1.setRange('highSideband', self.pars.exclude[v][1], var1.getMax()) self.rangeString = 'lowSideband,highSideband' self.ws.defineSet('obsSet', ','.join(obs)) def loadDataFromWorkspace(self, other, cut = None): #pull unbinned data from other workspace unbinnedData = other.data('data_unbinned') if not unbinnedData: unbinnedData = other.data('data_obs') if cut: unbinnedData = unbinnedData.reduce(cut) unbinnedData.Print() if self.pars.binData: #bin and import data unbinnedData.SetName('data_unbinned') getattr(self.ws, 'import')(unbinnedData) data = RooDataHist('data_obs', 'data_obs', other.set('obsSet'), unbinnedData) getattr(self.ws, 'import')(data) else: #just import data unbinnedData.SetName('data_obs') getattr(self.ws, 'import')(unbinnedData) def loadHistogramsFromWorkspace(self, other): #pull RooHist pdfs from other workspace pdfs = other.allPdfs() pdfIter = pdfs.createIterator() pdf = pdfIter.Next() while pdf: if pdf.IsA().InheritsFrom('RooHistPdf'): print 'importing',pdf.GetName(),'from old workspace' getattr(self.ws, 'import')(pdf) pdf = pdfIter.Next() def loadWorkspaceFromFile(self, filename, wsname = 'w', getFloatPars = True): print 'loading data workspace %s from file %s' % (wsname, filename) fin = TFile.Open(filename) if not fin: print 'failed to open the file',filename import os print 'cwd:',os.getcwd() print 'access of',filename,os.access(filename, os.R_OK) print 'list of root files in cwd' for f in os.listdir(os.getcwd()): if f[-5:] == '.root': print f,len(f),len(filename) fin = TFile.Open(os.getcwd() + '/' + filename) assert(fin) other = fin.Get(wsname) #pull unbinned data from other workspace self.loadDataFromWorkspace(other) #pull in histogram pdfs to save time self.loadHistogramsFromWorkspace(other) if getFloatPars and other.loadSnapshot('fitPars'): self.useImportPars = True self.ws.saveSnapshot('importParams', other.set('floatingParams'), True) # self.ws.Print() # put together a fitting model and return the pdf def makeFitter(self, useAlternateModels = False): if self.ws.pdf('total'): return self.ws.pdf('total') compPdfs = [] for component in self.pars.backgrounds: # print 'getting compModels' compModels = getattr(self.pars, '%sModels' % component) if hasattr(self.pars, '%sConvModels' % component): convModels = getattr(self.pars, '%sConvModels' % component) else: convModels = None if useAlternateModels: print 'loading Alternate Models' compModels = getattr(self.pars, '%sModelsAlt' % component) convModels = getattr(self.pars, '%sConvModelsAlt' % component) # print 'compModels = %s' % compModels compFiles = getattr(self.pars, '%sFiles' % component) compPdf = self.makeComponentPdf(component, compFiles, compModels, useAlternateModels, convModels) norm = self.ws.factory('prod::f_%s_norm' % component + \ '(n_%s[0.,1e6],' % component + \ '%s_nrm[1.,-0.5,5.])' % component) self.ws.var('n_%s' % component).setConstant(True) if hasattr(self, '%sExpected' % component): self.ws.var('n_%s' % component).setVal( getattr(self, '%sExpected' % component)) compPdfs.append( self.ws.factory('RooExtendPdf::%s_extended(%s,%s)' % \ (compPdf.GetName(), compPdf.GetName(), norm.GetName()) ) ) self.ws.factory('r_signal[0., -200., 200.]') self.ws.var('r_signal').setConstant(False) try: obs = [ self.pars.varNames[x] for x in self.pars.var ] except AttributeError: obs = self.pars.var for component in self.pars.signals: compFile = getattr(self.pars, '%sFiles' % component) compModels = getattr(self.pars, '%sModels' % component) if hasattr(self.pars, '%sConvModels' % component): convModels = getattr(self.pars, '%sConvModels' % component) else: convModels = None compPdf = self.makeComponentPdf(component, compFiles, compModels, useAlternateModels, convModels) norm = self.ws.factory( "prod::f_%s_norm(n_%s[0., 1e6],r_signal)" % \ (component, component) ) self.ws.var('n_%s' % component).setConstant(True) if hasattr(self, '%sExpected' % component): self.ws.var('n_%s' % component).setVal( getattr(self, '%sExpected' % component)) pdf = self.ws.factory('RooExtendPdf::%s_extended(%s,%s)' % \ (compPdf.GetName(), compPdf.GetName(), norm.GetName()) ) if (hasattr(self.pars, '%sInterference' % component)) and \ getattr(self.pars, '%sInterference' % component): getattr(self.ws, 'import') \ (pdf, RooFit.RenameAllNodes('interf_%sUp' % component), RooFit.RenameAllVariablesExcept('interf_%sUp' % component, ','.join(obs)), RooFit.Silence() ) getattr(self.ws, 'import') \ (pdf, RooFit.RenameAllNodes('interf_%sDown' % component), RooFit.RenameAllVariablesExcept('interf_%sDown'%component, ','.join(obs)), RooFit.Silence() ) if self.pars.includeSignal: compPdfs.append(pdf) #print compPdfs prodList = [ '%s' % (pdf.GetName()) \ for (idx, pdf) in enumerate(compPdfs) ] comps = RooArgList(self.ws.argSet(','.join(prodList))) getattr(self.ws, 'import')(RooAddPdf('total', 'total', comps)) return self.ws.pdf('total') # define the constraints on the yields, etc that will be part of the fit. def makeConstraints(self): if self.ws.set('constraintSet'): return self.ws.set('constraintSet') constraints = [] constrainedParameters = [] for constraint in self.pars.yieldConstraints: theYield = self.ws.var('%s_nrm' % constraint) if not theYield.isConstant(): self.ws.factory('RooGaussian::%s_const(%s, 1.0, %f)' % \ (constraint, theYield.GetName(), self.pars.yieldConstraints[constraint]) ) constraints.append('%s_const' % constraint) constrainedParameters.append(theYield.GetName()) if hasattr(self.pars, 'constrainShapes'): for component in self.pars.constrainShapes: pc = self.ws.pdf(component).getParameters(self.ws.set('obsSet')) parIter = pc.createIterator() par = parIter.Next() while par: if not par.isConstant(): theConst = self.ws.factory('RooGaussian::%s_const' % \ (par.GetName()) + \ '(%s, %f, %f)' % \ (par.GetName(), par.getVal(), par.getError()) ) constraints.append(theConst.GetName()) constrainedParameters.append(par.GetName()) par = parIter.Next() pc.IsA().Destructor(pc) self.ws.defineSet('constraintSet', ','.join(constraints)) self.ws.defineSet('constrainedSet', ','.join(constrainedParameters)) return self.ws.set('constraintSet') # fit the data using the pdf def fit(self, keepParameterValues = False): print 'construct fit pdf ...' fitter = self.makeFitter() print 'load data ...' data = self.loadData() self.resetYields() constraintSet = self.makeConstraints() if not keepParameterValues: self.readParametersFromFile() self.resetYields() # print constraints, self.pars.yieldConstraints print '\nfit constraints' constIter = constraintSet.createIterator() constraint = constIter.Next() constraints = [] while constraint: constraint.Print() constraints.append(constraint.GetName()) constraint = constIter.Next() constraintCmd = RooCmdArg.none() if constraintSet.getSize() > 0: constraints.append(fitter.GetName()) fitter = self.ws.pdf('totalFit_const') if not fitter: fitter = self.ws.factory('PROD::totalFit_const(%s)' % \ (','.join(constraints)) ) constraintCmd = RooFit.Constrained() # constraintCmd = RooFit.ExternalConstraints(self.ws.set('constraintSet')) if self.useImportPars: self.ws.loadSnapshot('importParams') self.ws.Print() # for constraint in pars.constraints: # self.ws.pdf(constraint).Print() # print rangeCmd = RooCmdArg.none() if self.rangeString and self.pars.doExclude: rangeCmd = RooFit.Range(self.rangeString) print 'fitting ...' fr = fitter.fitTo(data, RooFit.Save(True), RooFit.Extended(True), RooFit.Minos(False), RooFit.PrintEvalErrors(-1), RooFit.Warnings(False), constraintCmd, rangeCmd) fr.Print() return fr # determine the fitting model for each component and return them def makeComponentPdf(self, component, files, models, useAlternateModels, convModels): print 'making ComponentPdf %s' % component # print 'models = %s' % models # print 'files = %s' % files if convModels and not (convModels[0] == -1): thePdf = self.makeConvolvedPdf(component, files, models, useAlternateModels, convModels) elif (models[0] == -1): thePdf = self.makeComponentHistPdf(component, files) elif (models[0] == -2): thePdf = self.makeMorphingPdf(component, useAlternateModels, convModels) elif (models[0] == -3): pass else: thePdf = self.makeComponentAnalyticPdf(component, models, useAlternateModels) return thePdf #create a simple 2D histogram pdf def makeComponentHistPdf(self, component, files): if self.ws.pdf(component): return self.ws.pdf(component) compHist = self.utils.newEmptyHist('hist%s' % component) sumYields = 0. sumxsec = 0. sumExpected = 0. for (idx,fset) in enumerate(files): if hasattr(self.pars, '%scuts' % component): cutOverride = getattr(self.pars, '%scuts' % component) else: cutOverride = None filename = fset[0] tmpHist = self.utils.File2Hist(filename, 'hist%s_%i' % (component, idx), False,cutOverride,False,True,0) sumYields += tmpHist.Integral() sumxsec += fset[2] compHist.Add(tmpHist, self.pars.integratedLumi*fset[2]/fset[1]) sumExpected += tmpHist.Integral()*fset[2]* \ self.pars.integratedLumi/fset[1] print filename,'acc x eff: %.3g' % (tmpHist.Integral()/fset[1]) print filename,'N_expected: %.1f' % \ (tmpHist.Integral()*fset[2]*self.pars.integratedLumi/fset[1]) #tmpHist.Print() #compHist.Print() print '%s acc x eff: %.3g' % \ (component, sumExpected/sumxsec/self.pars.integratedLumi) print 'Number of expected %s events: %.1f' % (component, sumExpected) setattr(self, '%sExpected' % component, sumExpected) return self.utils.Hist2Pdf(compHist, component, self.ws, self.pars.order) #create a pdf which is a convolution of any two pdf def makeConvolvedPdf(self, component, files, models, useAlternateModels, convModels): if self.ws.pdf(component): return self.ws.pdf(component) #If a morphing model is selected, then convolve each individual component first and then morph if (models[0] == -2): return self.makeMorphingPdf(component, useAlternateModels, convModels) basePdf = self.makeComponentPdf('%s_base' % component, files, models, useAlternateModels, [-1]) convComponent = 'Global' ##Overwrite to use the same convolution model for all Pdfs convModel = getattr(self.pars, '%sConvModels' % convComponent) if useAlternateModels: convModel = getattr(self.pars, '%sConvModelsAlt' % convComponent) convPdf = self.makeComponentPdf('%s_conv' % convComponent, files, convModel, useAlternateModels, [-1]) var = self.pars.var[0] try: vName = self.pars.varNames[var] except AttributeError: vName = var self.ws.factory('RooFFTConvPdf::%s(%s,%s,%s)' % \ (component, vName, basePdf.GetName(), convPdf.GetName())) return self.ws.pdf(component) # create a pdf using the "template morphing" technique def makeMorphingPdf(self, component, useAlternateModels, convModels): if self.ws.pdf(component): return self.ws.pdf(component) filesNom = getattr(self.pars, '%s_NomFiles' % component) modelsNom = getattr(self.pars, '%s_NomModels' % component) filesMU = getattr(self.pars, '%s_MUFiles' % component) modelsMU = getattr(self.pars, '%s_MUModels' % component) filesMD = getattr(self.pars, '%s_MDFiles' % component) modelsMD = getattr(self.pars, '%s_MDModels' % component) filesSU = getattr(self.pars, '%s_SUFiles' % component) modelsSU = getattr(self.pars, '%s_SUModels' % component) filesSD = getattr(self.pars, '%s_SDFiles' % component) modelsSD = getattr(self.pars, '%s_SDModels' % component) if useAlternateModels: modelsNom = getattr(self.pars, '%s_NomModelsAlt' % component) modelsMU = getattr(self.pars, '%s_MUModelsAlt' % component) modelsMD = getattr(self.pars, '%s_MDModelsAlt' % component) modelsSU = getattr(self.pars, '%s_SUModelsAlt' % component) modelsSD = getattr(self.pars, '%s_SDModelsAlt' % component) # Adds five (sub)components for the component with suffixes Nom, MU, MD, SU, SD NomPdf = self.makeComponentPdf('%s_Nom' % component, filesNom, modelsNom, False, convModels) if hasattr(self, '%s_NomExpected' % component): setattr(self, '%sExpected' % component, getattr(self, '%s_NomExpected' % component)) MUPdf = self.makeComponentPdf('%s_MU' % component, filesMU, modelsMU, False, convModels) MDPdf = self.makeComponentPdf('%s_MD' % component, filesMD, modelsMD, False, convModels) SUPdf = self.makeComponentPdf('%s_SU' % component, filesSU, modelsSU, False, convModels) SDPdf = self.makeComponentPdf('%s_SD' % component, filesSD, modelsSD, False, convModels) fMU_comp = self.ws.factory("fMU_%s[0., -1., 1.]" % component) fSU_comp = self.ws.factory("fSU_%s[0., -1., 1.]" % component) fMU = RooFormulaVar("f_fMU_%s" % component, "1.0*@0*(@0 >= 0.)", RooArgList( fMU_comp ) ) fMD = RooFormulaVar("f_fMD_%s" % component, "-1.0*@0*(@0 < 0.)", RooArgList( fMU_comp ) ) fSU = RooFormulaVar("f_fSU_%s" % component, "@0*(@0 >= 0.)", RooArgList( fSU_comp ) ) fSD = RooFormulaVar("f_fSD_%s" % component, "@0*(-1)*(@0 < 0.)", RooArgList( fSU_comp ) ) fNom = RooFormulaVar("f_fNom_%s" % component, "(1.-abs(@0)-abs(@1))", RooArgList(fMU_comp,fSU_comp) ) morphPdf = RooAddPdf(component,component, RooArgList(MUPdf,MDPdf,SUPdf,SDPdf,NomPdf), RooArgList(fMU, fMD, fSU, fSD, fNom)) morphPdf.SetName(component) getattr(self.ws, 'import')(morphPdf) return self.ws.pdf(component) # create a pdf using an analytic function. def makeComponentAnalyticPdf(self, component, models, useAlternateModels): if self.ws.pdf(component): return self.ws.pdf(component) pdfList = [] for (idx,model) in enumerate(models): var = self.pars.var[idx] try: vName = self.pars.varNames[var] except AttributeError: vName = var auxModel = None if useAlternateModels: if hasattr(self.pars, '%sAuxModelsAlt' % component): auxModel = getattr(self.pars, '%sAuxModelsAlt' % component)[idx] else: if hasattr(self.pars, '%sAuxModels' % component): auxModel = getattr(self.pars, '%sAuxModels' % component)[idx] pdfList.append(self.utils.analyticPdf(self.ws, vName, model, '%s_%s'%(component,vName), '%s_%s'%(component,vName), auxModel ) ) pdfListNames = [ pdf.GetName() for pdf in pdfList ] if len(pdfList) > 1: self.ws.factory('PROD::%s(%s)' % \ (component, ','.join(pdfListNames))) else: pdfList[0].SetName(component) return self.ws.pdf(component) def loadData(self, weight = False): if self.ws.data('data_obs'): return self.ws.data('data_obs') unbinnedName = 'data_obs' if self.pars.binData: unbinnedName = 'data_unbinned' data = self.utils.File2Dataset(self.pars.DataFile, unbinnedName, self.ws, weighted = weight) if self.pars.binData: data = RooDataHist('data_obs', 'data_obs', self.ws.set('obsSet'), data) getattr(self.ws, 'import')(data) data = self.ws.data('data_obs') return data def stackedPlot(self, var, logy = False, pdfName = None, Silent = False): if not pdfName: pdfName = 'total' xvar = self.ws.var(var) nbins = xvar.getBins() if hasattr(self.pars, 'plotRanges'): xvar.setRange('plotRange', self.pars.plotRanges[var][1], self.pars.plotRanges[var][2]) xvar.setBins(self.pars.plotRanges[var][0], 'plotBins') else: xvar.setRange('plotRange', xvar.getMin(), xvar.getMax()) xvar.setBins(nbins, 'plotBins') sframe = xvar.frame() sframe.SetName("%s_stacked" % var) pdf = self.ws.pdf(pdfName) if isinstance(pdf, RooAddPdf): compList = RooArgList(pdf.pdfList()) else: compList = None data = self.ws.data('data_obs') nexp = pdf.expectedEvents(self.ws.set('obsSet')) if not Silent: print pdf.GetName(),'expected: %.0f' % (nexp) print 'data events: %.0f' % (data.sumEntries()) if nexp < 1: nexp = data.sumEntries() theComponents = [] if self.pars.includeSignal: theComponents += self.pars.signals theComponents += self.pars.backgrounds data.plotOn(sframe, RooFit.Invisible(), RooFit.Binning('plotBins')) # dataHist = RooAbsData.createHistogram(data,'dataHist_%s' % var, xvar, # RooFit.Binning('%sBinning' % var)) # #dataHist.Scale(1., 'width') # invData = RooHist(dataHist, 1., 1, RooAbsData.SumW2, 1.0, False) # #invData.Print('v') # sframe.addPlotable(invData, 'pe', True, True) for (idx,component) in enumerate(theComponents): if not Silent: print 'plotting',component,'...', if hasattr(self.pars, '%sPlotting' % (component)): plotCharacteristics = getattr(self.pars, '%sPlotting' % \ (component)) else: plotCharacteristics = {'color' : colorwheel[idx%6], 'title' : component } compCmd = RooCmdArg.none() if compList: compSet = RooArgSet(compList) if compSet.getSize() > 0: compCmd = RooFit.Components(compSet) removals = compList.selectByName('%s*' % component) compList.remove(removals) if not Silent: print 'events', self.ws.function('f_%s_norm' % component).getVal() sys.stdout.flush() if abs(self.ws.function('f_%s_norm' % component).getVal()) >= 1.: pdf.plotOn(sframe, #RooFit.ProjWData(data), RooFit.DrawOption('LF'), RooFit.FillStyle(1001), RooFit.FillColor(plotCharacteristics['color']), RooFit.LineColor(plotCharacteristics['color']), RooFit.VLines(), RooFit.Range('plotRange'), RooFit.NormRange('plotRange'), RooFit.Normalization(nexp, RooAbsReal.NumEvent), compCmd ) tmpCurve = sframe.getCurve() tmpCurve.SetName(component) tmpCurve.SetTitle(plotCharacteristics['title']) if 'visible' in plotCharacteristics: sframe.setInvisible(component, plotCharacteristics['visible']) data.plotOn(sframe, RooFit.Name('theData'), RooFit.Binning('plotBins')) sframe.getHist('theData').SetTitle('data') # theData = RooHist(dataHist, 1., 1, RooAbsData.SumW2, 1.0, True) # theData.SetName('theData') # theData.SetTitle('data') # sframe.addPlotable(theData, 'pe') if (logy): sframe.SetMinimum(0.01) sframe.SetMaximum(1.0e6) else: sframe.SetMaximum(sframe.GetMaximum()*1.35) pass excluded = (var in self.pars.exclude) bname = var if not excluded: for v in self.pars.exclude: if hasattr(self.pars, 'varNames') and \ (self.pars.varNames[v] == var): excluded = True bname = v if excluded: blinder = TBox(self.pars.exclude[bname][0], sframe.GetMinimum(), self.pars.exclude[bname][1], sframe.GetMaximum()) # blinder.SetName('blinder') # blinder.SetTitle('signal region') blinder.SetFillColor(kBlack) if self.pars.blind: blinder.SetFillStyle(1001) else: blinder.SetFillStyle(0) blinder.SetLineStyle(2) sframe.addObject(blinder) elif self.pars.blind: if not Silent: print "blind but can't find exclusion region for", var print 'excluded',excluded,self.pars.exclude print 'hiding data points' sframe.setInvisible('theData', True) #sframe.GetYaxis().SetTitle('Events / GeV') # dataHist.IsA().Destructor(dataHist) if not Silent: print xvar.setBins(nbins) return sframe def readParametersFromFile(self, fname=None): if (not fname): fname = self.pars.initialParametersFile if isinstance(fname, str): flist = [ fname ] else: flist = fname for tmpName in flist: if len(tmpName) > 0: print 'loading parameters from file',tmpName self.ws.allVars().readFromFile(tmpName) def expectedFromPars(self): components = self.pars.signals + self.pars.backgrounds for component in components: theYield = self.ws.var('n_%s' % component) setattr(self, '%sExpected' % component, theYield.getVal()) def initFromExplicitVals(self,opts): #,init_diboson= -1.0,init_WpJ=-1.0,init_top=-1.0,init_ZpJ=-1.0,init_QCD=-1.0 components = ['diboson', 'top', 'WpJ', 'ZpJ', 'QCD', 'WHbb'] for component in components: #double init init = getattr(opts, 'ext%s' % component) #init = -2.0 #setattr(self,init, 'init_%s' % component) #init = init_%s % component #print "init=", init #init = self.ws.var('init_%s' % component) #init.setVal(100.0) #init.setVal('init_%s' % component) #init = theYield.getVal() if (init>0.): print 'setting initial value for ',component,' to ',init setattr(self, '%sInitial' % component, init) def resetYields(self): if self.ws.data('data_obs'): Ndata = self.ws.data('data_obs').sumEntries() else: Ndata = 10000. print 'resetting yields...' components = self.pars.signals + self.pars.backgrounds for component in components: theYield = self.ws.var('n_%s' % component) theNorm = self.ws.var('%s_nrm' % component) if hasattr(self, '%sInitial' % component): print 'explicitly setting initial value for ',component theYield.setVal(getattr(self, '%sInitial' % component)) theNorm.setVal(1.0) theNorm.setConstant() else: fracofdata = -1. if hasattr(self.pars, '%sFracOfData' % component): fracofdata = getattr(self.pars, '%sFracOfData' % component) if (fracofdata >= 0.): print 'explicitly setting ', component,' yield to be', fracofdata,' of data' theYield.setVal(fracofdata*Ndata) elif hasattr(self, '%sExpected' % component): theYield.setVal(getattr(self, '%sExpected' % component)) else: print 'no expected value for',component theYield.setVal(Ndata/len(components)) if theNorm and not theNorm.isConstant(): theNorm.setVal(1.0) if component in self.pars.yieldConstraints: theYield.setError(theYield.getVal() * \ self.pars.yieldConstraints[component]) if theNorm: theNorm.setError(self.pars.yieldConstraints[component]) else: theYield.setError(sqrt(theYield.getVal())) theYield.Print() def generateToyMCSet(self,var,inputPdf,outFileName,NEvts): fMC = TFile(outFileName, "RECREATE"); # thevar = self.ws.var(var); print 'thevar=' print var # print thevar print '...' # varList = RooArgList() # varList.add(self.ws.var(var)) toymc = inputPdf.generate(RooArgSet(self.ws.var(var)),NEvts); tMC = toymc.tree(); fMC.cd(); tMC.Write(); fMC.Close(); def legend4Plot(plot, left = False): if left: theLeg = TLegend(0.2, 0.62, 0.55, 0.92, "", "NDC") else: theLeg = TLegend(0.60, 0.62, 0.92, 0.92, "", "NDC") theLeg.SetName('theLegend') theLeg.SetBorderSize(0) theLeg.SetLineColor(0) theLeg.SetFillColor(0) theLeg.SetFillStyle(0) theLeg.SetLineWidth(0) theLeg.SetLineStyle(0) theLeg.SetTextFont(42) theLeg.SetTextSize(.045) entryCnt = 0 for obj in range(0, int(plot.numItems())): objName = plot.nameOf(obj) if (not plot.getInvisible(objName)): theObj = plot.getObject(obj) objTitle = theObj.GetTitle() if len(objTitle) < 1: objTitle = objName dopts = plot.getDrawOptions(objName).Data() # print 'obj:',theObj,'title:',objTitle,'opts:',dopts,'type:',type(dopts) if theObj.IsA().InheritsFrom('TNamed'): theLeg.AddEntry(theObj, objTitle, dopts) entryCnt += 1 theLeg.SetY1NDC(0.9 - 0.05*entryCnt - 0.005) theLeg.SetY1(theLeg.GetY1NDC()) return theLeg legend4Plot = staticmethod(legend4Plot)
from ROOT import RooWorkspace workspace = RooWorkspace("electron_channel_2orMoreBtags") workspace.factory('lepton_AbsoluteEta[0]') workspace.factory('lumi[0]') workspace.factory('n_signal[2200,0,10000]') workspace.factory('n_VPlusJets[200,0,10000]') workspace.factory('n_QCD[10,0,10000]') workspace.factory('sum::yield(n_signal,n_VPlusJets,n_QCD)') workspace.factory("Poisson::model_core(n,yield)") workspace.factory("lumi[0]") # cross section - parameter of interest workspace.factory("xsec[0,0,0.1]") # selection efficiency * acceptance workspace.factory("efficiency[0]") # signal yield workspace.factory("prod::nsig(lumi,xsec,efficiency)") workspace.factory("Uniform::prior(xsec)") workspace.Print() workspace.SaveAs('electron_channel_2orMoreBtags.root')
RooFit.Strategy(args.fitStrategy)) if not args.decoBkg: res.Print() # decorrelated background parameters for Bayesian limits if args.decoBkg: signal_norm.setConstant() res = model.fitTo(rooDataHist, RooFit.Save(kTRUE), RooFit.Strategy(args.fitStrategy)) res.Print() ## temp workspace for the PDF diagonalizer w_tmp = RooWorkspace("w_tmp") deco = PdfDiagonalizer("deco", w_tmp, res) # here diagonalizing only the shape parameters since the overall normalization is already decorrelated background_deco = deco.diagonalize(background) print "##################### workspace for decorrelation" w_tmp.Print("v") print "##################### original parameters" background.getParameters(rooDataHist).Print("v") print "##################### decorrelated parameters" # needed if want to evaluate limits without background systematics if args.fixBkg: w_tmp.var("deco_eig1").setConstant() w_tmp.var("deco_eig2").setConstant() if not args.fixP3: w_tmp.var("deco_eig3").setConstant() background_deco.getParameters(rooDataHist).Print("v") print "##################### original pdf" background.Print() print "##################### decorrelated pdf" background_deco.Print() # release signal normalization signal_norm.setConstant(kFALSE)
DTF_D0sPi_M = RooFormulaVar( "DTF_D0sPi_M", "DTF_D0sPi_M", "TMath::Sqrt(1865**2+sPi_M**2 + 2*(Dst_DTF_D0_PE*Dst_DTF_sPi_PE - (Dst_DTF_D0_PX*Dst_DTF_sPi_PX+Dst_DTF_D0_PY*Dst_DTF_sPi_PY+Dst_DTF_D0_PZ*Dst_DTF_sPi_PZ)))", RooArgList(sPi_M, Dst_DTF_D0_PE, Dst_DTF_sPi_PE, Dst_DTF_D0_PX, Dst_DTF_sPi_PX, Dst_DTF_D0_PY, Dst_DTF_sPi_PY, Dst_DTF_D0_PZ, Dst_DTF_sPi_PZ)) dataset_WS.addColumn(DTF_D0sPi_M).setRange(1700, 2100) dataset_RS.addColumn(DTF_D0sPi_M).setRange(1700, 2100) try: test_mode = sys.argv[2] except: test_mode = False wspace = RooWorkspace("wspace") wspace.Print("t") if not test_mode: #Here is address of output file wsfile = TFile( "/afs/cern.ch/user/" + prefix + "/" + user + "/eos/lhcb/user/" + prefix + "/" + user + "/WrongSign/2015/WorkSpaces/WorkSpace" + id_seed + ".root", "recreate") else: wsfile = TFile("WorkSpace" + id_seed + ".root", "recreate") wspace.rfimport(varset) wspace.rfimport(varset_comb) wspace.rfimport(dataset_COMB_OS) wspace.rfimport(dataset_COMB_SS) wspace.rfimport(dataset_WS) wspace.rfimport(dataset_RS) wspace.Write("wspace")
pedDS.plotOn(xfped) if opts.sipm: ws.pdf('pedPlusOne').plotOn(xfped) ws.pdf('pedPlusOne').paramOn(xfped) else: ws.pdf('ped').plotOn(xfped) ws.pdf('ped').paramOn(xfped) c1 = TCanvas('c1', 'pedestal') xfped.Draw() makeHistPdf(ped_hist, ws, x) savePedWidth = ws.var('pedWidth').getVal() ws.Print() dataTree.Draw( '{0}>>sig_hist({1},{2:0.1f},{3:0.1f})'.format(HOTower, Nbins, minMip, maxMip), sigCut, 'goff') sig_hist = gDirectory.Get('sig_hist') x.setRange(minMip, maxMip) if (sig_hist.GetEntries > 0): ## fpar = array('d', [0.]*7) ## fparerr = array('d', [0.]*7) ## fpar[6] = pedRms ## chisqr = Double(0.) ## ndf = Long(0)
def ControlDataFit(free=True, sim=True): w = RooWorkspace('w_ctrl', 'w_ctrl') samples = ['b0g', 'bsg', 'cg', 'b0pi0', 'bspi0', 'cpi0'] # create the category w.factory('cat[%s]' % (','.join(samples))) files = { 'b0g': path + "../New/Tuples/Data/9_B2DstKpi_Dst2DgammTuple_BestCut.root", 'b0pi0': path + "../New/Tuples/Data/9_B2Dstpi0Tuple_BestCut.root", 'bsg': path + "../New/Tuples/Data/9_Bs2DstKpi_Dst2DgammaTuple_BestCut.root", 'bspi0': path + "../New/Tuples/Data/9_Bs2Dstpi0Tuple_BestCut.root", 'cg': path + "../New/Tuples/Data/9_B2Dstpipi_Dst2DgammTuple_BestCut.root", 'cpi0': path + "../New/Tuples/Data/9_B2Dstpipi_Dst2Dpi0Tuple_No16_BestCut.root" } # Make the dsets w.factory("B_DTFDict_D0_B_M[5100,5900]") w.var("B_DTFDict_D0_B_M").setBins(80) for samp in samples: assert (os.path.exists(files[samp])) tf = TFile(files[samp]) t = tf.Get('DecayTree') t.SetBranchStatus("*", 0) t.SetBranchStatus("B_DTFDict_D0_B_M", 1) dset = RooDataSet("data_%s" % (samp), "", t, RooArgSet(w.var("B_DTFDict_D0_B_M"))) getattr(w, 'import')(dset) tf.Close() c = TCanvas('ctrl', 'ctrl', 2100, 1200) c.Divide(3, 2) for i, samp in enumerate(samples): pdfname = 'data_pdf_%s' % (samp) dsetname = 'data_%s' % (samp) plot(c.cd(i + 1), w, pdfname, dsetname) c.Update() c.Modified() c.Print("plots/ctrl.pdf") # Make the total pdf # First try and merge the different bits from the different workspaces ImportMCShapes(w) # now want to make the ctrl pdfs # signal and misrec are the same as b0 sig_cg = w.pdf('sig_mc_pdf_b0g').Clone('sig_mc_pdf_cg') getattr(w, 'import')(sig_cg) sig_cpi0 = w.pdf('sig_mc_pdf_b0pi0').Clone('sig_mc_pdf_cpi0') getattr(w, 'import')(sig_cpi0) misrec_cg = w.pdf('misrec_mc_pdf_b0g').Clone('misrec_mc_pdf_cg') getattr(w, 'import')(misrec_cg) misrec_cpi0 = w.pdf('misrec_mc_pdf_b0pi0').Clone('misrec_mc_pdf_cpi0') getattr(w, 'import')(misrec_cpi0) # ignore the lambdas for now # there will be some Bs0 -> D*0 piK stuff with a misID'd K (I think this is the big bit which appears below the peak) # do 1CB for this w.factory('dm_ctrl_misidk2pi[-150,-450,-50]') w.factory('sum::bdstkp_cg_mean( b0g_mean, dm_ctrl_misidk2pi)') w.factory('sum::bdstkp_cpi0_mean( b0pi0_mean, dm_ctrl_misidk2pi)') w.factory('bdstkp_cg_sigma[40,5,200]') w.factory('bdstkp_cpi0_sigma[40,5,200]') w.factory('bdstkp_c_alpha1[-2.1,-4,0]') w.factory('bdstkp_c_n1[3]') w.factory( 'CBShape::bdstkp_mc_pdf_cg( B_DTFDict_D0_B_M, bdstkp_cg_mean, bdstkp_cg_sigma, bdstkp_c_alpha1, bdstkp_c_n1 )' ) w.factory( 'CBShape::bdstkp_mc_pdf_cpi0( B_DTFDict_D0_B_M, bdstkp_cpi0_mean, bdstkp_cpi0_sigma, bdstkp_c_alpha1, bdstkp_c_n1 )' ) # the stuff above the peak is probably mostly B- -> D*0 pi- with another random pi so could get this shape and shift it w.factory('dm_ctrl_dstpi[100,10,300]') w.factory('sum::bdsth_cg_mean( bdsth_b0g_mean, dm_ctrl_dstpi )') w.factory('sum::bdsth_cpi0_mean( bdsth_b0pi0_mean, dm_ctrl_dstpi )') w.factory( "CBShape::bdsth_cg_cb1( B_DTFDict_D0_B_M, bdsth_cg_mean, bdsth_b0g_sigma, bdsth_alpha1, bdsth_n1 )" ) w.factory( "CBShape::bdsth_cg_cb2( B_DTFDict_D0_B_M, bdsth_cg_mean, bdsth_b0g_sigma, bdsth_alpha2, bdsth_n2 )" ) w.factory("SUM::bdsth_mc_pdf_cg( bdsth_f1*bdsth_cg_cb1, bdsth_cg_cb2 )") w.factory( "CBShape::bdsth_cpi0_cb1( B_DTFDict_D0_B_M, bdsth_cpi0_mean, bdsth_b0pi0_sigma, bdsth_alpha1, bdsth_n1 )" ) w.factory( "CBShape::bdsth_cpi0_cb2( B_DTFDict_D0_B_M, bdsth_cpi0_mean, bdsth_b0pi0_sigma, bdsth_alpha2, bdsth_n2 )" ) w.factory( "SUM::bdsth_mc_pdf_cpi0( bdsth_f1*bdsth_cpi0_cb1, bdsth_cpi0_cb2 )") # Then make combinatorial shape in each cateogry # let these be independent for now for samp in samples: w.factory("comb_mc_%s_p0[-0.001,-0.1,0.]" % samp) w.factory( "Exponential::comb_mc_pdf_%s( B_DTFDict_D0_B_M, comb_mc_%s_p0 )" % (samp, samp)) w.factory("%s_comb_y[3000,0,12000]" % samp) # Now need to figure out what yields to restrict # sig yield first (require b0 / bs ratio consistent between g and pi0) w.factory("b0g_sig_y[3000,0,12000]") w.factory("b0pi0_sig_y[800,0,4000]") w.factory("bs2b0_rat[2.5,1.,4.]") w.factory("prod::bsg_sig_y(b0g_sig_y, bs2b0_rat)") w.factory("prod::bspi0_sig_y(b0pi0_sig_y, bs2b0_rat)") w.factory("cg_sig_y[6000,0,32000]") w.factory("cpi0_sig_y[1000,0,8000]") # now mis rec yield (ratio of this to sig should be the same for b0 and bs but will be different for g vs pi0) w.factory("misrec_to_sig_rat_g[0.2,0.001,0.6]") w.factory("misrec_to_sig_rat_pi0[0.2,0.001,0.6]") w.factory("prod::b0g_misrec_y( misrec_to_sig_rat_g, b0g_sig_y )") w.factory("prod::b0pi0_misrec_y( misrec_to_sig_rat_pi0, b0pi0_sig_y )") w.factory("prod::bsg_misrec_y( misrec_to_sig_rat_g, bsg_sig_y )") w.factory("prod::bspi0_misrec_y( misrec_to_sig_rat_pi0, bspi0_sig_y )") w.factory("prod::cg_misrec_y( misrec_to_sig_rat_g, cg_sig_y )") w.factory("prod::cpi0_misrec_y( misrec_to_sig_rat_pi0, cpi0_sig_y )") # the cases of B->D*pipi, B->D*KK, Lb->D*ph all involve a misID so will # be different for B0 and Bs (as they differ with a K or pi misID) however # for all of these the ratio of g -> pi0 should be the same # there is also Bs->D*KK which should scale the same for g and pi0 modes w.factory("misid_g2pi0_rat[0.1,0.0001,10.]") w.factory("b0g_bdstpp_y[1000,0,12000]") w.factory("bsg_bdstpp_y[1000,0,12000]") w.factory("prod::b0pi0_bdstpp_y( misid_g2pi0_rat, b0g_bdstpp_y )") w.factory("prod::bspi0_bdstpp_y( misid_g2pi0_rat, bsg_bdstpp_y )") w.factory("b0g_bdstkk_y[1000,0,12000]") w.factory("bsg_bdstkk_y[1000,0,12000]") w.factory("prod::b0pi0_bdstkk_y( misid_g2pi0_rat, b0g_bdstkk_y )") w.factory("prod::bspi0_bdstkk_y( misid_g2pi0_rat, bsg_bdstkk_y )") w.factory("b0g_lbdstph_y[1000,0,12000]") w.factory("bsg_lbdstph_y[1000,0,12000]") w.factory("prod::b0pi0_lbdstph_y( misid_g2pi0_rat, b0g_lbdstph_y )") w.factory("prod::bspi0_lbdstph_y( misid_g2pi0_rat, bsg_lbdstph_y )") w.factory("bsdstkk_to_bdstkk_rat[1.,0.1,2.]") w.factory("prod::b0g_bsdstkk_y( bsdstkk_to_bdstkk_rat, b0g_bdstkk_y )") w.factory("prod::b0pi0_bsdstkk_y( bsdstkk_to_bdstkk_rat, b0pi0_bdstkk_y )") w.factory("prod::bsg_bsdstkk_y( bsdstkk_to_bdstkk_rat, bsg_bdstkk_y )") w.factory("prod::bspi0_bsdstkk_y( bsdstkk_to_bdstkk_rat, bspi0_bdstkk_y )") # B -> DKpi same logic as misrec w.factory("bdkp_to_sig_rat_g[0.2,0.001,0.6]") w.factory("bdkp_to_sig_rat_pi0[0.2,0.001,0.6]") w.factory("prod::b0g_bdkp_y( bdkp_to_sig_rat_g, b0g_sig_y )") w.factory("prod::b0pi0_bdkp_y( bdkp_to_sig_rat_pi0, b0pi0_sig_y )") w.factory("prod::bsg_bdkp_y( bdkp_to_sig_rat_g, bsg_sig_y )") w.factory("prod::bspi0_bdkp_y( bdkp_to_sig_rat_pi0, bspi0_sig_y )") # infact can be much more sophisitcated with efficiencies etc here # i.e. if the PID cut distinguishing B -> D0 Kpi from B -> D0 pipi is binary one knows the exact yield of the cross feed in each # the B -> DKp cross feed yield (float for now) w.factory("cg_bdstkp_y[3000,0,12000]") w.factory("cpi0_bdstkp_y[800,0,4000]") # B -> D* K / B -> D* pi (adding random pi- to B0 and random K- to Bs0) # so ratio to signal should be same for both g and pi0 modes but # different for B0 -> Bs w.factory("bdsth_to_sig_rat_addpi[0.2,0.001,0.6]") w.factory("bdsth_to_sig_rat_addk[0.2,0.001,0.6]") w.factory("prod::b0g_bdsth_y( bdsth_to_sig_rat_addpi, b0g_sig_y )") w.factory("prod::b0pi0_bdsth_y( bdsth_to_sig_rat_addpi, b0pi0_sig_y )") w.factory("prod::bsg_bdsth_y( bdsth_to_sig_rat_addk, bsg_sig_y )") w.factory("prod::bspi0_bdsth_y( bdsth_to_sig_rat_addk, bspi0_sig_y )") # the B- -> D* pi- (can probably constrain this better as well) w.factory("cg_bdsth_y[3000,0,12000]") w.factory("cpi0_bdsth_y[800,0,4000]") # Lb -> Dph (mid-ID k for p and pi for p and add random g or pi0) so will be different for all 4 really # express this ratio to the Lb -> D*ph one (they should be similar in magnitude?) w.factory("lbdph_to_lbdstph_b0g[1.,0.5,2.]") w.factory("lbdph_to_lbdstph_b0pi0[1.,0.5,2.]") w.factory("lbdph_to_lbdstph_bsg[1.,0.5,2.]") w.factory("lbdph_to_lbdstph_bspi0[1.,0.5,2.]") w.factory("prod::b0g_lbdph_y( lbdph_to_lbdstph_b0g, b0g_lbdstph_y )") w.factory("prod::b0pi0_lbdph_y( lbdph_to_lbdstph_b0pi0, b0pi0_lbdstph_y )") w.factory("prod::bsg_lbdph_y( lbdph_to_lbdstph_bsg, bsg_lbdstph_y )") w.factory("prod::bspi0_lbdph_y( lbdph_to_lbdstph_bspi0, bspi0_lbdstph_y )") # Part reco shape should have same Bs / B0 ratio w.factory("partrec_to_sig_rat_g[0.2,0.001,0.6]") w.factory("partrec_to_sig_rat_pi0[0.2,0.001,0.6]") w.factory("prod::b0g_partrec_y( partrec_to_sig_rat_g, b0g_sig_y )") w.factory("prod::b0pi0_partrec_y( partrec_to_sig_rat_pi0, b0pi0_sig_y )") w.factory("prod::bsg_partrec_y( partrec_to_sig_rat_g, bsg_sig_y )") w.factory("prod::bspi0_partrec_y( partrec_to_sig_rat_pi0, bspi0_sig_y )") # make the yields (different for ctrl and b0 / bs) b_components = [ 'sig', 'misrec', 'bdstpp', 'bdstkk', 'bsdstkk', 'bdkp', 'bdsth', 'partrec', 'lbdph', 'lbdstph', 'comb' ] for samp in ['b0g', 'b0pi0', 'bsg', 'bspi0']: fact_str = "SUM::data_pdf_%s(" % samp for comp in b_components: fact_str += "%s_%s_y*%s_mc_pdf_%s," % (samp, comp, comp, samp) fact_str = fact_str[:-1] + ")" w.factory(fact_str) w.pdf('data_pdf_%s' % samp).Print('v') ctrl_components = ['sig', 'misrec', 'bdstkp', 'bdsth', 'comb'] for samp in ['cg', 'cpi0']: fact_str = "SUM::data_pdf_%s(" % samp for comp in ctrl_components: fact_str += "%s_%s_y*%s_mc_pdf_%s," % (samp, comp, comp, samp) fact_str = fact_str[:-1] + ")" w.factory(fact_str) w.pdf('data_pdf_%s' % samp).Print('v') CreateSimPdf(w, 'data') CreateSimData(w, 'data') # Now fix appropriate parameters # To start with we'll fix all shape parameters from MC and just float the yields (and exponential slope) for comp in b_components: if comp == 'comb': continue # no pre-defined shape for combinatorial if comp == 'bsdstkk': continue # this params for this piece are covered by bdstkk w.set('%s_mc_sim_pdf_pars' % comp).setAttribAll("Constant") # Now relax the constraints on a few important params w.var("b0g_mean").setConstant(False) w.var("b0g_sigma").setConstant(False) #w.var("dm_b02bs").setConstant(False) #w.var("dm_g2pi0").setConstant(False) #w.var("ssig_b02bs").setConstant(False) #w.var("ssig_g2pi0").setConstant(False) #w.var("b0g_misrec_mean").setConstant(False) #w.var("b0g_misrec_sigma").setConstant(False) #w.var("dm_missg2addg").setConstant(False) #w.var("ssig_missg2addg").setConstant(False) w.Print('v') w.pdf('data_sim_pdf').Print('v') w.data('data_sim_data').Print('v') # free fit first if free: for i, samp in enumerate(samples): pdfname = 'data_pdf_%s' % (samp) dsetname = 'data_%s' % (samp) w.pdf(pdfname).fitTo( w.data(dsetname)) # nothing to fit in this case pars = w.pdf(pdfname).getParameters( RooArgSet(w.var("B_DTFDict_D0_B_M"))) w.saveSnapshot('data_free_fit_%s' % samp, pars) if sim: pdfname = 'data_sim_pdf' dsetname = 'data_sim_data' w.pdf(pdfname).fitTo(w.data(dsetname)) pars = w.pdf(pdfname).getParameters( RooArgSet(w.var("B_DTFDict_D0_B_M"))) w.saveSnapshot('data_sim_fit', pars) w.writeToFile('files/w_ctrl.root')
wsFN = outdir_datacards + 'Qstar' + str( mass) + '_workspace_' + name + '.root' nObs = dataHist_data.sumEntries() #nObs = roohistBkg.sumEntries(); #nBkg = roohistBkg.sumEntries(); w = RooWorkspace('w', 'workspace') getattr(w, 'import')(signal) getattr(w, 'import')(background) getattr(w, 'import')(background_norm) getattr(w, 'import')(roohistBkg, RooFit.Rename("data_obs")) #getattr(w,'import')(dataHist_data,RooFit.Rename("data_obs")) #getattr(w,'import')(background_f6) #getattr(w,'import')(background_f6_norm) w.Print() w.writeToFile(wsFN) # ----------------------------------------- # write a datacard ##not needed #ExpectedSignalRate = signalCrossSection*LUMI*signalEfficiency datacard = open(dcFN, 'w') datacard.write('imax 1\n') datacard.write('jmax 1\n') datacard.write('kmax *\n') datacard.write('---------------\n') datacard.write('shapes * * ' + wsFN + ' w:$PROCESS\n') datacard.write('---------------\n') datacard.write('bin 1\n')
def rooFit502(): print ">>> create workspace..." workspace = RooWorkspace("workspace", "workspace") print ">>> create typedef (shorthands)..." workspace.factory("$Typedef(Gaussian,Gaus)") workspace.factory("$Typedef(Chebychev,Cheby)") print ">>> operator pdf examples..." print ">>> SUM (coef1*pdf1,pdf2) - pdf addition" workspace.factory( "SUM::summodel( f[0,1]*Gaussian::gx(x[-10,10],m[0],1.0), Chebychev::ch(x,{0.1,0.2,-0.3}) )" ) print ">>> SUM (yield1*pdf1,yield2*pdf2) - extended pdf addition" workspace.factory("SUM::extsummodel( Nsig[0,1000]*gx, Nbkg[0,1000]*ch )") print ">>> PROD ( pdf1, pdf2 ) - pdf multiplication" # PDF multiplication is done with PROD ( pdf1, pdf2 ) workspace.factory("PROD::gxz( gx, Gaussian::gz(z[-10,10],0,1) )") print ">>> PROD ( pdf1|obs, pdf2 ) - conditional p.d.f multiplication" workspace.factory("Gaussian::gy( y[-10,10], x, 1.0 )") workspace.factory("PROD::gxycond( gy|x, gx )") print ">>> NCONV (obs,pdf1,pdf2) - numeric convolution" print ">>> FCONV (obs,pdf1,pdf2) - fft convolution" workspace.factory( "FCONV::lxg( x, Gaussian::g(x,mg[0],1), Landau::lc(x,0,1) )") print ">>> SIMUL( index, state1=pdf1, state2=pdf2,...) - simultaneous pdfs are constructed" workspace.factory( "SIMUL::smodel( c[A=0,B=1], A=Gaussian::gs(x,m,s[1]), B=Landau::ls(x,0,1) )" ) print ">>> operator function examples..." print ">>> prod (func1, func2,...) - function multiplication" workspace.factory("prod::uv(u[10],v[10])") print ">>> sum (func1, func2,...) - function addition" workspace.factory("sum::uv2(u,v)") print ">>> interpreted and compiled expression based pdfs..." print ">>> create a RooGenericPdf interpreted pdf by using single quotes to pass the expression string argument" workspace.factory("EXPR::G('x*x+1',x)") # Create a custom compiled p.d.f similar to the above interpreted p.d.f. # The code required to make this p.d.f. is automatically embedded in the workspace workspace.factory("CEXPR::GC('x*x+a',{x,a[1]})") # Compiled and interpreted functions (rather than pdfs) can be made with the lower case # 'expr' and 'cexpr' types print ">>> print workspace contents:" workspace.Print() print "\n>>> save workspace in memory..." gDirectory.Add(workspace)