def bkg_fit(tree, outputfile, branches): print "combinatorial" wspace, dataset, bMass, theBMass = define_workspace_bmass_data( "wspace_comb_bkg", branches[0], tree) wspace.factory('exp_alpha[-1.0, -100.0, -1.e-4]') wspace.factory('Exponential::bkg(x,exp_alpha)') wspace.factory('nbkg[1000,0,10e+6]') wspace.factory('RooExtendPdf::ebkg(bkg,nbkg)') nbkg = wspace.var('nbkg') ebkg = wspace.pdf('ebkg') results = ebkg.fitTo(dataset, RooFit.Extended(True), RooFit.Save(), RooFit.Range(4.7, 5.7), RooFit.PrintLevel(-1)) results.Print() bkgframe = theBMass.frame() dataset.plotOn(bkgframe, RooFit.Binning(nbin_data), RooFit.Name("datas")) ebkg.plotOn(bkgframe, RooFit.Name("ebkg"), RooFit.LineColor(49), RooFit.Normalization(1.0, ROOT.RooAbsReal.RelativeExpected), RooFit.LineWidth(3)) params = ebkg.getParameters(ROOT.RooArgSet(bMass)) #c1=canvas_create(bkgframe,4.7,5.7,nbin_data,'m (e^{+}e^{-}K) [GeV]') c1, top, bottom = canvas_create_pull(bkgframe, 4.7, 5.7, nbin_data, 'm(e^{+}e^{-}K) [GeV]', theBMass) top.cd() CMS_lumi() c1.SaveAs('bkg_comb_' + outputfile + '.pdf') n_param = results.floatParsFinal().getSize() print "chi2", bkgframe.chiSquare(n_param), "ndof", n_param print "edm", results.edm(), "log", results.minNll() residuals(bkgframe, theBMass, 'bkg_comb_' + outputfile) return {"exp_alpha": params.getRealValue('exp_alpha')}
def plotContours(): par1, par2 = "amp-41Ca", "amp-36Cl" f = TFile("./data/fitWorkspace.root") fitWorkspace = f.Get("fitWorkspace") fData = fitWorkspace.allData().front() model = fitWorkspace.pdf("model") # redeclare the minimizer since it can't be saved into the workspace for some reason minimizer = ROOT.RooMinimizer( model.createNLL(fData, RF.NumCPU(2, 0), RF.Extended(True))) # minimizer.setMinimizerType("Minuit2") minimizer.setPrintLevel(-1) minimizer.setStrategy(2) minimizer.migrad() fitResult = minimizer.save() c = TCanvas("c", "c", 1100, 800) fContour = minimizer.contour(fitWorkspace.var(par1), fitWorkspace.var(par2), 1, 2, 3) fContour.SetTitle("Contour of %s vs %s" % (par1, par2)) # set plot range mux = fitWorkspace.var(par1).getValV() upx = fitWorkspace.var(par1).getErrorHi() lox = fitWorkspace.var(par1).getErrorLo() muy = fitWorkspace.var(par2).getValV() upy = fitWorkspace.var(par2).getErrorHi() loy = fitWorkspace.var(par2).getErrorLo() fContour.GetXaxis().SetRangeUser(mux + 4 * lox, mux + 4 * upx) fContour.GetYaxis().SetRangeUser(muy + 4 * loy, muy + 4 * upy) fContour.Draw() c.Print("./plots/contour-%s-vs-%s.pdf" % (par1, par2))
def SaveResult(**kwargs): print '------SaveResult start {0}'.format(label) plotframe=kwargs['origPlot'] var=kwargs['origVar'] data=kwargs['data'] tPDF=kwargs['totPDF'] kwargs['fitDir'].cd() kwargs['fitres'].Write(kwargs['label']) kwargs['figDir'].cd() plotframe.SetMaximum(plotframe.GetMaximum()*1.5) plotframe.Draw() plotframe.Write(kwargs['label']) canv.SaveAs(tMPfIG) #plotframeForPull=RooPlot(plotframe.GetXaxis().GetXmin(),plotframe.GetXaxis().GetXmax()) plotframeForPull=var.frame(RooFit.Title(kwargs['label']+' creates for pull distribution'),RooFit.Range(plotframe.GetXaxis().GetXmin(),plotframe.GetXaxis().GetXmax())) #plotframeForPull.addPlotable(cutData,'p') data['content'].plotOn(plotframeForPull,RooFit.Name('data')) if not 'absNumNormalize' in kwargs.keys(): tPDF['content'].plotOn(plotframeForPull,RooFit.Name('totModel')) else: tPDF['content'].plotOn(plotframeForPull,RooFit.Name('totModel'),RooFit.Normalization(kwargs['absNumNormalize'],RooAbsReal.NumEvent)) #plotframeForPull.Draw() plotframeForPull.Write(label+'ForPull') print '------SaveResult End {0}'.format(label) return None
def SaveSimulResult(**kwargs): print '------SaveSimulResult start {0}'.format(kwargs['label']) plotframes = kwargs['origPlot'] vars = kwargs['origVar'] datas = kwargs['data'] tPDFs = kwargs['totPDF'] label = kwargs['label'] kwargs['fitDir'].cd() kwargs['fitres'].Write(kwargs['label']) for idx, plotframe in enumerate(plotframes): var = vars[idx] data = datas[idx] tPDF = tPDFs[idx] frameName = plotframe.GetName() kwargs['figDir'].cd() plotframe.SetMaximum(plotframe.GetMaximum() * 1.5) plotframe.Draw() canv.SaveAs(tMPfIG) plotframe.Write(label + 'In' + plotframe.GetName()) plotframeForPull = var.frame( RooFit.Title(label + ' creates for pull distribution' + 'in {0} frame'.format(frameName)), RooFit.Range(plotframe.GetXaxis().GetXmin(), plotframe.GetXaxis().GetXmax())) data['content'].plotOn(plotframeForPull, RooFit.Name('data')) tPDF['content'].plotOn(plotframeForPull, RooFit.Name('totModel')) plotframeForPull.Write(label + 'ForPull' + '_{0}Frame'.format(frameName)) print '------SaveSimulResult End {0}'.format(kwargs['label']) return None
def ImportMCShapes(w): mc_types = [ 'sig', 'misrec', 'bdstpp', 'bdstkk', 'bdkp', 'bdsth', 'partrec', 'lbdph', 'lbdstph' ] for typ in mc_types: assert (os.path.exists('files/w_%s.root' % typ)) tf = TFile('files/w_%s.root' % typ) wmc = tf.Get('w_%s' % typ) assert (wmc) wmc.loadSnapshot('%s_mc_sim_fit' % typ) pdfname = '%s_mc_sim_pdf' % typ getattr(w, 'import')(wmc.pdf(pdfname), rf.RecycleConflictNodes()) pars = w.pdf(pdfname).getParameters( RooArgSet(w.var('B_DTFDict_D0_B_M'))) w.defineSet(pdfname + '_pars', pars) tf.Close() # some special jiggery pokery for the dstkk stuff (as it was fitted in 8 categories not 4 to MC) for samp in ['b0g', 'b0pi0', 'bsg', 'bspi0']: bdstkk = w.pdf('bdstkk_mc_pdf_b0_%s' % samp) bdstkk.SetName('bdstkk_mc_pdf_%s' % samp) bsdstkk = w.pdf('bdstkk_mc_pdf_bs_%s' % samp) bsdstkk.SetName('bsdstkk_mc_pdf_%s' % samp) getattr(w, 'import')(bdstkk, rf.RecycleConflictNodes()) bd_pars = w.pdf('bdstkk_mc_pdf_%s' % samp).getParameters( RooArgSet(w.var('B_DTFDict_D0_B_M'))) w.defineSet('bdstkk_mc_pdf_%s_pars' % samp, bd_pars) getattr(w, 'import')(bsdstkk, rf.RecycleConflictNodes()) bs_pars = w.pdf('bsdstkk_mc_pdf_%s' % samp).getParameters( RooArgSet(w.var('B_DTFDict_D0_B_M'))) w.defineSet('bsdstkk_mc_pdf_%s_pars' % samp, bs_pars)
def model_hist(xvar, yvar, modfuncs, nbins=95, crange=(-10.0, 10.0)): """Construct histogram of model functions, based on bin integrals. xvar, yvar: Coordinate variables. modfuncs: Model functions used in fit. nbins: Number of bins in histograms. crange: Range of coordinates. """ hists = [ TH2D('hmodel{0}{1}'.format(c, i), 'hmodel{0}{1}'.format(c, i), nbins, crange[0], crange[1], nbins, crange[0], crange[1]) for (i, c) in ic ] for xbin in range(nbins): xlo = hists[0].GetXaxis().GetBinLowEdge(xbin + 1) xup = hists[0].GetXaxis().GetBinUpEdge(xbin + 1) for ybin in range(nbins): ylo = hists[0].GetXaxis().GetBinLowEdge(ybin + 1) yup = hists[0].GetXaxis().GetBinUpEdge(ybin + 1) name = 'bin_{0}_{1}'.format(xbin, ybin) xvar.setRange(name, xlo, xup) yvar.setRange(name, ylo, yup) for hist, modfunc in zip(hists, modfuncs): integral = modfunc.createIntegral( RooArgSet(xvar, yvar), RooFit.NormSet(RooArgSet(xvar, yvar)), RooFit.Range(name)).getVal() hist.SetBinContent(xbin + 1, ybin + 1, integral) return hists
def fit(): """Runs the mass fit. Either nominal with making pretty plots or in spearmint mode which does not save the workspace and returns a metric.""" # Get the data # TODO: rewrite selection to use gcm itself mode = gcm() sel = selection.get_final_selection() df = mode.get_data([dtf_dm(), m(mode.D0)]) df = df[sel] from . import fit_config from ROOT import RooFit as RF from .fit_setup import setup_workspace wsp, _ = setup_workspace() data = fit_config.pandas_to_roodataset(df, wsp.set('datavars')) model = wsp.pdf('total') plot_fit('_start_values', wsp=wsp) result = model.fitTo(data, RF.NumCPU(4), RF.Save(True), RF.Strategy(2), RF.Extended(True)) if not helpers.check_fit_result(result, log): log.error('Bad fit quality') fit_config.dump_workspace(mode, wsp)
def run_fit_minuit(self, fitrange=None, debug=True): """ run the RooFit Fitter and MIGRAD, HESSE and MINOS """ self.fitrange = self.fitrangehelper(fitrange) print self.fitrange self.xvardata.setRange("runfit", *self.fitrange) self.func_pdf.fitTo(self.datahist, rf.Save(), rf.Range("runfit"), rf.SumW2Error(True), ROOT.RooCmdArg('Strategy', 3)) if debug: print "\n**************************" print "***** finished fitTo in RooFit ******" print "*********************\n" # construct the Log(Likelihood) nll = self.func_pdf.createNLL(self.datahist) m = ROOT.RooMinimizer(nll) m.migrad() if debug: print "\n*************************************" print "************ finished MIGRAD ****************" print "***************************************\n" m.hesse() if debug: print "\n*************************************" print "************ finished HESSE *****************" print "***************************************\n" m.minos() if debug: print "\n*************************************" print "************ finished MINOS *****************" print "***************************************\n" self.fitresult = m.save()
def fit(model, hists, fitmethod, eps=1.0e-7): """Fit beam shapes to Beam Imaging data. model: Beam shape model (derived from BeamShapeCore). hists: List of four TH2F with BI data. fitmethod: Function(pdf, data) that fits pdf to data. eps: Value of convergence criteria. """ RooAbsReal.defaultIntegratorConfig().setEpsAbs(eps) RooAbsReal.defaultIntegratorConfig().setEpsRel(eps) modfuncs = model.model_functions() datahist = [ RooDataHist('scan{0}Beam{1}RestDataHist'.format(c, i), 'scan{0}Beam{1}RestDataHist'.format(c, i), RooArgList(model.xvar(), model.yvar()), hists[j]) for j, (i, c) in enumerate(ic) ] sample = RooCategory('sample', 'sample') for (i, c) in ic: sample.defineType('{0}_ScanData_Beam{1}Rest'.format(c, i)) combdata = RooDataHist('combdata', 'combined data', RooArgList(model.xvar(), model.yvar()), RooFit.Index(sample), RooFit.Import('X_ScanData_Beam1Rest', datahist[0]), RooFit.Import('Y_ScanData_Beam1Rest', datahist[1]), RooFit.Import('X_ScanData_Beam2Rest', datahist[2]), RooFit.Import('Y_ScanData_Beam2Rest', datahist[3])) simpdf = RooSimultaneous('simpdf', 'simultaneous pdf', sample) for j, (i, c) in enumerate(ic): simpdf.addPdf(modfuncs[j], '{0}_ScanData_Beam{1}Rest'.format(c, i)) result = fitmethod(simpdf, combdata) return result, modfuncs, datahist
def test_datafit(self, pdf_names=['dijet'], rebin_factor=1.0): hname = "data_" + self.x_name print hname h = self.file.Get(hname).Clone(hname + "_clone") if rebin_factor > 1.: h.Rebin(rebin_factor) ROOT.SetOwnership(h, False) self.x.setRange(self.x.getMin(self.x_name), self.x.getMax(self.x_name)) data_bkg = ROOT.RooDataHist("data", "", ROOT.RooArgList(self.x), h, 1.0) for pdf_name in pdf_names: print pdf_name pdf_range = ('%.0fto%.0f' % (self.x.getMin(), self.x.getMax())) print "\tRange: " + pdf_range pdf_order = ( 'deg%d' % FTestCfg_data[pdf_name]['MaxOrder'][pdf_range] ) if pdf_range in FTestCfg_data[pdf_name]['MaxOrder'].keys() else ( 'deg%d' % FTestCfg_data[pdf_name]['MaxOrder']["default"]) if pdf_order not in FitBkgCfg_data[pdf_name].keys(): pdf_order = "any" print "\tOrder matching 'range': " + pdf_order if pdf_range not in FitBkgCfg_data[pdf_name][pdf_order].keys(): pdf_range = "default" print "\tRange matching 'order': " + pdf_range [pdf_bkg, param_bkg] = generate_pdf( self.x, pdf_name=pdf_name, n_param=FTestCfg_data[pdf_name]['MaxOrder'][pdf_range], n_iter=0, gcs=gcs, mass_range=pdf_range, parameter_set="default", is_data=True) res = pdf_bkg.fitTo( data_bkg, # RooFit.Strategy(2), # RooFit.Minimizer("Minuit2"), # RooFit.Minos(1), RooFit.Save(1), RooFit.PrintLevel(-1), RooFit.PrintEvalErrors(0)) res.Print() # h_rebinned = data_bkg.createHistogram(hname+"_"+pdf_name+"_rebinned", self.x, RooFit.Binning( int((self.x.getMax()-self.x.getMin())/5.0) , self.x.getMin(), self.x.getMax()) ) # data_bkg_rebinned = ROOT.RooDataHist("data_"+pdf_name+"_rebinned","", ROOT.RooArgList(self.x), h_rebinned, 1.0) # self.plot( data=data_bkg_rebinned, pdfs=[pdf_bkg], res=None, add_pulls=True, legs=[pdf_name], ran=pdf_name, n_par=FTestCfg_data[pdf_name]['ndof'][pdf_range], title="datafit_"+pdf_name) self.plot(data=data_bkg, pdfs=[pdf_bkg], res=None, add_pulls=True, legs=[pdf_name], ran=pdf_name, n_par=FTestCfg_data[pdf_name]['ndof'][pdf_range], title="datafit_" + pdf_name)
def get_dataset(varargset, ftree, cut='', wt='', scale=1): """Return a dataset. Return a dataset from the ntuple `ftree'. Apply a selection cut using the `cutVar' variable and the selection `cut'. """ from rplot.fixes import ROOT from rplot.tselect import Tsplice splice = Tsplice(ftree) splice.make_splice('sel', cut) from ROOT import RooDataSet, RooFit, RooFormulaVar, RooArgList tmpdst = RooDataSet('tmpdataset', '', varargset, RooFit.Import(ftree)) if wt: wtvar = RooFormulaVar('wt', '{}*@0'.format(scale), RooArgList(varargset[wt])) wtvar = tmpdst.addColumn(wtvar) varargset.remove(varargset[wt]) varargset.add(wtvar) dst = RooDataSet('dataset', 'Dataset', varargset, RooFit.Import(tmpdst), RooFit.WeightVar(wtvar)) varargset.remove(wtvar) dst = dst.reduce(varargset) return dst
def kde_fit(tree, outputfile, branches, pdfname, SavePlot=True): print "KDE - {}".format(pdfname) wspace, dataset, bMass, theBMass = define_workspace_bmass_data( "wspace_kde", branches[0], tree) kde_frame = theBMass.frame() wspace.factory('KeysPdf::{0}(x,data,MirrorLeft,2.0)'.format(pdfname)) kde = wspace.pdf(pdfname) dataset.plotOn(kde_frame, RooFit.Binning(nbin_data), RooFit.Name("datas")) kde.plotOn(kde_frame, RooFit.LineColor(ROOT.kBlue), RooFit.LineWidth(2)) #wf = ROOT.TFile('ws_bkg_kde_'+outputfile+'_{}.root'.format(pdfname), "RECREATE") #wspace.Write() #wf.Close() #c1=canvas_create(kde_frame,4.7,5.7,nbin_data,'m (e^{+}e^{-}K) [GeV] ') c1, top, bottom = canvas_create_pull(kde_frame, 4.7, 5.7, nbin_data, 'm(e^{+}e^{-}K) [GeV]', theBMass) top.cd() CMS_lumi() if SavePlot: c1.SaveAs('bkg_kde_' + outputfile + '_{}.pdf'.format(pdfname)) residuals(kde_frame, theBMass, 'bkg_kde_' + outputfile + '_' + pdfname) return kde
def draw_likelihood_curves(pdf, dataset, fit_result, base_name="NLL-"): """Draw likelihood curve for all variables""" c = R.TCanvas("likelihood","") for n,var in enumerate(pdf.getParameters(dataset)): if var.isConstant(): continue print var.GetName(), "now." nll = pdf.createNLL(dataset) fitted_var = fit_result.floatParsFinal().find(var.GetName()) delta = 4 * fitted_var.getError() assert(fitted_var == var) for x_range in (None, (fitted_var.getVal()-delta, fitted_var.getVal()+delta)): if x_range is None: f = var.frame() nll.plotOn(f, RF.ShiftToZero()) fname = base_name + var.GetName() else: low = max(var.getMin(), x_range[0]) up = min(var.getMax(), x_range[1]) f = var.frame(RF.Range(low, up)) nll.plotOn(f, RF.ShiftToZero()) fname = base_name + var.GetName() + "-zoomed" f.Draw() c.SaveAs(fname + ".pdf") #c.SetLogy(True) #c.SaveAs(fname + "-log.pdf") #c.SetLogy(False) c.Clear()
def plot_fit_params(self, wsp): """ Plot all free fit parameters onto canvas Args: wsp (ROOT.RooWorkspace): workspace where the model is stored """ fit_var = get_var(wsp, self.fit_var) cans = OrderedDict() for bin_name in self.bins: frame = fit_var.frame(rf.Title('Fit Results')) plotname = '{}_{}'.format(self.full_model, bin_name) full_pdf = wsp.pdf(plotname) full_pdf.paramOn(frame, rf.Layout(0.1, 0.9, 0.9), rf.Format('NEU', rf.AutoPrecision(2))) can = r.TCanvas(create_random_str(32), 'rcan', 600, 600) can.cd() frame.findObject('{}_paramBox'.format(full_pdf.GetName())).Draw() cans[bin_name] = can #can.SaveAs(pdfname) # returns fit params for each fit return cans
def checkYieldFixSideband(**kwargs): iF=TFile.Open(kwargs['fileName']) print iF space=iF.Get('space') mass=space.var(kwargs['mass']) bkgY=space.var(kwargs['bkgYield']) bkg=space.pdf(kwargs['bkgPdf']) # kill mass range mass.setRange('lSide', mass.getMin() , signalRegion[0] ) mass.setRange('rSide', signalRegion[1] , mass.getMax() ) # kill -2sig~2sig #mass.setRange('lSide', mass.getMin() , kwargs['mean']-2.0*kwargs['width']) #mass.setRange('rSide', kwargs['mean']+2.0*kwargs['width'], mass.getMax() ) # keep +-5.5sig~+-3.0sig #mass.setRange('lSide', kwargs['mean']-5.5*kwargs['width'], kwargs['mean']-3.0*kwargs['width']) #mass.setRange('rSide', kwargs['mean']+3.0*kwargs['width'], kwargs['mean']+5.5*kwargs['width']) bkgSideRatio=bkg.createIntegral(RooArgSet(mass),RooFit.NormSet(RooArgSet(mass)),RooFit.Range('lSide,rSide')) yVal=bkgY.getVal() yErr2=bkgY.getError()**2 # err square rVal=bkgSideRatio.getVal() rErr2=(rVal*(1-rVal))/yVal # binomial error outVal=rVal*yVal outErr=(rVal**2*yErr2+rErr2*yVal**2)**0.5 return ( int(outVal), int(outErr) )
def checkYield(**kwargs): iF=TFile.Open(kwargs['fileName']) space=iF.Get('space') mass=space.var(kwargs['mass']) bkgY=space.var(kwargs['bkgYield']) mean=space.var(kwargs['meanVar']) wid1=space.var(kwargs['widthVar1']) wid2=space.var(kwargs['widthVar2']) wid=wid1 if wid1.getVal()>wid2.getVal() else wid2 bkg=space.pdf(kwargs['bkgPdf']) mass.setRange('lSide', mass.getMin() , mean.getVal()-2.0*wid.getVal()) mass.setRange('rSide', mean.getVal()+2.0*wid.getVal(), mass.getMax() ) bkgSideRatio=bkg.createIntegral(RooArgSet(mass),RooFit.NormSet(RooArgSet(mass)),RooFit.Range('lSide,rSide')) yVal=bkgY.getVal() yErr2=bkgY.getError()**2 # err square rVal=bkgSideRatio.getVal() rErr2=(rVal*(1-rVal))/yVal # binomial error outVal=rVal*yVal outErr=(rVal**2*yErr2+rErr2*yVal**2)**0.5 return ( int(outVal), int(outErr) )
def getValueAndError(cfg, obs, comp, binWidth, rfr, ttname, window=None): """ Try to be clever and not re-compute something that has already been computed """ obs_set = RooArgSet(obs) compname = comp.GetName() bwidth = binWidth.getVal() compInt = None if ttname in cfg._yields and compname in cfg._yields[ttname]: Ntemp = cfg._yields[ttname][compname][0] else: if window: obs.setRange("myrange", window[0], window[1]) compInt = comp.createIntegral(obs_set, RF.Range("myrange")) else: compInt = comp.createIntegral(obs_set) Ntemp = compInt.getVal() * bwidth error = -1 if rfr: if ttname in cfg._yields and compname in cfg._yields[ttname] \ and cfg._yields[ttname][compname][1] != -1: error = cfg._yields[ttname][compname][1] else: if not compInt: if window: obs.setRange("myrange", window[0], window[1]) compInt = comp.createIntegral(obs_set, RF.Range("myrange")) else: compInt = comp.createIntegral(obs_set) error = ROOT.RU.getPropagatedError(compInt, rfr) * bwidth logging.info("Found {} +/- {} for {} in region {}".format( Ntemp, error, compname, ttname)) return [Ntemp, error]
def check_fit_bias(self, param_to_study, N_toys=1000, verbose=False, save=False, save_folder='.', save_prefix='bias_check'): """Using RooMCStudy() class make bias checks in fitted model's parameter param_to_study by repitative sampling of toys from the model and then fitting them. Normally, if mean or sigma of pull plot (should look like Gaussian) are within 3sigma from 0 and 1 respectively, the fit is not biased. NB: Fit extendability and weights presence are taken into account automatically. Parameters ---------- param_to_study: RooRealVar variable for which the fit results will be accumulated N_toys: int, optional (default=1000) number of toy samples to be generated verbose: bool, optional (default=False) verbosity of the output save: bool, optional (default=False) whether save the plot or not save_folder: str, optional (default='.') path for saving save_prefix: str, optional (default='bias_check') prefix to the file name Returns ------- frame: RooPlot, RooPlot, RooPlot frames with distributions for variable's fitted value, error and pull respectively (requires further drawing on the canvas) """ if not self.is_fitted: raise Exception('Model was not fitted to data, fit it first.') is_extended = self.model.canBeExtended() is_sum_w2 = self.data.isWeighted() MC_manager = ROOT.RooMCStudy( self.model, ROOT.RooArgSet(self.var), RF.Extended(is_extended), RF.FitOptions(RF.SumW2Error(is_sum_w2), RF.Verbose(verbose))) MC_manager.generateAndFit(N_toys) frame_var = param_to_study.frame() MC_manager.plotParamOn(frame_var) frame_err = MC_manager.plotError(param_to_study) frame_pull = MC_manager.plotPull(param_to_study, -3, 3, 60, ROOT.kTRUE) if save: c_var = ROOT.TCanvas("c_var", "c_var", 800, 600) frame_var.Draw() c_err = ROOT.TCanvas("c_err", "c_err", 800, 600) frame_err.Draw() c_pull = ROOT.TCanvas("c_pull", "c_pull", 800, 600) frame_pull.Draw() c_var.SaveAs( f'{save_folder}/{save_prefix}_{self.var.GetName()}.pdf') c_err.SaveAs( f'{save_folder}/{save_prefix}_{self.var.GetName()}err.pdf') c_pull.SaveAs( f'{save_folder}/{save_prefix}_{self.var.GetName()}pull.pdf') return frame_var, frame_err, frame_pull
def AddSweights(ifile, polarity, particle, sample): #----> Open subsample files f = r.TFile(ifile, 'read') t = f.Get('DecayTree') t.SetBranchStatus('sw_sig', 0) t.SetBranchStatus('sw_bkg', 0) #----> Create subsample files which will contain sweights of = r.TFile(ifile[0:-5] + '_sw.root', 'recreate') ot = t.CloneTree(0) ot.SetName('DecayTree') LcM_range = [2230, 2330] Lc_M = r.RooRealVar('Lc_M', '#Lambda_{c} mass', LcM_range[0], LcM_range[1]) ds = GetDataset(t, Lc_M) #Create a workspace named 'w' with the model to fit the Lc_Mass peak nsig = r.RooRealVar("nsig", "N signal evts", 100000, 0, 500000) nbkg = r.RooRealVar("nbkg", "N bkg evts", 400000, 0, 500000) w = CreateMassFitModel(Lc_M, nsig, nbkg) model = w.pdf("model") result = model.fitTo(ds, RF.Extended(True), RF.Save()) nsig = w.var('nsig') nbkg = w.var('nbkg') sData = r.RooStats.SPlot("sData", "An SPlot", ds, model, r.RooArgList(nsig, nbkg)) ds_w = GetWeightedDS(ds) #----> Create branches for sweights sw_bkg = np.zeros(1, dtype=float) sw_sig = np.zeros(1, dtype=float) ot.Branch("sw_bkg", sw_bkg, "sw_bkg/D") ot.Branch("sw_sig", sw_sig, "sw_sig/D") for i in range(ds_w.numEntries()): t.GetEntry(i) sw_bkg[0] = ds_w.get(i).getRealValue("nbkg_sw") sw_sig[0] = ds_w.get(i).getRealValue("nsig_sw") ot.Fill() ot.Write() of.Close() f.Close() #Save fit results to file of_fit = r.TFile( datadir + '/MISID/IntermediateFiles_SS/FitResults/FitResults_' + particle + '_' + polarity + suffix[sample], 'Recreate') result.Write() of_fit.Close() PlotMassFit(model, ds, Lc_M, particle, polarity, sample) return
def fit(self, snapshot_name, do_matrix=True, save_to_file=None): """ do the fit...and save a snapshot """ if not self.data: print("data is missing") return if self.ws.loadSnapshot(snapshot_name): print("Reuse fitted results saved at snapshot: {}".format( snapshot_name)) return True if os.path.isfile(self.corr_root_path): print("Reuse fitted results saved at root file: {}".format( self.corr_root_path)) fout = ROOT.TFile.Open(self.corr_root_path) self.corr = fout.Get("corr") self.corr.SetDirectory(0) self.fit_res = fout.Get("nll_res") return True nuisance = self.mc.GetNuisanceParameters() nuisance.Print("v") nll = self.simPdf.createNLL( self.data, RooFit.Constrain(nuisance), RooFit.GlobalObservables(self.mc.GetGlobalObservables())) nll.enableOffsetting(True) minim = ROOT.RooMinimizer(nll) minim.optimizeConst(2) #minim.setStrategy(2) minim.setStrategy(1) #minim.setProfile() status = minim.minimize( "Minuit2", ROOT.Math.MinimizerOptions.DefaultMinimizerAlgo()) if status != 0: minim.setStrategy(1) status = minim.minimize( "Minuit2", ROOT.Math.MinimizerOptions.DefaultMinimizerAlgo()) assert status == 0, "Fit did not converge..change to a different strategy" status = minim.hesse() print("Hesse status:", status) self.ws.saveSnapshot(snapshot_name, self.ws.allVars()) if save_to_file: print("debug", self.out_dir, save_to_file) #self.ws.writeToFile(os.path.join(self.out_dir, save_to_file)) # after performed the Fit, plot the coefficient matrix if do_matrix: self.fit_res = minim.save() corr_hist = self.fit_res.correlationHist() self.corr = corr_hist.Clone("corr") self.corr.SetDirectory(0) fout = ROOT.TFile.Open(self.corr_root_path, 'recreate') self.corr.Write() self.fit_res.SetName("nll_res") self.fit_res.Write() fout.Close()
def get_facc(rhf): '''Ratio of events in acceptance to all events''' in_acc = rhf.createIntegral( RooArgSet(x), RooFit.Range('acceptance')).getVal() tot = rhf.createIntegral(RooArgSet(x), RooFit.Range('total')).getVal() facc = in_acc / tot return facc
def _get_number_of_signal(self): import ROOT.RooFit as RF _isig = self._signal.createIntegral( self.wsp.set('datavars'), RF.NormSet(self.wsp.set('datavars')), RF.Range("signal")) log.info('Signal yield: {}'.format(self._nsig.getVal())) log.info('Signal integral: {}'.format(_isig.getVal())) return self._nsig.getVal() * _isig.getVal()
def chi2_fit(self, nbins=-1, fix_float=[], minos=False, minos_poi=None): """Fit the instance data with binned chi2 method using Minuit2. Set is_fitted=True. NB: weights presence is taken care of automatically NB: by default, binning is taken from the variable's definition. Otherwise, it is temporarily set to nbins value. Parameters ---------- nbins: int/float, optional (default=-1: take the number of bins from the variable's definition) number of bins in calculating chi2 fix_float: list of RooRealVar, optional (default=[]) variables from this list will be firstly setConstant(1) in the fit and then setConstant(0) minos: bool whether to calculate MINOS errors for minos_poi parameter of interest minos_poi: RooRealVar parameter of interest for which to calculate MINOS errors Returns ------- fit_results: RooFitResult results of the fit, can be printed with the Print() method """ init_nbins = self.var.numBins() if nbins != -1: assert (nbins % 1 == 0 and nbins >= 0), 'nbins type is not a positive integer' self.var.setBins(nbins) hist_to_fit = ROOT.RooDataHist( 'hist_to_fit', 'hist_to_fit', ROOT.RooArgSet(self.var), self.data) ### binning is taken from the var's definition is_extended = self.model.canBeExtended() chi2_var = ROOT.RooChi2Var("chi2_var", "chi2_var", self.model, hist_to_fit, RF.Extended(is_extended), RF.DataError(ROOT.RooAbsData.Auto)) m = ROOT.RooMinimizer(chi2_var) m.setMinimizerType("Minuit2") m.setPrintLevel(3) m.minimize("Minuit2", "minimize") for param in fix_float: param.setConstant(1) m.minimize("Minuit2", "minimize") for param in fix_float: param.setConstant(0) self.fit_status = m.minimize("Minuit2", "minimize") self.is_fitted = True self.var.setBins(init_nbins) if minos: if minos_poi is None: raise TypeError( 'Poi is None by default: set it to a proper variable to run MINOS.' ) if self.data.isWeighted(): interactivity_yn( 'The data is weighted and MINOS should not be used. Sure you want to proceed?' ) m.minos(ROOT.RooArgSet(minos_poi)) print('\n\n\nMINOS DONE, see the results above\n\n\n') return m.save()
def draw_data(self): self.mframe = self.xvar.frame() self.data.plotOn(self.mframe) self.underlying_model.plotOn(self.mframe) for icomp, compname in enumerate(self.pdfs): self.underlying_model.plotOn(self.mframe, RooFit.Components(compname), RooFit.LineColor(icomp + 1)) self.mframe.Draw()
def DoRooFit(histo, title): can = makeCMSCanvas(str(random.random()),"Fit result ",900,700) #Varible if "ele" in title: x1 = RooRealVar("x1","m_{e^{+}e^{-}}",80,100) if "mu" in title: x1 = RooRealVar("x1","m_{#mu^{+}#mu^{-}}",80,100) #Define CB function m = RooRealVar("mean_{CB}","mean of gaussian",60,120) s = RooRealVar("#sigma_{CB}","width of gaussian",0,3) a = RooRealVar("#alpha_{CB}","mean of gaussian",0,100) n = RooRealVar("n_{CB}","width of gaussian",0,5) CB = RooCBShape("CB","CB PDF",x1, m, s, a, n) m.setConstant(kFALSE) s.setConstant(kFALSE) a.setConstant(kFALSE) n.setConstant(kFALSE) #Define Gaussian function mean1 = RooRealVar("mean_{G}","mean of gaussian",-60,60) sigma1 = RooRealVar("#sigma_{G}","width of gaussian",0,10) gauss1 = RooGaussian("gauss1","gaussian PDF",x1,mean1,sigma1) mean1.setConstant(kFALSE) sigma1.setConstant(kFALSE) #Starting values of the parameters mean1.setVal(1.0) sigma1.setVal(1.0) m.setVal(90.0) s.setVal(1.0) a.setVal(10.0) n.setVal(2.0) # Construct CB (x) gauss x1.setBins(10000, "cache") CBxG = RooFFTConvPdf("CBxG", "CB (X) gauss", x1, CB, gauss1) can.cd() d = RooDataHist("d","d",RooArgList(x1),RooFit.Import(histo)) CBxG.fitTo(d, RooLinkedList()) # Plot PDF and toy data overlaid xframe2 = x1.frame(RooFit.Name("xframe"),RooFit.Title("")) # RooPlot d.plotOn(xframe2, RooLinkedList() ) CBxG.paramOn(xframe2, RooFit.Layout(0.65,0.99,0.9)) xframe2.getAttText().SetTextSize(0.03) CBxG.plotOn(xframe2) xframe2.Draw() can.SaveAs("DataVsMC/FitResults/"+title+"_Roofit.pdf") can.SaveAs("DataVsMC/FitResults/"+title+"_Roofit.png") return;
def plot_ll(self, poi, nbins=100, poi_min=-1, poi_max=-1, save=False, save_folder='.', save_prefix='pll'): """Plot the nominal and profiled likelihoods for the instance's data and model for the provided parameter of interest Parameters ---------- poi: RooRealVar parameter of interest for which the likelihoods will be plotted nbins: int, optional (default=100) number of bins for plotting poi_min: float, optional (default=-1, set to be -5*poi_fit_error) left range for plotting poi_max: float, optional (default=-1, set to be +5*poi_fit_error) right range for plotting save: bool, optional (default=False) whether save the plot or not save_folder: str, optional (default='.') path for saving save_prefix: str, optional (default='pll') prefix to the file name Returns ------- frame: RooPlot frame containing the likelihood plots (requires further drawing on the canvas) """ poi_from_model = self.model.getVariables().find(poi.GetName()) if poi_min == -1: poi_min = poi_from_model.getVal() - 5 * poi_from_model.getError() if poi_max == -1: poi_max = poi_from_model.getVal() + 5 * poi_from_model.getError() assert (nbins % 1 == 0 and nbins >= 0), 'nbins must be a positive integer' assert (poi_min < poi_max), 'left range value must be lower than right range one' nll = self.model.createNLL(self.data) pll = nll.createProfile(ROOT.RooArgSet(poi)) frame_nll = poi.frame(RF.Bins(nbins), RF.Range(poi_min, poi_max)) frame_nll.SetTitle('') nll.plotOn(frame_nll, RF.ShiftToZero(), RF.LineColor(ROOT.kGreen)) pll.plotOn(frame_nll, RF.LineColor(ROOT.kRed)) frame_nll.SetMaximum(25.) frame_nll.SetMinimum(0.) frame_nll.SetXTitle(poi.GetName()) if save: c_ll = ROOT.TCanvas("c_ll", "c_ll", 800, 600) frame_nll.Draw() c_ll.SaveAs(f'{save_folder}/{save_prefix}.pdf') return frame_nll
def get_hist(self, pdf, obs, events, hist_name): hist = pdf.createHistogram(hist_name, obs, RooFit.IntrinsicBinning(), RooFit.Extended(True)) if hist.Integral() > 1E-6: if hist.GetSumw2 is None: hist.Sumw2(True) hist.Scale(events / hist.Integral()) else: print(hist.GetName(), "MISSING") return hist
def PlotMassFit(model, ds, Lc_M, particle, polarity, sample): c = r.TCanvas() frame = Lc_M.frame(RF.Title('#Lambda_{c} mass peak distribution')) ds.plotOn(frame) model.plotOn(frame) model.paramOn(frame, RF.Layout(0.6, 0.9, 0.85)) frame.Draw() c.Draw() imgsuff = suffix[sample][0:-5] + '.png' c.SaveAs('plots/Fit_' + particle + '_' + polarity + imgsuff) return
def MakeIntegral(self,intrange=None, pdfname = None): """ make pdf integral that returns in range [0,1] """ if intrange is None: intrange = self.fitrange if pdfname is None: pdf = self.func_pdf else: pdf = self.wk.pdf(pdfname) self.integral = pdf.createIntegral( self.xvardata, rf.NormSet(self.xvardata), rf.Range(*intrange) ) return self.integral
def plot_on(self, pdf, line_style, events, tag, leg_opt="L", do_norm=True): if do_norm: opt = RooFit.Normalization(events, ROOT.RooAbsReal.NumEvent) else: opt = ROOT.RooCmdArg.none() pdf.plotOn(self.frame, RooFit.LineStyle(line_style), RooFit.LineColor(self.colors[self.plotted_id]), opt) self.legend.AddEntry(self.frame.getObject(self.plotted_id), tag + "={:.2f}".format(events), leg_opt) self.plotted_id += 1
def getMistagBinBounds(config, mistag, mistagdistrib): """ suggest a binning for turning per-event mistag into mistag categories This routine takes a mistag observable and a PDF or data set, and suggests a number of mistag category boundaries which have approximately equal statistics in each category. config -- config dictionary mistag -- mistag observable (eta) mistagdistrib -- a PDF or a RooDataSet returns a (python) list of mistag category bin bounds relevant configuration dictionary keys: 'NMistagCategories': number of mistag categories for which to suggest a set of bin bounds """ mistag.setBins(1000, 'MistagBinBounds') from ROOT import RooArgSet, RooHistPdf, RooDataHist if (mistagdistrib.InheritsFrom('RooAbsData') and not mistagdistrib.InheritsFrom('RooDataHist')): # ok, unbinned data set, get only tagged events, and form a binned clone argset = RooArgSet(mistag) mistagdistrib = mistagdistrib.reduce( RooFit.SelectVars(argset), RooFit.cut('0 != qt')) ROOT.SetOwnership(mistagdistrib, True) dhist = RooDataHist( '%s_binned' % mistagdistrib.GetName(), '%s_binned' % mistagdistrib.GetName(), mistagdistrib.get(), 'MistagBinBounds') dhist.add(mistagdistrib) mistagdistrib = dhist if mistagdistrib.InheritsFrom('RooAbsData'): # convert a binned dataset to a RooHistPdf dhist = mistagdistrib mistagdistrib = RooHistPdf('%s_pdf' % dhist.GetName(), '%s_pdf' % dhist.GetName(), RooArgSet(mistag), dhist) if (mistagdistrib.InheritsFrom('RooAbsPdf')): # use createCdf to obtain the CDF cdfroofit = mistagdistrib.createCdf( RooArgSet(mistag), RooArgSet(mistag)) ROOT.SetOwnership(cdfroofit, True) def cdf(x): oldval = mistag.getVal() mistag.setVal(x) retVal = cdfroofit.getVal() mistag.setVal(oldval) return retVal if (mistagdistrib.InheritsFrom('RooHistPdf') and (abs(cdf(mistag.getMin())) > 1e-9 or abs(cdf(mistag.getMax()) - 1.) > 1e-9)): # createCdf does not work properly for RooHistPdf in older ROOT # versions because RooHistPdf does not support integrals over # subranges, so we have to fake this functionality until it's # supported by RooFit upstream # # capture histogram bin boundaries and contents print 'WARNING: Your version of RooFit still has buggy analytical ' \ 'integrals for RooHistPdf - activating workaround.' binboundlist = mistagdistrib.binBoundaries( mistag, mistag.getMin(), mistag.getMax()) ROOT.SetOwnership(binboundlist, True) binbounds = [ v for v in binboundlist ] del binboundlist bincontents = [ ] oldval = mistag.getVal() for i in xrange(0, len(binbounds) - 1): mistag.setVal(0.5 * (binbounds[i] + binbounds[i + 1])) bincontents.append(mistagdistrib.getValV(RooArgSet(mistag))) mistag.setVal(oldval) # build CDF from histogram def cdf(x): s = 0. for i in xrange(0, len(binbounds) - 1): if x < binbounds[i]: break elif x >= binbounds[i + 1]: s += bincontents[i] else: s += (bincontents[i] * (x - binbounds[i]) / (binbounds[i + 1] - binbounds[i])) break return s # find x for which f(x) = y by bisection def mybisect(y, f, lo, hi): initdx = abs(hi - lo) flo, fhi = f(lo) - y, f(hi) - y if 0. == flo: return lo elif 0. == fhi: return hi mid = .5 * (lo + hi) while (abs(hi - lo) > 1e-15 and abs(hi - lo) / initdx > 1e-15): fmid = f(mid) - y if 0. == fmid: break elif flo * fmid < 0.: hi, fhi = mid, fmid elif fmid * fhi < 0.: lo, flo = mid, fmid else: raise ValueError('no sign change in f(x) between %g and %g' % (lo, hi)) mid = .5 * (lo + hi) return mid # find binning with roughly same stats by inverting the CDF by bisection lo, hi, binsum = mistag.getMin(), mistag.getMax(), cdf(mistag.getMax()) retVal = [ lo ] for i in xrange(1, config['NMistagCategories']): retVal.append(mybisect(binsum * float(i) / float(config['NMistagCategories']), cdf, lo, hi)) retVal.append(hi) print 'INFO: suggested mistag category bounds: %s' % str(retVal) return retVal