diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..19fae23 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.root +*.pyc +*.pdf +*.png diff --git a/archive/fitter.py b/archive/fitter.py new file mode 100644 index 0000000..f3a2b8b --- /dev/null +++ b/archive/fitter.py @@ -0,0 +1,441 @@ +#!/usr/bin/env python +from collections import OrderedDict +import root_numpy +import ROOT +from ROOT import RooFit +import numpy as np +ROOT.gROOT.ProcessLine(open('models.cc').read()) +from ROOT import DoubleCBFast +from helper import * +#ROOT.gErrorIgnoreLevel=ROOT.kError +#ROOT.RooMsgService.instance().setGlobalKillBelow(RooFit.FATAL) +import matplotlib as mpl +mpl.use('agg') +from matplotlib import pyplot as plt +import atexit + +class fitter(object): + def __init__(self): + self.sig_low = BLIND_LOW + self.sig_up = BLIND_UP + self.fom_low = B_FOM_LOW + self.fom_up = B_FOM_UP + self.fit_low = FIT_LOW + self.fit_up = FIT_UP + self.nbin_data = 50 + self.fit_init = False + + def init_fit_mc(self, drawSNR=False, + sigName="B^{+}#rightarrow K^{+} J/#psi(#rightarrow e^{+}e^{-})", + fit_var='BToKEE_fit_mass', paramOn=True, **kwargs): + + init_dict = {} + init_dict['isMC'] = True + init_dict['drawSNR'] = drawSNR + init_dict['mvaCut'] = None + init_dict['sigName'] = sigName + init_dict['fit_var'] = fit_var + init_dict['paramOn'] = paramOn + init_dict['fit_init'] = True + init_dict['var'] = {} + init_dict['pdf'] = {} + kwargs.update(init_dict) + self.__dict__.update(**kwargs) + + def init_fit_data(self, drawSNR=False, params={}, blinded=False, expS=0.0, + sigName="B^{+}#rightarrow K^{+} J/#psi(#rightarrow e^{+}e^{-})", + fit_var='BToKEE_fit_mass', partialfit={}, mvaCut=0.0, plotBkgUnc=False, **kwargs): + + init_dict = {} + init_dict['isMC'] = False + init_dict['drawSNR'] = drawSNR + init_dict['params'] = params + init_dict['blinded'] = blinded + init_dict['expS'] = expS + init_dict['sigName'] = sigName + init_dict['fit_var'] = fit_var + init_dict['partialfit'] = partialfit + init_dict['mvaCut'] = mvaCut + init_dict['plotBkgUnc'] = plotBkgUnc + init_dict['fit_init'] = True + init_dict['var'] = {} + init_dict['pdf'] = {} + kwargs.update(init_dict) + self.__dict__.update(**kwargs) + + def init_fit_kde(self, pdfname="partial", fit_var='BToKEE_fit_mass', **kwargs): + init_dict = {} + init_dict['isMC'] = True + init_dict['pdfname'] = pdfname + init_dict['fit_var'] = fit_var + init_dict['paramOn'] = False + init_dict['drawSNR'] = False + init_dict['fit_init'] = True + init_dict['var'] = {} + init_dict['pdf'] = {} + kwargs.update(init_dict) + self.__dict__.update(**kwargs) + + def load_tree(self, tree): + self.wspace = ROOT.RooWorkspace('myWorkSpace') + thevars = ROOT.RooArgSet() + Mass = ROOT.RooRealVar(self.fit_var, "m(K^{+}e^{+}e^{-})", self.fit_low, self.fit_up, "GeV") + + thevars.add(Mass) + + self.fulldata = ROOT.RooDataSet('fulldata', 'fulldata', tree, ROOT.RooArgSet(thevars)) + theMassfunc = ROOT.RooFormulaVar("x", "x", "@0", ROOT.RooArgList(Mass)) + self.mass = self.fulldata.addColumn(theMassfunc) + self.mass.setRange(self.fit_low, self.fit_up) + thevars.add(self.mass) + + cut = '' + + self.data = self.fulldata.reduce(thevars, cut) + getattr(self.wspace,'import')(self.data, RooFit.Rename("data")) + # When a RooWorkspace is set as an attribute of a class, it can trigger a memory error + # This is solved in the latest ROOT version > 6.14.08 + atexit.register(self.wspace.Delete) + + def setup_model_sig(self): + self.wspace.factory('nsig[5000.0, 0.0, 1000000.0]' ) + + # Double-sided Crystal-ball + self.wspace.factory('mean[{}, {}, {}]'.format((self.fit_up+self.fit_low)/2.0, self.fit_low, self.fit_up)) + self.wspace.factory('width[4.1858e-02, 1.0e-6, 5.0e-1]') + self.wspace.factory('alpha1[1.0, 0.0, 10.0]') + self.wspace.factory('n1[1.0, 1.0, 20.0]') + self.wspace.factory('alpha2[1.0, 0.0, 10.0]') + self.wspace.factory('n2[1.0, 1.0, 20.0]') + self.wspace.factory('GenericPdf::sig("DoubleCBFast(x,mean,width,alpha1,n1,alpha2,n2)", {x,mean,width,alpha1,n1,alpha2,n2})') + + self.var['mean'] = self.wspace.var('mean') + self.var['width'] = self.wspace.var('width') + self.var['alpha1'] = self.wspace.var('alpha1') + self.var['n1'] = self.wspace.var('n1') + self.var['alpha2'] = self.wspace.var('alpha2') + self.var['n2'] = self.wspace.var('n2') + self.var['nsig'] = self.wspace.var('nsig') + self.pdf['sig'] = self.wspace.pdf('sig') + + def setup_model_bkg(self): + self.wspace.factory('nbkg[10000.0, 0.0, 1000000.0]') + + # Exponential + self.wspace.factory('exp_alpha[-1.0, -100.0, -1.e-4]') + self.wspace.factory('Exponential::bkg(x,exp_alpha)') + + # Partially reconstructed bkg + for name, info in self.partialfit.items(): + wpf = ROOT.TFile(info['filename'], "READ") + wp = wpf.Get("myPartialWorkSpace") + partialPDF = wp.pdf(name) + self.wspace.factory('n{}[{}, {}, {}]'.format(name, info['expected_yield'], \ + info['expected_yield'] - 4.0*np.sqrt(info['expected_yield']), \ + info['expected_yield'] + 4.0*np.sqrt(info['expected_yield'])) \ + if 'expected_yield' in info else 'n{}[10.0, 0.0, 100000.0]'.format(name)) + getattr(self.wspace, "import")(partialPDF, RooFit.Rename(name)) + self.var[name] = self.wspace.var('n'+name) + + self.var['exp_alpha'] = self.wspace.var('exp_alpha') + self.var['nbkg'] = self.wspace.var('nbkg') + self.pdf['bkg'] = self.wspace.pdf('bkg') + for name in self.partialfit.keys(): + self.pdf[name] = self.wspace.pdf(name) + + def bkg_unc_propagation(self, outputfile): + # define the set obs = (x) + self.wspace.defineSet('obs', 'x') + # make the set obs known to Python + obs = self.wspace.set('obs') + + nsig_interested_pdf = self.pdf['sig'].createIntegral(obs,obs,"fom_window") ; + nsig_interested_pdf_err = nsig_interested_pdf.getPropagatedError(self.results, obs) + self.nsig_interested = self.var['nsig'].getVal() * nsig_interested_pdf.getVal() + self.nsig_interested_err = self.nsig_interested * np.sqrt(pow(self.var['nsig'].getError()/self.var['nsig'].getVal(), 2) + pow(nsig_interested_pdf_err/nsig_interested_pdf.getVal(), 2)) if self.var['nsig'].getVal() != 0.0 else 0.0 + nbkg_comb_pdf = self.pdf['bkg'].createIntegral(obs,obs,"fom_window") + nbkg_comb_pdf_err = nbkg_comb_pdf.getPropagatedError(self.results, obs) + nbkg_comb = self.var['nbkg'].getVal() * nbkg_comb_pdf.getVal() + nbkg_comb_err = nbkg_comb * np.sqrt(pow(self.var['nbkg'].getError()/self.var['nbkg'].getVal(), 2) + pow(nbkg_comb_pdf_err/nbkg_comb_pdf.getVal(), 2)) if self.var['nbkg'].getVal() != 0.0 else 0.0 + self.nbkg_total = nbkg_comb + print("*"*80) + print("MVA Cut: {}".format(self.mvaCut)) + if not self.fitConverged: + print("*"*20 + "NOT COVERGE" + "*"*20) + print("Number of signals: {}".format(self.var['nsig'].getVal())) + print("Number of signals in 3.0 sigma: {}, uncertainty: {}".format(self.nsig_interested, self.nsig_interested_err)) + print("Number of background - combinatorial: {}, uncertainty: {}".format(nbkg_comb, nbkg_comb_err)) + for name in partialfit.keys(): + nbkg_pdf_pdf = self.pdf[name].createIntegral(obs,obs,"fom_window") + nbkg_partial = self.var[name].getVal() * nbkg_pdf_pdf.getVal() + self.nbkg_total += nbkg_partial + print("Number of background - {}: {}".format(name, nbkg_partial)) + + # Calculate 1-sigma error band of the total bkg through linear error propagation + bkgframe = self.mass.frame() + self.data.plotOn(bkgframe, RooFit.Binning(self.nbin_data)) + + nbinx = 1000 + xvar = np.linspace(self.fom_low, self.fom_up, nbinx) + self.fit_params = self.pdf['model'].getVariables() + ordered_fit_params = ['exp_alpha', 'nbkg'] + ['n'+name for name in self.partialfit.keys()] + if not self.blinded: + ordered_fit_params += ['nsig',] + full_bkg = ['bkg',] + [name for name in self.partialfit.keys()] + fit_params_info = OrderedDict() + for name in ordered_fit_params: + fit_params_info[name] = {'mean': self.fit_params.find(name).getVal(), 'error': self.fit_params.find(name).getError()} + self.pdf['model'].plotOn(bkgframe,RooFit.Components(",".join(full_bkg))) + model_curve = bkgframe.getCurve() + model_cen = np.array([model_curve.interpolate(x) for x in xvar]) + bkgframe.remove(str(0),False) + #self.results.covarianceMatrix().Print() + #self.results.correlationMatrix().Print() + covMatrix = root_numpy.matrix(self.results.covarianceMatrix()) + exp_event = self.pdf['model'].expectedEvents(self.fit_params) + fa = [] + for name, info in fit_params_info.items(): + adjust_norm = info['error'] if (name in (['nsig', 'nbkg',] + ['n'+p for p in self.partialfit.keys()])) else 0.0 + self.fit_params.setRealValue(name, info['mean']+info['error']) + + self.pdf['model'].plotOn(bkgframe,RooFit.Components(",".join(full_bkg)),RooFit.Normalization(exp_event+adjust_norm, ROOT.RooAbsReal.NumEvent)) + model_curve = bkgframe.getCurve() + fa_plus = np.array([model_curve.interpolate(x) for x in xvar]) + bkgframe.remove(str(0),False) + self.fit_params.setRealValue(name, info['mean']-2.0*info['error']) + + self.pdf['model'].plotOn(bkgframe,RooFit.Components(",".join(full_bkg)),RooFit.Normalization(exp_event-adjust_norm, ROOT.RooAbsReal.NumEvent)) + model_curve = bkgframe.getCurve() + fa_minus = np.array([model_curve.interpolate(x) for x in xvar]) + bkgframe.remove(str(0),False) + if name == 'nsig': + fa.append(np.zeros(nbinx)) + else: + fa.append((fa_plus - fa_minus) / (2.0*info['error'])) + # reset the params matrix + self.fit_params.setRealValue(name, info['mean']) + + fa = np.array(fa).T + tmp = np.array([np.asarray(np.matmul(FA, covMatrix)).flatten() for FA in fa]) + bkg_unc = np.sqrt(np.array([np.dot(t, FA) for t, FA in zip(tmp, fa)])) + self.nbkg_total_err = np.sqrt(np.trapz(bkg_unc*bkg_unc, x=xvar)) / ((self.fit_up-self.fit_low)/self.nbin_data) + + if self.plotBkgUnc: + fig, ax = plt.subplots() + ax.plot(xvar, model_cen, 'b-', label=r'$N_{{\rm bkg}}={0:.1f}\pm{1:.1f}$'.format(self.nbkg_total, self.nbkg_total_err)) + ax.fill_between(xvar, model_cen-bkg_unc, model_cen+bkg_unc, facecolor='red', alpha=0.5, linewidth=0.0, label=r'$1\sigma$') + ax.set_xlabel(r'$m(K^{+}e^{+}e^{-}) [{\rm GeV}]$') + ax.set_ylabel(r'a.u.') + ax.set_ylim(bottom=0) + ax.legend(loc='upper right') + fig.savefig(outputfile.replace('.pdf','')+'_totalbkg_1sigma.pdf', bbox_inches='tight') + + self.SNR = self.nsig_interested/np.sqrt(self.nsig_interested + self.nbkg_total) + + print("Total number of background: {}, uncertainty: {}".format(self.nbkg_total, self.nbkg_total_err)) + print("S/sqrt(S+B): {}".format(self.SNR)) + print("*"*80) + + def plot(self, outputfile): + ROOT.gStyle.SetOptFit(0000); + ROOT.gROOT.SetBatch(True); + ROOT.gROOT.SetStyle("Plain"); + ROOT.gStyle.SetGridStyle(3); + ROOT.gStyle.SetOptStat(000000); + ROOT.gStyle.SetOptTitle(0) + #ROOT.TH1.AddDirectory(False) + + #xframe = wspace.var('x').frame(RooFit.Title("PF electron")) + xframe = self.mass.frame() + + if self.isMC: + self.data.plotOn(xframe, RooFit.Binning(self.nbin_data), RooFit.Name("datapoint")) + self.pdf['model'].plotOn(xframe,RooFit.Name("global"),RooFit.Range("Full"),RooFit.LineColor(2),RooFit.MoveToBack()) + if self.paramOn: + self.pdf['model'].paramOn(xframe,RooFit.Layout(0.60,0.92,0.73)) + #self.pdf['model'].paramOn(xframe,RooFit.Layout(0.15,0.45,0.73)) + xframe.getAttText().SetTextSize(0.03) + legend = ROOT.TLegend(0.65,0.75,0.92,0.85); + pt = ROOT.TPaveText(0.72,0.38,0.92,0.50,"brNDC") + #legend = ROOT.TLegend(0.15,0.75,0.42,0.85) + #pt = ROOT.TPaveText(0.15,0.38,0.45,0.50,"brNDC") + legend.AddEntry(xframe.findObject("global"),"Total Fit","l") + + else: + if self.blinded: + self.data.plotOn(xframe, RooFit.Binning(self.nbin_data), RooFit.CutRange("SB1,SB2"), RooFit.Name("datapoint")) + else: + self.data.plotOn(xframe, RooFit.Binning(self.nbin_data), RooFit.Name("datapoint")) + self.pdf['model'].plotOn(xframe,RooFit.Name("global"),RooFit.Range("Full"),RooFit.LineColor(2),RooFit.MoveToBack()) + self.pdf['model'].plotOn(xframe,RooFit.Name("bkg"),RooFit.Components("bkg"),RooFit.Range("Full"),RooFit.DrawOption("F"),RooFit.VLines(),RooFit.FillColor(42),RooFit.LineColor(42),RooFit.LineWidth(1),RooFit.MoveToBack()) + plotted_partial = [] + for name, info in self.partialfit.items(): + self.pdf['model'].plotOn(xframe,RooFit.Name(name),RooFit.Components("bkg,"+",".join(plotted_partial)+",{}".format(name)),RooFit.Range("Full"),RooFit.DrawOption("F"),RooFit.VLines(),RooFit.FillColor(info['color']),RooFit.LineColor(info['color']),RooFit.LineWidth(1),RooFit.MoveToBack()) + plotted_partial.append(name) + self.pdf['model'].plotOn(xframe,RooFit.Name("sig"),RooFit.Components("sig"),RooFit.Range("Full"),RooFit.DrawOption("L"),RooFit.LineStyle(2),RooFit.LineColor(1)) + legend = ROOT.TLegend(0.56,0.65,0.92,0.85) #if prefix == 'BToKEE' else ROOT.TLegend(0.46,0.70,0.92,0.85) + legend.AddEntry(xframe.findObject("bkg"),"Combinatorial","f") + for name, info in self.partialfit.items(): + legend.AddEntry(xframe.findObject(name),info['label'],"f") + legend.AddEntry(xframe.findObject("sig"),self.sigName,"l") + + xframe.GetYaxis().SetTitleOffset(0.9) + xframe.GetYaxis().SetTitleFont(42) + xframe.GetYaxis().SetTitleSize(0.05) + xframe.GetYaxis().SetLabelSize(0.04) + xframe.GetYaxis().SetLabelFont(42) + xframe.GetXaxis().SetTitleOffset(0.9) + xframe.GetXaxis().SetTitleFont(42) + xframe.GetXaxis().SetTitleSize(0.05) + xframe.GetXaxis().SetLabelSize(0.04) + xframe.GetXaxis().SetLabelFont(42) + + xframe.GetYaxis().SetTitle("Events / {0:.0f} MeV".format((self.fit_up - self.fit_low)/self.nbin_data*1000.)) + xtitle = "m(K^{+}e^{+}e^{-}) [GeV]" #if prefix == 'BToKEE' else "m(K^{+}K^{-}e^{+}e^{-}) [GeV]" + xframe.GetXaxis().SetTitle(xtitle) + xframe.SetStats(0) + xframe.SetMinimum(0) + + + legend.SetTextFont(42) + legend.SetTextSize(0.04) + legend.AddEntry(xframe.findObject("datapoint"),"Data","lpe") + + if self.drawSNR: + pt = ROOT.TPaveText(0.7,0.35,0.92,0.63,"brNDC") + #pt = ROOT.TPaveText(0.72,0.30,0.92,0.63,"brNDC") + pt.SetFillColor(0) + pt.SetBorderSize(1) + pt.SetTextFont(42); + pt.SetTextSize(0.04); + pt.SetTextAlign(12) + if self.mvaCut: + pt.AddText("MVA cut: {0:.2f}".format(self.mvaCut)) + pt.AddText("S_{{total}}: {0:.0f}#pm{1:.0f}".format(self.nsig_total, self.nsig_total_err)) + pt.AddText("S: {0:.0f}#pm{1:.0f}".format(self.nsig_interested, self.nsig_interested_err)) + if not self.isMC: + pt.AddText("B: {0:.0f}#pm{1:.0f}".format(self.nbkg_total, self.nbkg_total_err)) + pt.AddText("S/#sqrt{{S+B}}: {0:.1f}".format(self.SNR)) + #pt.AddText("Punzi: {0:.1f}".format(Punzi(nbkgWindow, 2.0, 5.0))) + if not self.fitConverged: + pt.AddText("Fit is not converged") + + + # Plot results of fit on a different frame + c2 = ROOT.TCanvas('canvas', 'canvas', 800, 600) + c2.SetGrid() + c2.cd() + ROOT.gPad.SetLeftMargin(0.10) + ROOT.gPad.SetRightMargin(0.05) + xframe.Draw() + legend.Draw() + if self.drawSNR: pt.Draw() + CMS_lumi(self.isMC) + c2.cd() + c2.Update() + c2.SaveAs(outputfile.replace('.pdf','')+'.pdf') + print("="*80) + + + def fit(self, tree, outputfile): + if not self.fit_init: return + msgservice = ROOT.RooMsgService.instance() + msgservice.setGlobalKillBelow(RooFit.FATAL) + self.load_tree(tree) + self.setup_model_sig() + if self.isMC: + self.wspace.factory('ExtendPdf::model(sig,nsig)') + else: + self.setup_model_bkg() + self.wspace.factory('SUM::model(nsig*sig,nbkg*bkg{})'.format(','+','.join(['n'+name+'*'+name for name in self.partialfit.keys()]))) + + self.var['mean'].setVal(self.params['mean']); self.var['mean'].setConstant(True) + self.var['width'].setVal(self.params['width']); self.var['width'].setConstant(True) + self.var['alpha1'].setVal(self.params['alpha1']); self.var['alpha1'].setConstant(True) + self.var['n1'].setVal(self.params['n1']); self.var['n1'].setConstant(True) + self.var['alpha2'].setVal(self.params['alpha2']); self.var['alpha2'].setConstant(True) + self.var['n2'].setVal(self.params['n2']); self.var['n2'].setConstant(True) + if self.blinded: + self.var['nsig'].setVal(self.expS); self.var['nsig'].setConstant(True) + + self.pdf['model'] = self.wspace.pdf('model') + + self.mass.setRange("window",self.sig_low,self.sig_up) + self.mass.setRange("fom_window",self.fom_low,self.fom_up) + self.mass.setRange("SB1",self.fit_low,self.sig_low) + self.mass.setRange("SB2",self.sig_up,self.fit_up) + + ## fit the model to the data. + print('Fitting data...') + if (not self.isMC) and self.blinded: + self.results = self.pdf['model'].fitTo(self.data, RooFit.Extended(True), RooFit.Save(), RooFit.Range("SB1,SB2"), RooFit.SplitRange(True), RooFit.PrintLevel(-1)) + else: + self.results = self.pdf['model'].fitTo(self.data, RooFit.Extended(True), RooFit.Save(), RooFit.Range(self.fit_low, self.fit_up), RooFit.PrintLevel(-1)) + + self.results.Print() + self.fitConverged = True if self.results.status() == 0 else False + self.nsig_total = self.var['nsig'].getVal() + self.nsig_total_err = self.var['nsig'].getError() + + if not self.isMC: + self.bkg_unc_propagation(outputfile) + self.plot(outputfile) + + if self.isMC: + return 0.0 + else: + output = {} + output['Stot'] = self.nsig_total + output['StotErr'] = self.nsig_total_err + output['S'] = self.nsig_interested + output['SErr'] = self.nsig_interested_err + output['B'] = self.nbkg_total + output['BErr'] = self.nbkg_total_err + output['exp_alpha'] = self.fit_params.find('exp_alpha').getVal() + output['fitConverged'] = self.fitConverged + return output + + + def fit_kde(self, tree, outputfile): + if not self.fit_init: return + msgservice = ROOT.RooMsgService.instance() + msgservice.setGlobalKillBelow(RooFit.FATAL) + self.load_tree(tree) + print('Fitting KDE...') + self.wspace.factory('KeysPdf::{0}(x,data,MirrorLeft,2.0)'.format(self.pdfname)) + self.pdf['model'] = self.wspace.pdf(self.pdfname) + self.plot(outputfile) + + wf = ROOT.TFile(outputfile.replace('.pdf','').replace('.root','')+'.root', "RECREATE") + self.wspace.Write() + wf.Close() + print("Created a RooWorkspace file - {}, with a KeysPdf named - {}".format(outputfile.replace('.pdf','').replace('.root','')+'.root', self.pdfname)) + + +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser(description='Unbinned likelihood fit') + parser.add_argument("-i", "--inputfile", dest="inputfile", default="", help="Input file") + parser.add_argument("-o", "--outputfile", dest="outputfile", default="", help="Output file") + parser.add_argument("-p", "--partial", dest="partial", action="store_true", help="Fit partially reconstructed background") + parser.add_argument("-n", "--pdfname", dest="pdfname", default="partial", help="PDF name of the Partially reconstructed background") + args = parser.parse_args() + + params = params_jpsi_pf + partialfit = OrderedDict() + partialfit['partial'] = {'filename': 'part_workspace_jpsi_pf.root', 'label': 'Partially Reco.', 'color': 40} + #partialfit['partial'] = {'filename': 'part_workspace_nonresonant_lowq2_pf.root', 'label': 'Partially Reco.', 'color': 40} + #partialfit['jpsi'] = {'filename': 'jpsi_workspace_lowq2_pf.root', 'label': 'B^{+}#rightarrow K^{+} J/#psi(#rightarrow e^{+}e^{-})', 'color': 46, 'expected_yield': 150} + + tree = ROOT.TChain('tree') + tree.AddFile(args.inputfile) + b_fitter = fitter() + if args.partial: + b_fitter.init_fit_kde(pdfname=args.pdfname) + b_fitter.fit_kde(tree, args.outputfile) + else: + b_fitter.init_fit_mc() + #b_fitter.init_fit_data(params=params, partialfit=partialfit, drawSNR=True) + b_fitter.fit(tree, args.outputfile) + + diff --git a/models.cc b/archive/models.cc similarity index 100% rename from models.cc rename to archive/models.cc diff --git a/models.h b/archive/models.h similarity index 100% rename from models.h rename to archive/models.h diff --git a/fit/KEE_lowq2_roofit_plb_pull_modified_kde.py b/fit/KEE_lowq2_roofit_plb_pull_modified_kde.py new file mode 100644 index 0000000..770dd06 --- /dev/null +++ b/fit/KEE_lowq2_roofit_plb_pull_modified_kde.py @@ -0,0 +1,566 @@ +import ROOT +from ROOT import RooFit +import math +from roofit_helper import * +#ROOT.gROOT.ProcessLine(open('roofit_models.h').read()) +#from ROOT import DoubleSidedCB +#from ROOT import ROOT_DoubleSidedCB +#from XGBweight import XGBweight +#rt.gInterpreter.Declare(XGBweight) +#from PUweight import PUweight +#rt.gInterpreter.Declare(PUweight) +from roofit_models import root_function_DoubleSidedCB +ROOT.gInterpreter.Declare(root_function_DoubleSidedCB) +#ROOT.gStyle.SetOptFit(0000); +ROOT.gROOT.SetBatch(True); +ROOT.gROOT.SetStyle("Plain"); +msgservice = ROOT.RooMsgService.instance() +msgservice.setGlobalKillBelow(RooFit.FATAL) +import csv +import os.path +import atexit + +import numpy as np +import matplotlib as mpl +mpl.use('agg') +import matplotlib.font_manager +from matplotlib import pyplot as plt +from matplotlib import rc +#.Allow for using TeX mode in matplotlib Figures +rc('font',**{'family':'sans-serif','sans-serif':['Computer Modern Roman']}) +rc('text', usetex=True) +plt.rcParams['text.latex.preamble']=[r"\usepackage{lmodern}"] + +ratio=5.0/7.0 +fig_width_pt = 3*246.0 # Get this from LaTeX using \showthe\columnwidth +inches_per_pt = 1.0/72.27 # Convert pt to inch +golden_mean = ratio if ratio != 0.0 else (np.sqrt(5)-1.0)/2.0 # Aesthetic ratio +fig_width = fig_width_pt*inches_per_pt # width in inches +fig_height = fig_width*golden_mean # height in inches +fig_size = [fig_width,fig_height] + +params = {'text.usetex' : True, + 'axes.labelsize': 24, + 'font.size': 24, + 'legend.fontsize': 20, + 'xtick.labelsize': 24, + 'ytick.labelsize': 24, + 'font.family' : 'lmodern', + 'text.latex.unicode': True, + 'axes.grid' : True, + 'text.usetex': True, + 'figure.figsize': fig_size} +plt.rcParams.update(params) + +nbin_data = 20 + +def residuals(xframe, var,name): + hresid = xframe.residHist() + xframe2 = var.frame() + xframe2.addPlotable(hresid,"P") + c2=canvas_create(xframe2,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',False) + c2.SaveAs(name+'_residual.pdf') + hpull = xframe.pullHist() + xframe3 = var.frame() + xframe3.addPlotable(hpull,"P") + c3=canvas_create(xframe3,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',False) + c3.SaveAs(name+'_pull.pdf') + + + +def define_workspace_bmass_data(wspace_name,mB_branch,tree): + wspace = ROOT.RooWorkspace(wspace_name) + fitvars = ROOT.RooArgSet() + bMass = ROOT.RooRealVar(mB_branch, "m(K^{+}e^{+}e^{-})", 4.7, 5.7, "GeV") + fitvars.add(bMass) + dataset = ROOT.RooDataSet('data','data',tree, ROOT.RooArgSet(fitvars)) + theBMassfunc = ROOT.RooFormulaVar("x", "x", "@0", ROOT.RooArgList(bMass) ) + theBMass = dataset.addColumn(theBMassfunc) ; + theBMass.setRange(4.7,5.7); + fitvars.add(theBMass) + getattr(wspace, "import")(dataset, RooFit.Rename('data')) + # When a RooWorkspace is set as an attribute of a class, it can trigger a memory error + # This is solved in the latest ROOT version > 6.14.08 + atexit.register(wspace.Delete) + return wspace,dataset,bMass,theBMass + + +def get_visible_yield_error(obs, results, pdf, amplitude): + intgral_pdf = pdf.createIntegral(obs,obs,"window") + intgral_pdf_err = intgral_pdf.getPropagatedError(results, obs) + visible = amplitude.getVal() * intgral_pdf.getVal() + if intgral_pdf.getVal()==0: + visible_err =0 + else: + visible_err = visible * math.sqrt(pow(amplitude.getError()/amplitude.getVal(), 2) + pow(intgral_pdf_err/intgral_pdf.getVal(), 2)) if amplitude.getVal() != 0.0 else 0.0 + if np.isnan(visible): + visible = 0.0 + if np.isnan(visible_err): + visible_err = 0.0 + return visible, visible_err + +def get_visible_yield(obs, pdf, amplitude): + intgral_pdf = pdf.createIntegral(obs,obs,"window") + visible = amplitude * intgral_pdf.getVal() + return visible + + +##################### signal fit == Double sided CB ###################### +def signal_fit(tree, outputfile, branches): + print "Signal" + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_signal",branches[0],tree) + # signal + wspace.factory('mean[5.272e+00, 5.22e+00, 5.5e+00]') + wspace.factory('width[4.1858e-02, 1.0e-6, 5.0e-1]') + wspace.factory('alpha1[1.0, 0.0, 10.0]') + wspace.factory('n1[1.0, 1.0, 20.0]') + wspace.factory('alpha2[1.0, 0.0, 10.0]') + wspace.factory('n2[1.0, 1.0, 20.0]') + wspace.factory('GenericPdf::sig( "DoubleSidedCB2(x,mean,width,alpha1,n1,alpha2,n2)",{x,mean,width,alpha1,n1,alpha2,n2})') + + sgnframe=theBMass.frame() + wspace.factory('nsig[1000,0,100000000]') + wspace.factory('RooExtendPdf::esig(sig,nsig)') + sig=wspace.pdf('sig') + nsig=wspace.var('nsig') + esig=wspace.pdf('esig') + results = esig.fitTo(dataset,RooFit.Extended(True),RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1)) + + results.Print() + dataset.plotOn(sgnframe,RooFit.Binning(nbin_data), RooFit.Name("datas")) + esig.plotOn(sgnframe, RooFit.Normalization(1.0, ROOT.RooAbsReal.RelativeExpected), RooFit.LineColor(ROOT.kBlue), RooFit.LineWidth(2) ) + n_param = results.floatParsFinal().getSize() + print "chi2",sgnframe.chiSquare(n_param),"ndof",n_param + print "edm",results.edm(),"log",results.minNll() + + #c1=canvas_create(sgnframe,4.7,5.7,nbin_data,'m (e^{+}e^{-}K) [GeV] ') + c1, top, bottom =canvas_create_pull(sgnframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',theBMass) + top.cd() + + CMS_lumi() + c1.SaveAs('sgn_eek_'+outputfile+'.pdf') + residuals(sgnframe,theBMass,'sgn_eek_'+outputfile) + params=esig.getParameters(ROOT.RooArgSet(bMass)) + return {"mean":params.getRealValue('mean'),"width": params.getRealValue('width'),"alpha1":params.getRealValue('alpha1'),"n1":params.getRealValue('n1'),"alpha2":params.getRealValue('alpha2'),"n2":params.getRealValue('n2')} + + +############################### B->KJpsi fit ############################## +def kjpsi_fit(tree, outputfile, branches): + print "kjpsi" + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_kjpsi_bkg",branches[0],tree) + wspace.factory('mean_kjpsi[4.7, 1.0, 5.0]') + wspace.factory('width_kjpsi[0.1, 0.001, 5.0]') + wspace.factory("RooGaussian::kjpsi(x,mean_kjpsi,width_kjpsi)") + wspace.factory('nkjpsi[1000,0,10e+6]') + wspace.factory('RooExtendPdf::ekjpsi(kjpsi,nkjpsi)') + nkjpsi=wspace.var('nkjpsi') + ekjpsi=wspace.pdf('ekjpsi') + results = ekjpsi.fitTo(dataset,RooFit.Extended(True),RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1)) + results.Print() + kjpframe=theBMass.frame() + dataset.plotOn(kjpframe,RooFit.Binning(nbin_data), RooFit.Name("datas")) + ekjpsi.plotOn(kjpframe,RooFit.Name("ekjpsi"),RooFit.LineColor(30),RooFit.Normalization(1.0, ROOT.RooAbsReal.RelativeExpected),RooFit.LineWidth(3)) + #c1=canvas_create(kjpframe,4.7,5.7,nbin_data,'m (e^{+}e^{-}K) [GeV] ') + c1, top, bottom =canvas_create_pull(kjpframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',theBMass) + top.cd() + + CMS_lumi() + c1.SaveAs('bkg_jpsik_'+outputfile+'.pdf') + residuals(kjpframe,theBMass,'bkg_jpsik_'+outputfile) + params=ekjpsi.getParameters(ROOT.RooArgSet(bMass)) + n_param = results.floatParsFinal().getSize() + print "chi2",kjpframe.chiSquare(n_param),"ndof",n_param + print "edm",results.edm(),"log",results.minNll() + + return {"mean_kjpsi":params.getRealValue('mean_kjpsi'),"width_kjpsi":params.getRealValue('width_kjpsi')} + + +############################ BKG fit ################################# +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')} + + +############################ KDE fit ####################### +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 + + +############################# total fit ############################## +def total_fit(tree, outputfile, branches, sgn_parameters=None, kjpsi_pdf=None, kstaree_pdf=None, bkg_parameters=None, set_sgn_yield=None,Blind_range={"min":4.7,"max":5.7} , number_of_mctoys=None,mva=None,log='log.csv'): + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_total",branches[0],tree) + print "Total" + #amplitudes + wspace.factory('nsig[10.0, 0.0, 1000000.0]' ) + wspace.factory('nbkg[100.0, 0.0, 100000000.0]') + wspace.factory('nkjpsi[10.0, 0.0, 1000000.0]') + wspace.factory('nkstaree[10.0, 0.0, 1000000.0]') + + # signal + wspace.factory('mean[5.272e+00, 5.22e+00, 5.5e+00]') + wspace.factory('width[4.1858e-02, 1.0e-6, 5.0e-1]') + wspace.factory('alpha1[1.0, 0.0, 10.0]') + wspace.factory('n1[1.0, 1.0, 20.0]') + wspace.factory('alpha2[1.0, 0.0, 10.0]') + wspace.factory('n2[1.0, 1.0, 20.0]') + wspace.factory('GenericPdf::sig( "DoubleSidedCB2(x,mean,width,alpha1,n1,alpha2,n2)",{x,mean,width,alpha1,n1,alpha2,n2})') + + # Exponential - bkg + wspace.factory('exp_alpha[-1.0, -100.0, -1.e-4]') + alpha = wspace.var('alpha') + wspace.factory('Exponential::bkg(x,exp_alpha)') + + # Gaussian - bkg + #wspace.factory('mean_kjpsi[4.7, 1.0, 5.0]') + #wspace.factory('width_kjpsi[0.1, 0.001, 5.0]') + #wspace.factory("RooGaussian::kjpsi(x,mean_kjpsi,width_kjpsi)") + + # KJpsi - bkg + getattr(wspace, "import")(kjpsi_pdf, RooFit.Rename('kjpsi')) + + # K* ee - bkg + getattr(wspace, "import")(kstaree_pdf, RooFit.Rename('kstaree')) + + #sum + #wspace.factory('SUM::model(nsig*sig,nbkg*bkg,nkjpsi*kjpsi,nkstaree*kstaree)') + wspace.factory('SUM::model(nsig*sig,nbkg*bkg,nkjpsi*kjpsi)') + + model = wspace.pdf('model'); bkg = wspace.pdf('bkg') + sig = wspace.pdf('sig'); kjpsi = wspace.pdf('kjpsi'); + nsig = wspace.var('nsig'); nbkg = wspace.var('nbkg') + nkjpsi = wspace.var('nkjpsi') + #mean = wspace.var('mean') + nkstaree = wspace.var('nkstaree') + kstaree = wspace.pdf('kstaree') + + if set_sgn_yield!=None: + nsig.setVal(set_sgn_yield) + nsig.setConstant(True) + for par in sgn_parameters.keys(): + (wspace.var(par)).setVal(sgn_parameters[par]) + (wspace.var(par)).setConstant(True) + #for par in kjpsi_parameters.keys(): + # (wspace.var(par)).setVal(kjpsi_parameters[par]) + # (wspace.var(par)).setConstant(True) + for par in bkg_parameters.keys(): + (wspace.var(par)).setVal(bkg_parameters[par]) + + results = model.fitTo(dataset, RooFit.Extended(True), RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1)) + print results.Print() + xframe=theBMass.frame(RooFit.Title("")) + + + if Blind_range["min"]>4.7 and Blind_range["max"]<5.7: + norm = dataset.reduce('(({0} > {1}) & ({0} < {2})) | (({0}> {3}) & ({0} < {4}))'.format(branches[0],"4.7", str(Blind_range["min"]),str(Blind_range["max"]), "5.7")).sumEntries() / dataset.reduce('({0} > {1}) & ({0} < {2})'.format(branches[0],"4.7", "5.7")).sumEntries() +# blind= ROOT.RooRealVar("blind","blind",Blind_range["min"],Blind_range["max"]) + # blind.setRange("left",4.7,Blind_range["min"]) + # blind.setRange("right",Blind_range["max"],5.7) + theBMass.setRange("left",4.7,Blind_range["min"]) + theBMass.setRange("right",Blind_range["max"],5.7) + norm=1.0 + dataset.plotOn(xframe,RooFit.Binning(nbin_data), RooFit.Name("datas"),RooFit.CutRange("left,right")) + + else: + norm=1. + dataset.plotOn(xframe,RooFit.Binning(nbin_data), RooFit.Name("datas")) + + + #norm=1. + #dataset.plotOn(xframe,RooFit.Binning(nbin_data), RooFit.Name("datas")) + + model.plotOn(xframe,RooFit.Name("bkg"),RooFit.Components("bkg"),RooFit.Range("Full"),RooFit.DrawOption("L"),RooFit.VLines(),RooFit.FillColor(49),RooFit.LineColor(49),RooFit.LineStyle(2),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineWidth(3)) + model.plotOn(xframe,RooFit.Name("kjpsi"),RooFit.Components("kjpsi"),RooFit.Range("Full"),RooFit.FillColor(30),RooFit.LineColor(30),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineStyle(2), RooFit.LineWidth(3),RooFit.DrawOption("L"),RooFit.MoveToBack()) + #model.plotOn(xframe,RooFit.Name("kstaree"),RooFit.Components("kstaree"),RooFit.Range("Full"),RooFit.FillColor(30),RooFit.LineColor(12),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineStyle(2), RooFit.LineWidth(3),RooFit.DrawOption("L"),RooFit.MoveToBack()) + model.plotOn(xframe,RooFit.Name("sig"),RooFit.Components("sig"),RooFit.Range("Full"),RooFit.DrawOption("L"),RooFit.LineStyle(2),RooFit.LineColor(ROOT.kBlue),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected), RooFit.LineWidth(3)) + model.plotOn(xframe, RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineColor(ROOT.kRed) ) + + wspace.defineSet('obs', 'x') + obs = wspace.set('obs') + theBMass.setRange("window",Blind_range["min"],Blind_range["max"]) + + #theBMass.setRange("window",5.0,5.4) + obs2= ROOT.RooRealVar("obs2","obs2",Blind_range["min"],Blind_range["max"]) + nset = ROOT.RooArgSet(obs2) + print sig.getVal(), sig.getVal(nset) + print Blind_range + print nbkg.getVal(),nkjpsi.getVal(),nsig.getVal() + nbkg_visible, nbkg_visible_err = get_visible_yield_error(obs, results, bkg, nbkg) + nsig_visible, nsig_visible_err = get_visible_yield_error(obs, results, sig, nsig) + nkjpsi_visible, nkjpsi_visible_err = get_visible_yield_error(obs, results, kjpsi, nkjpsi) + print "hereee",nbkg_visible,nsig_visible,nkjpsi_visible +# c1=canvas_create(xframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]') + n_param = results.floatParsFinal().getSize() + print "chi2",xframe.chiSquare(n_param),"ndof",n_param + print "edm",results.edm(),"log",results.minNll() + #c1=canvas_create(xframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]') + c1, top, bottom =canvas_create_pull(xframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',theBMass) + top.cd() + + legend = ROOT.TLegend(0.65,0.65,0.92,0.85) + legend.AddEntry(xframe.findObject("bkg"),"Combinatorial","l"); + legend.AddEntry(xframe.findObject("kjpsi"),"B -> J/#psiK","l"); + #legend.AddEntry(xframe.findObject("kstaree"),"B -> eeK*","l"); + legend.AddEntry(xframe.findObject("sig"),"B -> eeK","l"); + legend.SetLineColor(ROOT.kWhite) + legend.SetTextFont(42); + legend.SetTextSize(0.04); + legend.AddEntry(xframe.findObject("datas"),"Data","lpe"); + legend.Draw(); + pt=pt_create(mva,nsig_visible,nsig_visible_err,nkjpsi_visible+nbkg_visible) + pt.Draw() + CMS_lumi() + c1.cd() + c1.Update() + c1.SaveAs('total_fit_'+outputfile+'.pdf') + print nsig_visible, nsig_visible_err, nbkg_visible_err, nkjpsi_visible_err + residuals(xframe,theBMass,outputfile+"_poutana") + if number_of_mctoys!=None: + nsig.setConstant(False) + mctoys = ROOT.RooMCStudy(model, ROOT.RooArgSet(theBMass), + RooFit.Binned( ROOT.kTRUE), + #RooFit.Binned( ROOT.kFALSE), + ROOT.RooFit.Silence(), + RooFit.Extended(), + RooFit.FitOptions( + RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1) + ) + ) + mctoys.generateAndFit(number_of_mctoys) + + frame1 = mctoys.plotParam(nsig, ROOT.RooFit.Bins(40)) + frame2 = mctoys.plotError(nsig, ROOT.RooFit.Bins(40)) + frame3 = mctoys.plotPull(nsig, ROOT.RooFit.Bins(40), + ROOT.RooFit.FitGauss(ROOT.kTRUE) + ) + # Plot distribution of minimized likelihood + frame4 = mctoys.plotNLL(ROOT.RooFit.Bins(40)) + cpr=canvas_create(frame1,4.7,5.7,1,'Distribution of the fitted value of N_{sgn}',False) + cpr.SaveAs("cpr_"+outputfile+".pdf") + cerr=canvas_create(frame2,0,1,1,'Distribution of the fitted error of N_{sgn}',False) + cerr.SaveAs("cerr_"+outputfile+".pdf") + cpull=canvas_create(frame3,4.7,5.7,1,' Pull of N_{sgn}',False) + cpull.SaveAs("cpull_"+outputfile+".pdf") + clog=canvas_create(frame4,4.7,5.7,1,'- log (L)') + clog.SaveAs("clog_"+outputfile+".pdf") + + postfit_data = mctoys.fitParDataSet() + postfit_nsig = np.array([postfit_data.get(i).getRealValue("nsig") for i in range(int(postfit_data.sumEntries()))]) + #postfit_nsig = np.array([get_visible_yield(obs, sig, postfit_data.get(i).getRealValue("nsig")) for i in range(int(postfit_data.sumEntries()))]) + #postfit_mu = np.array([s/nsig_visible for s in postfit_nsig]) + postfit_mu = np.array([s/set_sgn_yield for s in postfit_nsig]) + rms_mu = np.std(postfit_mu) + fig, ax = plt.subplots() + ax.hist(postfit_mu, bins=50, normed=True, histtype='step', label='MVA={}, RMS={}'.format(mva, rms_mu)) + ax.set_xlabel(r'$\mu$') + ax.set_ylabel('a.u.') + ax.legend(loc='best') + fig.savefig('cmu_{}.pdf'.format(outputfile), bbox_inches='tight') + + csv_header = ['cut', 'nsig', 'nbkg', 'njpsi', 'snr', 'rms_mu'] + df = {} + df['cut'] = mva + df['nsig'] = nsig_visible + df['nbkg'] = nbkg_visible + df['njpsi'] = nkjpsi_visible + df['snr'] = nsig_visible / np.sqrt(nsig_visible + nbkg_visible + nkjpsi_visible) + df['rms_mu'] = 0.0 if number_of_mctoys == None else rms_mu_ + csv_outputfile = log + file_exists = os.path.isfile(csv_outputfile) + with open (csv_outputfile, 'a+') as filedata: + writer = csv.DictWriter(filedata, delimiter=',', fieldnames=csv_header) + if not file_exists: + writer.writeheader() + writer.writerow(df) + + + return (nsig_visible,nbkg_visible,nkjpsi_visible) + + +def kee_yield_from_kjpsi(kjpsi_yield,tree_kee,tree_kjpsi,total_kee,total_kjpsi,xgb): + print "\nWARNING!!!!!",total_kee,"will be used as denominsator for kee eff. and ",total_kjpsi,"for kjpsi. Is this correct ?; code hypothesizes that cross validation is in 8 parts (hardcoded, change if different)\n" + hkee = ROOT.TH1F("hkee","",50,4.7,5.7) + hkjpsi = ROOT.TH1F("hkjpsi","",50,4.7,5.7) + #tree_kee.Draw("Bmass>>hkee","1./8.*(Bmass>4.7 && Bmass<5.7 && Mll>1.05 && Mll<2.45 && xgb>"+xgb+")") + #tree_kjpsi.Draw("Bmass>>hkjpsi","1./8.*(Bmass>4.7 && Bmass<5.7 && Mll>2.8 && Mll<3.25 && xgb>"+xgb+")") + tree_kee.Draw("Bmass>>hkee","1./8.*(Bmass>4.7 && Bmass<5.7 && Mll>1.05 && Mll<2.45 && ( (Npv<15 && xgb>8) || (Npv>14 && xgb>8.5 ) ))") + tree_kjpsi.Draw("Bmass>>hkjpsi","1./8.*(Bmass>4.7 && Bmass<5.7 && Mll>2.8 && Mll<3.25 && ( (Npv<15 && xgb>8) || (Npv>14 && xgb>8.5 ) ))") + + eff_kee=float(hkee.Integral()) / total_kee + eff_kjpsi=float(hkjpsi.Integral()) / total_kjpsi + result = kjpsi_yield / eff_kjpsi * 4.43*0.01/(1.026*5.93) *eff_kee + print "expect",result,"eff rare",eff_kee,"eff res",eff_kjpsi,"res data",kjpsi_yield + print "rare eff num",float(hkee.Integral()),"den",total_kee + return result + +################################### for scan ############################ +def FitForScan(inputfile, mva, isgnfile, ikspiBkg, ibkg, kjpsi_yield_for_kee,total_nsgn, total_nkjpsi, name ): + branches=["Bmass","Mll","xgb"] + cuts = "xgb>"+str(mva)+" && 1.05"+str(args.mva)+" && 1.05<"+branches[1]+" && "+branches[1]+"<2.45"+" && "+branches[3]+">2.0" #+" && {} > 10 && {} > 10".format(branches[4], branches[5]) + cuts_samesign = branches[2]+">"+str(args.mva)+" && 1.05<"+branches[1]+" && "+branches[1]+"<2.45" + print "cut: ", cuts + #cuts = " 1.05<"+branches[1]+" && "+branches[1]+"<2.45 && ( (Npv<15 && xgb>8) || (Npv>14 && xgb>8.5 ) )" + args.outputfile+="_wp"+str(args.mva) + + bkg_parameters={'exp_alpha':-1.98} + + print "start" + if args.fit_primtv: + if args.sel_primtv!= None: + args.sel_primtv = args.sel_primtv.split(",") + else: + args.sel_primtv = ["sgn","bkg_comb","bkg_kjpsi"] + print "primitive params" + if "sgn" in args.sel_primtv: + tree_sgn = ROOT.TChain('mytreefit') + tree_sgn.Add(args.isgnfile) + tree_sgn_cut=tree_sgn.CopyTree(cuts) + signal_parameters = signal_fit(tree_sgn_cut, args.outputfile+"_sgnMC", branches) + print "parameters SGN", signal_parameters['mean'], signal_parameters['width'],signal_parameters['alpha1'],signal_parameters['n1'],signal_parameters['alpha2'],signal_parameters['n2'] + + if "bkg_kjpsi" in args.sel_primtv: + tree_kjpsi = ROOT.TChain('mytreefit') + tree_kjpsi.Add(args.ikjpsiBkg) + tree_kjpsi_cut=tree_kjpsi.CopyTree(cuts) + kjpsi_pdf = kde_fit(tree_kjpsi_cut, args.outputfile+"_kjpsiMC", branches, 'kjpsi') + print "finished kde fit for K J/psi" + + if "bkg_kstaree" in args.sel_primtv: + tree_kstaree = ROOT.TChain('mytreefit') + tree_kstaree.Add(args.ikstareeBkg) + tree_kstaree_cut=tree_kstaree.CopyTree(cuts) + kstaree_pdf = kde_fit(tree_kstaree_cut, args.outputfile+"_kstareeMC", branches, 'kstaree') + print "finished kde fit for K* ee" + + if "bkg_comb" in args.sel_primtv: + #cuts = branches[2]+">8 && "+branches[1]+"<5." + #cuts = branches[2]+">"+str(args.mva)+" && "+branches[1]+"<5" + tree_bkg = ROOT.TChain('mytreefit') + tree_bkg.Add(args.ibkg) + tree_bkg_cut=tree_bkg.CopyTree(cuts_samesign) + bkg_parameters = bkg_fit(tree_bkg_cut, args.outputfile+"_SameSign", branches) + print "parameters Combinatorial BKG", bkg_parameters['exp_alpha'] + + else: + signal_parameters={'mean': 5.272, 'width': 0.057, 'alpha1': 0.652, 'n1': 3.3, 'alpha2': 1.32, 'n2': 2.01} + kjpsi_parameters={'mean_kjpsi':4.72,'width_kjpsi':1.06} + bkg_parameters={'exp_alpha':-1.98} + + if args.kjpsi_yield_for_kee!=None: + tree_sgn = ROOT.TChain('mytreefit') + tree_sgn.Add(args.isgnfile) + tree_kjpsi = ROOT.TChain('mytreefit') + tree_kjpsi.Add(args.ikspiBkg) + args.set_expected_sgn = kee_yield_from_kjpsi(args.kjpsi_yield_for_kee,tree_sgn,tree_kjpsi,args.total_nsgn,args.total_nkjpsi,str(args.mva)) + print "WARNING expected signal set and FIXED to ",args.set_expected_sgn,"in all q^2" + + #args.set_expected_sgn = None + if not args.skip_realfit: + #cuts = branches[2]+">"+str(args.mva)+" && 1.05<"+branches[1]+" && "+branches[1]+"<2.45"+" && "+branches[3]+">2.0 &&"+branches[4]+">2.0" + tree = ROOT.TChain('mytreefit') + tree.Add(args.inputfile) + tree_cut=tree.CopyTree(cuts) + nsig, nbkg, nkjpsi =total_fit(tree_cut, args.outputfile, branches, signal_parameters, kjpsi_pdf, kstaree_pdf, bkg_parameters, args.set_expected_sgn, {"min":5.0,"max":5.4}, args.number_of_mctoys, str(args.mva), args.log) + # combinatorial BKG parameters set but not fixed. + print "sigma",float(nsig)/math.sqrt(nsig+nkjpsi+nbkg),"nsig",float(nsig),"nbkg",float(nbkg),"Kjpsi leak",float(nkjpsi) diff --git a/fit/KJpsi_roofit_plb_modified_kde_fixedPartial.py b/fit/KJpsi_roofit_plb_modified_kde_fixedPartial.py new file mode 100644 index 0000000..31e0801 --- /dev/null +++ b/fit/KJpsi_roofit_plb_modified_kde_fixedPartial.py @@ -0,0 +1,504 @@ +import ROOT +from ROOT import RooFit +import math +from roofit_helper import * +#ROOT.gROOT.ProcessLine(open('roofit_models.h').read()) +#from ROOT import DoubleSidedCB +#from ROOT import ROOT_DoubleSidedCB +from roofit_models import root_function_DoubleSidedCB +ROOT.gInterpreter.Declare(root_function_DoubleSidedCB) +#ROOT.gStyle.SetOptFit(0000); +ROOT.gROOT.SetBatch(True); +ROOT.gROOT.SetStyle("Plain"); +msgservice = ROOT.RooMsgService.instance() +msgservice.setGlobalKillBelow(RooFit.FATAL) +import numpy as np +import csv +import os.path +import atexit + +nbin_data = 50 + +def residuals(xframe, var,name): + hresid = xframe.residHist() + xframe2 = var.frame() + xframe2.addPlotable(hresid,"P") + c2=canvas_create(xframe2,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',False) + c2.SaveAs(name+'_residual.pdf') + hpull = xframe.pullHist() + xframe3 = var.frame() + xframe3.addPlotable(hpull,"P") + c3=canvas_create(xframe3,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',False) + c3.SaveAs(name+'_pull.pdf') + + + +def define_workspace_bmass_data(wspace_name,mB_branch,tree,Bmass_min=4.7): + wspace = ROOT.RooWorkspace(wspace_name) + fitvars = ROOT.RooArgSet() + bMass = ROOT.RooRealVar(mB_branch, "m(K^{+}e^{+}e^{-})", Bmass_min, 5.7, "GeV") + fitvars.add(bMass) + dataset = ROOT.RooDataSet('data','data',tree, ROOT.RooArgSet(fitvars)) + theBMassfunc = ROOT.RooFormulaVar("x", "x", "@0", ROOT.RooArgList(bMass) ) + theBMass = dataset.addColumn(theBMassfunc) ; + theBMass.setRange(Bmass_min,5.7); + fitvars.add(theBMass) + getattr(wspace, "import")(dataset, RooFit.Rename('data')) + # When a RooWorkspace is set as an attribute of a class, it can trigger a memory error + # This is solved in the latest ROOT version > 6.14.08 + atexit.register(wspace.Delete) + return wspace,dataset,bMass,theBMass + + +def get_visible_yield(obs, results, pdf, amplitude): + intgral_pdf = pdf.createIntegral(obs,obs,"window") + visible = amplitude.getVal() * intgral_pdf.getVal() + return visible + +def get_visible_yield_error(obs, results, pdf, amplitude): + intgral_pdf = pdf.createIntegral(obs,obs,"window") + intgral_pdf_err = intgral_pdf.getPropagatedError(results, obs) + visible = amplitude.getVal() * intgral_pdf.getVal() + visible_err = visible * math.sqrt(pow(amplitude.getError()/amplitude.getVal(), 2) + pow(intgral_pdf_err/intgral_pdf.getVal(), 2)) if amplitude.getVal() != 0.0 else 0.0 + return visible, visible_err + + + +##################### signal fit == Double sided CB ###################### +def signal_fit(tree, outputfile, branches, SavePlot=True): + print "Signal" + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_signal",branches[0],tree) + # signal + wspace.factory('mean[5.2873e+00, 5.25e+00, 5.3e+00]') + wspace.factory('width[5.0642e-02, 1.0e-6, 5.0e-1]') + wspace.factory('alpha1[8.1430e-01, 0.0, 10.0]') + wspace.factory('n1[9.8615e+01, 0.0, 100.0]') + wspace.factory('CBShape::sigcb(x,mean,width,alpha1,n1)') + wspace.factory('mean2[5.2274e+00, 5.0e+00, 5.30e+00]') + wspace.factory('width2[9.3738e-02, 1.0e-6, 5.0e-1]') + wspace.factory('RooGaussian::sigg(x,mean2,width2)') + wspace.factory('frac[4.4875e-01, 0, 1.0]') + wspace.factory('SUM::sig(sigcb,frac*sigg)') + + sgnframe=theBMass.frame() + wspace.factory('nsig[1000,0,100000000]') + wspace.factory('RooExtendPdf::esig(sig,nsig)') + sig=wspace.pdf('sig') + nsig=wspace.var('nsig') + esig=wspace.pdf('esig') + results = esig.fitTo(dataset,RooFit.Extended(True),RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1)) + + results.Print() + dataset.plotOn(sgnframe,RooFit.Binning(nbin_data), RooFit.Name("datas")) + esig.plotOn(sgnframe, RooFit.Normalization(1.0, ROOT.RooAbsReal.RelativeExpected), RooFit.LineColor(ROOT.kBlue), RooFit.LineWidth(2) ) + n_param = results.floatParsFinal().getSize() + print "chi2",sgnframe.chiSquare(n_param),"ndof",n_param + print "edm",results.edm(),"log",results.minNll() + + #c1=canvas_create(sgnframe,4.7,5.7,nbin_data,'m (e^{+}e^{-}K) [GeV] ') + c1, top, bottom =canvas_create_pull(sgnframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',theBMass) + top.cd() + + CMS_lumi() + if SavePlot: + c1.SaveAs('sgn_eek_'+outputfile+'.pdf') + residuals(sgnframe,theBMass,'sgn_eek_'+outputfile) + params=esig.getParameters(ROOT.RooArgSet(bMass)) + #return {"mean":1} + return {"mean":params.getRealValue('mean'),"width": params.getRealValue('width'),"alpha1":params.getRealValue('alpha1'),"n1":params.getRealValue('n1'),"frac":params.getRealValue('frac'),"gauss_mean":params.getRealValue('mean2'),"gauss_width":params.getRealValue('width2')} + +############################ BKG fit ################################# + +############################### other B fit==Expo ############################## +def otherB_fit(tree, outputfile, branches, SavePlot=True): + print "otherB" + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_otherB_bkg",branches[0],tree) + wspace.factory('exp_alpha_otherb[-6.7, -100.0, -1.e-4]') + exp_alpha_otherb = wspace.var('exp_alpha_otherb') + wspace.factory('Exponential::exp_otherb(x,exp_alpha_otherb)') + wspace.factory('notherB[1000,0,10e+6]') + wspace.factory('RooExtendPdf::eexp_otherb(exp_otherb,notherB)') + notherB=wspace.var('notherB') + eexp_otherb=wspace.pdf('eexp_otherb') + results = eexp_otherb.fitTo(dataset,RooFit.Extended(True),RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1)) + results.Print() + otherb_frame=theBMass.frame() + dataset.plotOn(otherb_frame,RooFit.Binning(nbin_data), RooFit.Name("datas")) + eexp_otherb.plotOn(otherb_frame,RooFit.Name("eexpOB"),RooFit.LineColor(30),RooFit.Normalization(1.0, ROOT.RooAbsReal.RelativeExpected),RooFit.LineWidth(3)) + #c1=canvas_create(otherb_frame,4.7,5.7,nbin_data,'m (e^{+}e^{-}K) [GeV] ') + c1, top, bottom =canvas_create_pull(otherb_frame,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',theBMass) + top.cd() + + CMS_lumi() + if SavePlot: + c1.SaveAs('bkg_otherB_'+outputfile+'.pdf') + residuals(otherb_frame,theBMass,'bkg_otherB_'+outputfile) + params=eexp_otherb.getParameters(ROOT.RooArgSet(bMass)) + n_param = results.floatParsFinal().getSize() + print "chi2",otherb_frame.chiSquare(n_param),"ndof",n_param + print "edm",results.edm(),"log",results.minNll() + + return {"exp_alpha_otherb":params.getRealValue('exp_alpha_otherb')} + +############################ KDE fit ####################### +def kde_fit(tree, outputfile, branches, pdfname, SavePlot=True, par=1.5, Bmass_min=4.7): + print "KDE - {}".format(pdfname) + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_kde",branches[0],tree, Bmass_min=Bmass_min) + kde_frame=theBMass.frame() + #wspace.factory('KeysPdf::{0}(x,data,MirrorLeft,2.0)'.format(pdfname)) + wspace.factory('KeysPdf::{0}(x,data,MirrorLeft,{1})'.format(pdfname, par)) + 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,Bmass_min,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 + + +############################ Combinatorial fit =Expo ########################### +def bkg_fit(tree, outputfile, branches, SavePlot=True): + print "combinatorial" + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_comb_bkg",branches[0],tree) + wspace.factory('exp_alpha_comb[-1.5, -100.0, -1.e-4]') + wspace.factory('Exponential::exp_comb(x,exp_alpha_comb)') + wspace.factory('ncomb[1000,0,10e+6]') + wspace.factory('RooExtendPdf::eexp_comb(exp_comb,ncomb)') + ncomb=wspace.var('ncomb') + eexp_comb=wspace.pdf('eexp_comb') + + results = eexp_comb.fitTo(dataset,RooFit.Extended(True),RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1) ) + results.Print() + combframe=theBMass.frame() + dataset.plotOn(combframe,RooFit.Binning(nbin_data), RooFit.Name("datas")) + eexp_comb.plotOn(combframe,RooFit.Name("eexp_comb"), RooFit.LineColor(49),RooFit.Normalization(1.0, ROOT.RooAbsReal.RelativeExpected),RooFit.LineWidth(3)) + params=eexp_comb.getParameters(ROOT.RooArgSet(bMass)) + #c1=canvas_create(combframe,4.7,5.7,nbin_data,'m (e^{+}e^{-}K) [GeV]') + c1, top, bottom =canvas_create_pull(combframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',theBMass) + top.cd() + + CMS_lumi() + if SavePlot: + c1.SaveAs('bkg_comb_'+outputfile+'.pdf') + n_param = results.floatParsFinal().getSize() + print "chi2",combframe.chiSquare(n_param),"ndof",n_param + print "edm",results.edm(),"log",results.minNll() + if SavePlot: + residuals(combframe,theBMass,'bkg_comb_'+outputfile) + + return {"exp_alpha_comb":params.getRealValue('exp_alpha_comb')} + + + +############################# total fit ############################## +def total_fit(tree, outputfile, branches, signal_parameters=None, otherB_pdf=None, KstarJpsi_pdf=None, KstarPlusJpsi_pdf=None, comb_parameters=None,Significance_range=None, partial_ratio=None, partial_ratio_kstarplus=None, mvacut="",log='log.csv'): + + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_total",branches[0],tree) + print "Total" + #amplitudes + wspace.factory('nsignal[10000.0, 0.0, 1000000.0]' ) + wspace.factory('ncomb[500.0, 0.0, 1000000.0]') + wspace.factory('notherB[1000.0, 0.0, 1000000.0]') + wspace.factory('frac_partial[0.35, 0.0, 10.0]') + wspace.factory('prod::nKstarJpsi(frac_partial,nsignal)') + wspace.factory('frac_kstarplus[0.1, 0.0, 10.0]') + #wspace.factory('prod::nKstarPlusJpsi(frac_kstarplus,nsignal)') + wspace.factory('prod::nKstarPlusJpsi(frac_kstarplus,nKstarJpsi)') + + #wspace.factory('nKstarJpsi[10000.0, 0.0, 1000000.0]') + + # signal + wspace.factory('mean[5.278e+00, 5.22e+00, 5.5e+00]') + wspace.factory('width[5.8851e-02, 1.0e-6, 5.0e-1]') + wspace.factory('alpha1[1.85, 0.0, 10.0]') + wspace.factory('n1[19.9999, 0.0, 2000.0]') + wspace.factory('CBShape::cb_signal(x,mean,width,alpha1,n1)') + wspace.factory('gauss_mean[5.19e+00, 5.0e+00, 5.30e+00]') + wspace.factory('gauss_width[1.3367e-01, 1.0e-6, 5.0e-1]') + wspace.factory('RooGaussian::g_signal(x,gauss_mean,gauss_width)') + wspace.factory('frac[0.5, 0, 1.0]') + wspace.factory('SUM::signal(cb_signal,frac*g_signal)') + + # other B - bkg + getattr(wspace, "import")(otherB_pdf, RooFit.Rename('otherb')) + + # K*Jpsi - bkg + getattr(wspace, "import")(KstarJpsi_pdf, RooFit.Rename('kstarjpsi')) + + # K*+Jpsi - bkg + getattr(wspace, "import")(KstarPlusJpsi_pdf, RooFit.Rename('kstarplusjpsi')) + + # combinatorial - bkg + wspace.factory('exp_alpha_comb[-1.0, -10.0, -1.e-4]') + wspace.factory('Exponential::exp_comb(x,exp_alpha_comb)') + + #sum + wspace.factory('SUM::model(nsignal*signal,ncomb*exp_comb,nKstarJpsi*kstarjpsi,nKstarPlusJpsi*kstarplusjpsi,notherB*otherb)') + + model = wspace.pdf('model'); + signal = wspace.pdf('signal'); exp_comb = wspace.pdf('exp_comb') + otherb = wspace.pdf('otherb') + kstarjpsi = wspace.pdf('kstarjpsi') + kstarplusjpsi = wspace.pdf('kstarplusjpsi') + nsignal = wspace.var('nsignal'); ncomb = wspace.var('ncomb') + nKstarJpsi = wspace.obj('nKstarJpsi') + nKstarPlusJpsi = wspace.obj('nKstarPlusJpsi') + notherB = wspace.var('notherB') + frac_partial = wspace.var('frac_partial') + frac_kstarplus = wspace.var('frac_kstarplus') + + for par in signal_parameters.keys(): + (wspace.var(par)).setVal(signal_parameters[par]) + if par not in ['mean', 'gauss_mean']: + (wspace.var(par)).setConstant(True) + for par in comb_parameters.keys(): + (wspace.var(par)).setVal(comb_parameters[par]) + (wspace.var(par)).setConstant(True) + + if partial_ratio is not None: + wspace.var('frac_partial').setVal(partial_ratio) + #wspace.var('frac_partial').setConstant(True) + + if partial_ratio_kstarplus is not None: + wspace.var('frac_kstarplus').setVal(partial_ratio_kstarplus) + wspace.var('frac_kstarplus').setConstant(True) + + results = model.fitTo(dataset, RooFit.Extended(True), RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1)) + print results.Print() + xframe=theBMass.frame(RooFit.Title("")) + + norm=1. + dataset.plotOn(xframe,RooFit.Binning(nbin_data), RooFit.Name("datas")) + + model.plotOn(xframe,RooFit.Name("exp_comb"),RooFit.Components("exp_comb"),RooFit.Range("Full"),RooFit.DrawOption("L"),RooFit.VLines(),RooFit.FillColor(49),RooFit.LineColor(49),RooFit.LineStyle(2),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineWidth(3)) + model.plotOn(xframe,RooFit.Name("otherb"),RooFit.Components("otherb"),RooFit.Range("Full"),RooFit.FillColor(30),RooFit.LineColor(30),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineStyle(2), RooFit.LineWidth(3),RooFit.DrawOption("L"),RooFit.MoveToBack()) + model.plotOn(xframe,RooFit.Name("kstarjpsi"),RooFit.Components("kstarjpsi"),RooFit.Range("Full"),RooFit.FillColor(30),RooFit.LineColor(12),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineStyle(2), RooFit.LineWidth(3),RooFit.DrawOption("L"),RooFit.MoveToBack()) + model.plotOn(xframe,RooFit.Name("kstarplusjpsi"),RooFit.Components("kstarplusjpsi"),RooFit.Range("Full"),RooFit.FillColor(30),RooFit.LineColor(46),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineStyle(2), RooFit.LineWidth(3),RooFit.DrawOption("L"),RooFit.MoveToBack()) + model.plotOn(xframe,RooFit.Name("signal"),RooFit.Components("signal"),RooFit.Range("Full"),RooFit.DrawOption("L"),RooFit.LineStyle(2),RooFit.LineColor(ROOT.kBlue),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected), RooFit.LineWidth(3)) + model.plotOn(xframe, RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineColor(ROOT.kRed) ) + # c1=canvas_create(xframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]') + # c1.SaveAs('total_fit_'+outputfile+'.pdf') + wspace.defineSet('obs', 'x') + obs = wspace.set('obs') + + params=model.getParameters(ROOT.RooArgSet(bMass)) + if Significance_range==None: + Significance_range={"min":params["mean"]-2*params["width"],"max":params["mean"]+2*params["width"]} + theBMass.setRange("window",Significance_range["min"],Significance_range["max"]) + + #theBMass.setRange("window",5.0,5.4) + obs2= ROOT.RooRealVar("obs2","obs2",Significance_range["min"],Significance_range["max"]) + nset = ROOT.RooArgSet(obs2) + print nsignal.getVal(), nsignal.getVal(nset) + print Significance_range + ncomb_visible, ncomb_visible_err = get_visible_yield_error(obs, results, exp_comb, ncomb) + nsig_visible, nsig_visible_err = get_visible_yield_error(obs, results, signal, nsignal) + nKstarJpsi_visible = get_visible_yield(obs, results, kstarjpsi , nKstarJpsi) + nKstarJpsi_visible_err = 0.0 + nKstarPlusJpsi_visible = get_visible_yield(obs, results, kstarplusjpsi , nKstarPlusJpsi) + nKstarPlusJpsi_visible_err = 0.0 + notherB_visible, notherB_visible_err = get_visible_yield_error(obs, results, otherb , notherB) + #notherB_visible = get_visible_yield(obs, results, otherb , notherB) + #notherB_visible_err = 0.0 + nbkg_visible = nKstarJpsi_visible+nKstarPlusJpsi_visible+ncomb_visible+notherB_visible + +# c1=canvas_create(xframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]') + n_param = results.floatParsFinal().getSize() + print "chi2",xframe.chiSquare(n_param),"ndof",n_param + print "edm",results.edm(),"log",results.minNll() + + + #c1=canvas_create(xframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]') + c1, top, bottom =canvas_create_pull(xframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',theBMass) + top.cd() + legend = ROOT.TLegend(0.65,0.65,0.92,0.85) + legend.AddEntry(xframe.findObject("exp_comb"),"Combinatorial","l"); + legend.AddEntry(xframe.findObject("kstarjpsi"),"B -> J/#psiK*","l"); + legend.AddEntry(xframe.findObject("kstarplusjpsi"),"B -> J/#psiK*+","l"); + legend.AddEntry(xframe.findObject("otherb"),"Other B","l"); + legend.AddEntry(xframe.findObject("signal"),"B -> J/#psiK","l"); + legend.SetLineColor(ROOT.kWhite) + legend.SetTextFont(42); + legend.SetTextSize(0.04); + legend.AddEntry(xframe.findObject("datas"),"Data","lpe"); + legend.Draw(); + pt=pt_create(mvacut,nsig_visible,nsig_visible_err,nbkg_visible) + pt.Draw() + CMS_lumi() + c1.cd() + c1.Update() + + c1.SaveAs('total_fit_'+outputfile+'.pdf') + print "signal",nsig_visible,"+/-", nsig_visible_err,"comb",ncomb_visible,"+/-", ncomb_visible_err,"K* J/psi", nKstarJpsi_visible, "+/-", nKstarJpsi_visible_err, "K*+ J/psi", nKstarPlusJpsi_visible, "+/-", nKstarPlusJpsi_visible_err, "otherB", notherB_visible, "+/-",notherB_visible_err + + residuals(xframe,theBMass,outputfile+"_poutana") + + saveWS = True + + if saveWS: + # get likelihood + ''' + nll = model.createNLL(dataset) + ROOT.RooMinuit(nll).migrad() + nll_frame = nsignal.frame(RooFit.Bins(30),RooFit.Range(7500.0,10000.0),RooFit.Title("LL and profileLL in nsignal")) ; + #nll.plotOn(nll_frame,RooFit.ShiftToZero()) + pll = nll.createProfile(ROOT.RooArgSet(nsignal)) + pll.plotOn(nll_frame,RooFit.LineColor(2),RooFit.ShiftToZero()) + nll_frame.SetMinimum(0); + nll_frame.SetMaximum(10) + c2 = canvas_create(nll_frame,0.0,0.0,0.0,'nsig') + CMS_lumi() + c2.cd() + c2.Update() + c2.SaveAs('nll_'+outputfile+'.pdf') + ''' + + wspace_output = ROOT.RooWorkspace('wspace') + getattr(wspace_output, "import")(model) + getattr(wspace_output, "import")(dataset) + params = model.getParameters(dataset) + wspace_output.saveSnapshot("nominal_values",params) + wspace_output.Print("V") + wspace_output.writeToFile('wspace_'+outputfile+'.root') + + + + csv_header = ['cut', 'nsig_total', 'nsig_total_unc', 'nKstarJpsi_total', 'nKstarJpsi_total_unc', 'nKstarPlusJpsi_total', 'nKstarPlusJpsi_total_unc', 'nsig', 'nbkg', 'ncomb', 'nKstarJpsi', 'nKstarPlusJpsi', 'notherB', 'snr', 'chi2'] + df = {} + df['cut'] = mvacut + df['nsig_total'] = nsignal.getVal() + df['nsig_total_unc'] = nsignal.getError() + df['nKstarJpsi_total'] = nKstarJpsi.getVal() + df['nKstarJpsi_total_unc'] = nKstarJpsi.getPropagatedError(results) + df['nKstarPlusJpsi_total'] = nKstarPlusJpsi.getVal() + df['nKstarPlusJpsi_total_unc'] = nKstarPlusJpsi.getPropagatedError(results) + df['nsig'] = nsig_visible + df['nbkg'] = nbkg_visible + df['ncomb'] = ncomb_visible + df['nKstarJpsi'] = nKstarJpsi_visible + df['nKstarPlusJpsi'] = nKstarPlusJpsi_visible + df['notherB'] = notherB_visible + df['snr'] = nsig_visible / np.sqrt(nsig_visible + nbkg_visible) + df['chi2'] = xframe.chiSquare(n_param) + csv_outputfile = log + file_exists = os.path.isfile(csv_outputfile) + with open (csv_outputfile, 'a+') as filedata: + writer = csv.DictWriter(filedata, delimiter=',', fieldnames=csv_header) + if not file_exists: + writer.writeheader() + writer.writerow(df) + + return (nsig_visible, ncomb_visible, nKstarJpsi_visible, notherB_visible, nsignal.getVal() ) + + + +#################################### main ################################ +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser(description='Unbinned likelihood fit') + parser.add_argument("-i", "--inputfile", dest="inputfile", default="../BDT/TrainingCore/forMeas_xgbmodel_kee_v5.1_12B_Mu9_*_data.root", help="Input data file") + parser.add_argument("-o", "--outputfile", dest="outputfile", default="test", help="Output name") + parser.add_argument("--mvacut", dest="mva",default=6.2,type=float) + parser.add_argument("--isgn", "--isgnfile", dest="isgnfile", default="mc_files/reg/BParkingNANO_2021Mar05_BuToKJpsi_Toee_v2_BToKEEAnalyzer_2021Mar12_HLTMu9IP6_mc_tighterPreselectionWODmass_mva_pf.root", help="Input signal file") + parser.add_argument("--ibkg", dest="ibkg", default="../BDT/TrainingCore/forMeas_xgbmodel_kee_v5.1_12B_Mu9_*_samesign.root", help="Input combinatorial BKG file") + parser.add_argument("--iotherB", dest="iotherB_BKG", default="OtherB_BKGtree_KJpsiEE.root", help="Input combinatorial BKG file") + parser.add_argument("--iKstarJpsi_BKG", dest="iKstarJpsi_BKG", default="mc_files/reg/BParkingNANO_2021Mar05_BdToKstarJpsi_Toee_v2_BToKEEAnalyzer_2021Mar12_HLTMu9IP6_mc_tighterPreselectionWODmass_kaon_mva_pf.root", help="Input combinatorial BKG file") + parser.add_argument("--iKstarPlusJpsi_BKG", dest="iKstarPlusJpsi_BKG", default="mc_files/reg/BParkingNANO_2021Mar05_BdToKstarJpsi_Toee_v2_BToKEEAnalyzer_2021Mar12_HLTMu9IP6_mc_tighterPreselectionWODmass_kaon_mva_pf.root", help="Input combinatorial BKG file") + parser.add_argument("--fit_primitive", dest="fit_primtv", default=False, action='store_true', help="primitive fits for fixing params or use defaults") + parser.add_argument("--skip_realfit", dest="skip_realfit", default=False, action='store_true', help="does not perform the final fit. useful for defining parameters, tests on pdfs") + parser.add_argument("--sel_primitive", dest="sel_primtv", default=None, help="runs only the selected primitive fits. Options: sgn bkg_comb bkg_otherb bkg_kstar_kee bkg_kstar_piee. they can be combined with ',' in strings. No spaces") + parser.add_argument("--minx", dest="minx", default=-1.0,type=float, help="minx for integral") + parser.add_argument("--maxx", dest="maxx", default=-1.0,type=float, help="maxx for integral") + parser.add_argument("--log", dest="log", default="log.csv", help="log of the fitting results") + parser.add_argument("--partial_ratio", dest="partial_ratio", default=None, type=float, help="fixing the partially reco. yield") + parser.add_argument("--partial_ratio_kstarplus", dest="partial_ratio_kstarplus", default=None, type=float, help="fixing the partially reco. yield") + args = parser.parse_args() + + branches=["Bmass","Mll","xgb","KLmassD0","Mu9_IP6"] + cuts = branches[2]+">"+str(args.mva)+" && 2.9<"+branches[1]+" && "+branches[1]+"<3.2" + " && " + branches[3] + ">2.0" #+ " && " + branches[4] + cuts_otherb = branches[2]+">"+str(args.mva)+" && 2.9<"+branches[1]+" && "+branches[1]+"<3.2" + " && " + branches[3] + ">2.0" #+ " && " + branches[0] + " < 5.2" + + if args.mva < 6.0: + cuts_samesign = branches[2]+">"+str(args.mva)+" && 2.9<"+branches[1]+" && "+branches[1]+"<3.2" + else: + cuts_samesign = branches[2]+"> 6.0 "+" && 2.9<"+branches[1]+" && "+branches[1]+"<3.2" + #cuts = branches[2]+">"+str(args.mva)+" && 2.9<"+branches[1]+" && "+branches[1]+"<3.25" + #cuts = branches[2]+">"+str(args.mva)+" && 2.8<"+branches[1]+" && "+branches[1]+"<3.25" + " && " + branches[3] + ">2.0" + + args.outputfile+="_wp"+str(args.mva) + + comb_parameters={'exp_alpha_comb':-1.50615} + + print "start" + if args.fit_primtv: + if args.sel_primtv!= None: + args.sel_primtv = args.sel_primtv.split(",") + else: + args.sel_primtv = ["sgn","bkg_comb","bkg_otherb","bkg_kstarjpsi","bkg_kstarplusjpsi"] + print "primitive params" + if "sgn" in args.sel_primtv: + tree_sgn = ROOT.TChain('mytreefit') + tree_sgn.Add(args.isgnfile) + tree_sgn_cut=tree_sgn.CopyTree(cuts) + print tree_sgn_cut.GetEntries() + signal_parameters = signal_fit(tree_sgn_cut, args.outputfile+"_sgnMC", branches) + print "parameters SGN", signal_parameters['mean'], signal_parameters['width'],signal_parameters['alpha1'],signal_parameters['n1'],signal_parameters['frac'],signal_parameters['gauss_mean'],signal_parameters['gauss_width'] + + if "bkg_otherb" in args.sel_primtv: + tree_otherB = ROOT.TChain('mytreefit') + tree_otherB.Add(args.iotherB_BKG) + tree_otherB_cut=tree_otherB.CopyTree(cuts_otherb) + otherB_pdf = kde_fit(tree_otherB_cut, args.outputfile+"_otherBMC", branches, 'otherb', par=2.0, Bmass_min=4.5) + print "finished kde fit for other B" + + if "bkg_comb" in args.sel_primtv: + tree_bkg = ROOT.TChain('mytreefit') + tree_bkg.Add(args.ibkg) + tree_bkg_cut=tree_bkg.CopyTree(cuts_samesign) + comb_parameters = bkg_fit(tree_bkg_cut, args.outputfile+"_SameSign", branches) + print "parameters Combinatorial BKG", comb_parameters['exp_alpha_comb'] + + if "bkg_kstarjpsi" in args.sel_primtv: + tree_KstarJpsi = ROOT.TChain('mytreefit') + tree_KstarJpsi.Add(args.iKstarJpsi_BKG) + tree_KstarJpsi_cut=tree_KstarJpsi.CopyTree(cuts) + KstarJpsi_pdf = kde_fit(tree_KstarJpsi_cut, args.outputfile+"_KstarJpsiMC", branches, 'kstarjpsi') + print "finished kde fit for K* J/psi" + + if "bkg_kstarplusjpsi" in args.sel_primtv: + tree_KstarPlusJpsi = ROOT.TChain('mytreefit') + tree_KstarPlusJpsi.Add(args.iKstarPlusJpsi_BKG) + tree_KstarPlusJpsi_cut=tree_KstarPlusJpsi.CopyTree(cuts) + KstarPlusJpsi_pdf = kde_fit(tree_KstarPlusJpsi_cut, args.outputfile+"_KstarPlusJpsiMC", branches, 'kstarplusjpsi', par=2.0) + print "finished kde fit for K*+ J/psi" + + else: + print "Need to provide MC template" + + if not args.skip_realfit: + tree = ROOT.TChain('mytreefit') + tree.Add(args.inputfile) + tree_cut=tree.CopyTree(cuts) + if args.minx==-1: args.minx=signal_parameters["mean"]-2*signal_parameters["width"] + if args.maxx==-1: args.maxx=signal_parameters["mean"]+2*signal_parameters["width"] + + #nsig, nbkg, nKstarJpsi, notherB, nsig_total =total_fit(tree_cut, args.outputfile, branches, signal_parameters, otherB_parameters, KstarJpsi_pdf,comb_parameters, {"min":args.minx,"max":args.maxx}, args.partial_ratio, str(args.mva), args.log) + nsig, nbkg, nKstarJpsi, notherB, nsig_total =total_fit(tree_cut, args.outputfile, branches, signal_parameters, otherB_pdf, KstarJpsi_pdf, KstarPlusJpsi_pdf, comb_parameters, {"min":args.minx,"max":args.maxx}, args.partial_ratio, args.partial_ratio_kstarplus, str(args.mva), args.log) + + print "sig",nsig,"comb", nbkg,"K* J/psi", nKstarJpsi,"otherB", notherB,"all sig", nsig_total + # combinatorial BKG parameters set but not fixed. +# print "sigma",float(nsig)/math.sqrt(nsig+nkjpsi+nbkg),"nsig",float(nsig),"nbkg",float(nbkg),"Kjpsi leak",float(nkjpsi) + + + diff --git a/fit/KPsi2S_roofit_plb_modified_kde_fixedPartial.py b/fit/KPsi2S_roofit_plb_modified_kde_fixedPartial.py new file mode 100644 index 0000000..a36daa8 --- /dev/null +++ b/fit/KPsi2S_roofit_plb_modified_kde_fixedPartial.py @@ -0,0 +1,547 @@ +import ROOT +from ROOT import RooFit +import math +from roofit_helper import * +#ROOT.gROOT.ProcessLine(open('roofit_models.h').read()) +#from ROOT import DoubleSidedCB +#from ROOT import ROOT_DoubleSidedCB +from roofit_models import root_function_DoubleSidedCB +ROOT.gInterpreter.Declare(root_function_DoubleSidedCB) +#ROOT.gStyle.SetOptFit(0000); +ROOT.gROOT.SetBatch(True); +ROOT.gROOT.SetStyle("Plain"); +msgservice = ROOT.RooMsgService.instance() +msgservice.setGlobalKillBelow(RooFit.FATAL) +import numpy as np +import csv +import os.path +import atexit + +nbin_data = 50 + +def residuals(xframe, var,name): + hresid = xframe.residHist() + xframe2 = var.frame() + xframe2.addPlotable(hresid,"P") + c2=canvas_create(xframe2,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',False) + c2.SaveAs(name+'_residual.pdf') + hpull = xframe.pullHist() + xframe3 = var.frame() + xframe3.addPlotable(hpull,"P") + c3=canvas_create(xframe3,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',False) + c3.SaveAs(name+'_pull.pdf') + +def define_workspace_bmass_data(wspace_name,mB_branch,tree,Bmass_min=4.7): + wspace = ROOT.RooWorkspace(wspace_name) + fitvars = ROOT.RooArgSet() + bMass = ROOT.RooRealVar(mB_branch, "m(K^{+}e^{+}e^{-})", Bmass_min, 5.7, "GeV") + fitvars.add(bMass) + dataset = ROOT.RooDataSet('data','data',tree, ROOT.RooArgSet(fitvars)) + theBMassfunc = ROOT.RooFormulaVar("x", "x", "@0", ROOT.RooArgList(bMass) ) + theBMass = dataset.addColumn(theBMassfunc) ; + theBMass.setRange(Bmass_min,5.7); + fitvars.add(theBMass) + getattr(wspace, "import")(dataset, RooFit.Rename('data')) + # When a RooWorkspace is set as an attribute of a class, it can trigger a memory error + # This is solved in the latest ROOT version > 6.14.08 + atexit.register(wspace.Delete) + return wspace,dataset,bMass,theBMass + +def get_visible_yield(obs, results, pdf, amplitude): + intgral_pdf = pdf.createIntegral(obs,obs,"window") + visible = amplitude.getVal() * intgral_pdf.getVal() + return visible + +def get_visible_yield_error(obs, results, pdf, amplitude): + intgral_pdf = pdf.createIntegral(obs,obs,"window") + intgral_pdf_err = intgral_pdf.getPropagatedError(results, obs) + visible = amplitude.getVal() * intgral_pdf.getVal() + visible_err = visible * math.sqrt(pow(amplitude.getError()/amplitude.getVal(), 2) + pow(intgral_pdf_err/intgral_pdf.getVal(), 2)) if (amplitude.getVal() != 0.0 and intgral_pdf.getVal() != 0) else 0.0 + return visible, visible_err + + + +##################### signal fit == Double sided CB ###################### +def signal_fit(tree, outputfile, branches, SavePlot=True): + print "Signal" + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_signal",branches[0],tree) + # signal + wspace.factory('mean[5.2873e+00, 5.25e+00, 5.3e+00]') + wspace.factory('width[5.0642e-02, 1.0e-6, 5.0e-1]') + wspace.factory('alpha1[8.1430e-01, 0.0, 10.0]') + wspace.factory('n1[9.8615e+01, 0.0, 100.0]') + wspace.factory('CBShape::sigcb(x,mean,width,alpha1,n1)') + wspace.factory('mean2[5.2274e+00, 5.0e+00, 5.30e+00]') + wspace.factory('width2[9.3738e-02, 1.0e-6, 5.0e-1]') + wspace.factory('RooGaussian::sigg(x,mean2,width2)') + wspace.factory('frac[4.4875e-01, 0, 1.0]') + wspace.factory('SUM::sig(sigcb,frac*sigg)') + + sgnframe=theBMass.frame() + wspace.factory('nsig[1000,0,100000000]') + wspace.factory('RooExtendPdf::esig(sig,nsig)') + sig=wspace.pdf('sig') + nsig=wspace.var('nsig') + esig=wspace.pdf('esig') + results = esig.fitTo(dataset,RooFit.Extended(True),RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1)) + + results.Print() + dataset.plotOn(sgnframe,RooFit.Binning(nbin_data), RooFit.Name("datas")) + esig.plotOn(sgnframe, RooFit.Normalization(1.0, ROOT.RooAbsReal.RelativeExpected), RooFit.LineColor(ROOT.kBlue), RooFit.LineWidth(2) ) + n_param = results.floatParsFinal().getSize() + print "chi2",sgnframe.chiSquare(n_param),"ndof",n_param + print "edm",results.edm(),"log",results.minNll() + + #c1=canvas_create(sgnframe,4.7,5.7,nbin_data,'m (e^{+}e^{-}K) [GeV] ') + c1, top, bottom =canvas_create_pull(sgnframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',theBMass) + top.cd() + + CMS_lumi() + if SavePlot: + c1.SaveAs('sgn_eek_'+outputfile+'.pdf') + residuals(sgnframe,theBMass,'sgn_eek_'+outputfile) + params=esig.getParameters(ROOT.RooArgSet(bMass)) + #return {"mean":1} + return {"mean":params.getRealValue('mean'),"width": params.getRealValue('width'),"alpha1":params.getRealValue('alpha1'),"n1":params.getRealValue('n1'),"frac":params.getRealValue('frac'),"gauss_mean":params.getRealValue('mean2'),"gauss_width":params.getRealValue('width2')} + +############################ BKG fit ################################# + +############################### other B fit==Expo ############################## +def otherB_fit(tree, outputfile, branches, SavePlot=True): + print "otherB" + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_otherB_bkg",branches[0],tree) + #wspace.factory('exp_alpha_otherb[-15.7, -100.0, -1.e-4]') + wspace.factory('exp_alpha_otherb[-15.7, -100.0, -5.0]') + exp_alpha_otherb = wspace.var('exp_alpha_otherb') + wspace.factory('Exponential::exp_otherb(x,exp_alpha_otherb)') + wspace.factory('notherB[1000,0,10e+6]') + wspace.factory('RooExtendPdf::eexp_otherb(exp_otherb,notherB)') + notherB=wspace.var('notherB') + eexp_otherb=wspace.pdf('eexp_otherb') + results = eexp_otherb.fitTo(dataset,RooFit.Extended(True),RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1)) + results.Print() + otherb_frame=theBMass.frame() + dataset.plotOn(otherb_frame,RooFit.Binning(nbin_data), RooFit.Name("datas")) + eexp_otherb.plotOn(otherb_frame,RooFit.Name("eexpOB"),RooFit.LineColor(30),RooFit.Normalization(1.0, ROOT.RooAbsReal.RelativeExpected),RooFit.LineWidth(3)) + #c1=canvas_create(otherb_frame,4.7,5.7,nbin_data,'m (e^{+}e^{-}K) [GeV] ') + c1, top, bottom =canvas_create_pull(otherb_frame,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',theBMass) + top.cd() + + CMS_lumi() + if SavePlot: + c1.SaveAs('bkg_otherB_'+outputfile+'.pdf') + residuals(otherb_frame,theBMass,'bkg_otherB_'+outputfile) + params=eexp_otherb.getParameters(ROOT.RooArgSet(bMass)) + n_param = results.floatParsFinal().getSize() + print "chi2",otherb_frame.chiSquare(n_param),"ndof",n_param + print "edm",results.edm(),"log",results.minNll() + + return {"exp_alpha_otherb":params.getRealValue('exp_alpha_otherb')} + + +############################ KDE fit ####################### +def kde_fit(tree, outputfile, branches, pdfname, SavePlot=True, par=1.5, Bmass_min=4.7): + print "KDE - {}".format(pdfname) + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_kde",branches[0],tree, Bmass_min=Bmass_min) + kde_frame=theBMass.frame() + #wspace.factory('KeysPdf::{0}(x,data,MirrorLeft,2.0)'.format(pdfname)) + wspace.factory('KeysPdf::{0}(x,data,MirrorLeft,{1})'.format(pdfname, par)) + 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,Bmass_min,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 + + +############################ Combinatorial fit =Expo ########################### +def bkg_fit(tree, outputfile, branches, SavePlot=True): + print "combinatorial" + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_comb_bkg",branches[0],tree) + wspace.factory('exp_alpha_comb[-1.5, -100.0, -1.e-4]') + wspace.factory('Exponential::exp_comb(x,exp_alpha_comb)') + wspace.factory('ncomb[1000,0,10e+6]') + wspace.factory('RooExtendPdf::eexp_comb(exp_comb,ncomb)') + ncomb=wspace.var('ncomb') + eexp_comb=wspace.pdf('eexp_comb') + + results = eexp_comb.fitTo(dataset,RooFit.Extended(True),RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1) ) + results.Print() + combframe=theBMass.frame() + dataset.plotOn(combframe,RooFit.Binning(nbin_data), RooFit.Name("datas")) + eexp_comb.plotOn(combframe,RooFit.Name("eexp_comb"), RooFit.LineColor(49),RooFit.Normalization(1.0, ROOT.RooAbsReal.RelativeExpected),RooFit.LineWidth(3)) + params=eexp_comb.getParameters(ROOT.RooArgSet(bMass)) + #c1=canvas_create(combframe,4.7,5.7,nbin_data,'m (e^{+}e^{-}K) [GeV]') + c1, top, bottom =canvas_create_pull(combframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',theBMass) + top.cd() + + CMS_lumi() + if SavePlot: + c1.SaveAs('bkg_comb_'+outputfile+'.pdf') + n_param = results.floatParsFinal().getSize() + print "chi2",combframe.chiSquare(n_param),"ndof",n_param + print "edm",results.edm(),"log",results.minNll() + if SavePlot: + residuals(combframe,theBMass,'bkg_comb_'+outputfile) + + return {"exp_alpha_comb":params.getRealValue('exp_alpha_comb')} + + + +############################# total fit ############################## +def total_fit(tree, outputfile, branches, signal_parameters=None, otherB_pdf=None, KstarPsi2S_pdf=None , KstarPlusPsi2S_pdf=None, KstarJpsi_pdf=None , KJpsi_pdf=None, comb_parameters=None,Significance_range=None, partial_ratio=None, partial_ratio_kstarplus=None, mvacut="",log='log.csv'): + wspace,dataset,bMass,theBMass = define_workspace_bmass_data("wspace_total",branches[0],tree) + print "Total" + #amplitudes + wspace.factory('nsignal[600.0, 0.0, 1000000.0]' ) + wspace.factory('ncomb[1000.0, 0.0, 1000000.0]') + wspace.factory('notherB[100.0, 0.0, 1000000.0]') + #wspace.factory('notherB[0.0, 0.0, 0.0]') + wspace.factory('nKstarJpsi[100.0, 0.0, 1000000.0]') + wspace.factory('nkjpsi[100.0, 0.0, 1000000.0]') + + wspace.factory('frac_partial[1.0, 0.0, 10.0]') + wspace.factory('prod::nKstarPsi2S(frac_partial,nsignal)') + + wspace.factory('frac_kstarplus[0.1, 0.0, 10.0]') + #wspace.factory('prod::nKstarPlusPsi2S(frac_kstarplus,nsignal)') + wspace.factory('prod::nKstarPlusPsi2S(frac_kstarplus,nKstarPsi2S)') + + + # signal + wspace.factory('mean[5.278e+00, 5.22e+00, 5.5e+00]') + wspace.factory('width[5.8851e-02, 1.0e-6, 5.0e-1]') + wspace.factory('alpha1[1.85, 0.0, 10.0]') + wspace.factory('n1[19.9999, 0.0, 2000.0]') + wspace.factory('CBShape::cb_signal(x,mean,width,alpha1,n1)') + wspace.factory('gauss_mean[5.19e+00, 5.0e+00, 5.30e+00]') + wspace.factory('gauss_width[1.3367e-01, 1.0e-6, 5.0e-1]') + wspace.factory('RooGaussian::g_signal(x,gauss_mean,gauss_width)') + wspace.factory('frac[0.5, 0, 1.0]') + wspace.factory('SUM::signal(cb_signal,frac*g_signal)') + + # other B - bkg + getattr(wspace, "import")(otherB_pdf, RooFit.Rename('otherb')) + + # K*Psi2S - bkg + getattr(wspace, "import")(KstarPsi2S_pdf, RooFit.Rename('kstarpsi2s')) + + # K*+Psi2S - bkg + getattr(wspace, "import")(KstarPlusPsi2S_pdf, RooFit.Rename('kstarpluspsi2s')) + + # K*Jpsi - bkg + getattr(wspace, "import")(KstarJpsi_pdf, RooFit.Rename('kstarjpsi')) + + # KJpsi - bkg + getattr(wspace, "import")(KJpsi_pdf, RooFit.Rename('kjpsi')) + + # combinatorial - bkg + wspace.factory('exp_alpha_comb[-1.0, -100.0, -1.e-4]') + wspace.factory('Exponential::exp_comb(x,exp_alpha_comb)') + + #sum + #wspace.factory('SUM::model(nsignal*signal,ncomb*exp_comb,nKstarPsi2S*kstarpsi2s,nKstarJpsi*kstarjpsi,nkjpsi*kjpsi,notherB*exp_otherb)') + #wspace.factory('SUM::model(nsignal*signal,ncomb*exp_comb,nKstarPsi2S*kstarpsi2s,nkjpsi*kjpsi,notherB*exp_otherb)') + #wspace.factory('SUM::model(nsignal*signal,ncomb*exp_comb,nKstarPsi2S*kstarpsi2s,notherB*exp_otherb)') + #wspace.factory('SUM::model(nsignal*signal,ncomb*exp_comb,nKstarPsi2S*kstarpsi2s,nKstarJpsi*kstarjpsi,notherB*exp_otherb)') + #wspace.factory('SUM::model(nsignal*signal,ncomb*exp_comb,nKstarPsi2S*kstarpsi2s,nKstarPlusPsi2S*kstarpluspsi2s,notherB*exp_otherb)') + #wspace.factory('SUM::model(nsignal*signal,ncomb*exp_comb,nKstarPsi2S*kstarpsi2s,nKstarPlusPsi2S*kstarpluspsi2s)') + wspace.factory('SUM::model(nsignal*signal,ncomb*exp_comb,nKstarPsi2S*kstarpsi2s,nKstarPlusPsi2S*kstarpluspsi2s,notherB*otherb)') + + model = wspace.pdf('model'); + signal = wspace.pdf('signal'); exp_comb = wspace.pdf('exp_comb') + otherb = wspace.pdf('otherb') + kjpsi = wspace.pdf('kjpsi') + kstarpsi2s = wspace.pdf('kstarpsi2s'); kstarjpsi = wspace.pdf('kstarjpsi') + kstarpluspsi2s = wspace.pdf('kstarpluspsi2s') + nsignal = wspace.var('nsignal'); ncomb = wspace.var('ncomb') + nKstarPsi2S = wspace.obj('nKstarPsi2S'); nKstarJpsi = wspace.var('nKstarJpsi') + nKstarPlusPsi2S = wspace.obj('nKstarPlusPsi2S') + nKJpsi = wspace.var('nkjpsi') + notherB = wspace.var('notherB') + frac_partial = wspace.var('frac_partial') + frac_kstarplus = wspace.var('frac_kstarplus') + + for par in signal_parameters.keys(): + (wspace.var(par)).setVal(signal_parameters[par]) + (wspace.var(par)).setConstant(True) + for par in comb_parameters.keys(): + (wspace.var(par)).setVal(comb_parameters[par]) + (wspace.var(par)).setConstant(True) + + if partial_ratio is not None: + wspace.var('frac_partial').setVal(partial_ratio) + #wspace.var('frac_partial').setConstant(True) + + if partial_ratio_kstarplus is not None: + wspace.var('frac_kstarplus').setVal(partial_ratio_kstarplus) + wspace.var('frac_kstarplus').setConstant(True) + + + #wspace.var('nKstarJpsi').setVal(267) + #wspace.var('nKstarJpsi').setConstant(True) + + results = model.fitTo(dataset, RooFit.Extended(True), RooFit.Save(), RooFit.Range(4.7,5.7), RooFit.PrintLevel(-1)) + print results.Print() + xframe=theBMass.frame(RooFit.Title("")) + + norm=1. + dataset.plotOn(xframe,RooFit.Binning(nbin_data), RooFit.Name("datas")) + + model.plotOn(xframe,RooFit.Name("exp_comb"),RooFit.Components("exp_comb"),RooFit.Range("Full"),RooFit.DrawOption("L"),RooFit.VLines(),RooFit.FillColor(49),RooFit.LineColor(49),RooFit.LineStyle(2),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineWidth(3)) + model.plotOn(xframe,RooFit.Name("otherb"),RooFit.Components("otherb"),RooFit.Range("Full"),RooFit.FillColor(30),RooFit.LineColor(30),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineStyle(2), RooFit.LineWidth(3),RooFit.DrawOption("L"),RooFit.MoveToBack()) + #model.plotOn(xframe,RooFit.Name("kjpsi"),RooFit.Components("kjpsi"),RooFit.Range("Full"),RooFit.FillColor(43),RooFit.LineColor(43),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineStyle(2), RooFit.LineWidth(3),RooFit.DrawOption("L"),RooFit.MoveToBack()) + model.plotOn(xframe,RooFit.Name("kstarpsi2s"),RooFit.Components("kstarpsi2s"),RooFit.Range("Full"),RooFit.FillColor(30),RooFit.LineColor(12),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineStyle(2), RooFit.LineWidth(3),RooFit.DrawOption("L"),RooFit.MoveToBack()) + model.plotOn(xframe,RooFit.Name("kstarpluspsi2s"),RooFit.Components("kstarpluspsi2s"),RooFit.Range("Full"),RooFit.FillColor(30),RooFit.LineColor(46),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineStyle(2), RooFit.LineWidth(3),RooFit.DrawOption("L"),RooFit.MoveToBack()) + #model.plotOn(xframe,RooFit.Name("kstarjpsi"),RooFit.Components("kstarjpsi"),RooFit.Range("Full"),RooFit.FillColor(30),RooFit.LineColor(15),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineStyle(2), RooFit.LineWidth(3),RooFit.DrawOption("L"),RooFit.MoveToBack()) + model.plotOn(xframe,RooFit.Name("signal"),RooFit.Components("signal"),RooFit.Range("Full"),RooFit.DrawOption("L"),RooFit.LineStyle(2),RooFit.LineColor(ROOT.kBlue),RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected), RooFit.LineWidth(3)) + model.plotOn(xframe, RooFit.Normalization(norm, ROOT.RooAbsReal.RelativeExpected),RooFit.LineColor(ROOT.kRed) ) + # c1=canvas_create(xframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]') + # c1.SaveAs('total_fit_'+outputfile+'.pdf') + wspace.defineSet('obs', 'x') + obs = wspace.set('obs') + + params=model.getParameters(ROOT.RooArgSet(bMass)) + if Significance_range==None: + Significance_range={"min":params["mean"]-2*params["width"],"max":params["mean"]+2*params["width"]} + theBMass.setRange("window",Significance_range["min"],Significance_range["max"]) + + #theBMass.setRange("window",5.0,5.4) + obs2= ROOT.RooRealVar("obs2","obs2",Significance_range["min"],Significance_range["max"]) + nset = ROOT.RooArgSet(obs2) + print nsignal.getVal(), nsignal.getVal(nset) + print Significance_range + ncomb_visible, ncomb_visible_err = get_visible_yield_error(obs, results, exp_comb, ncomb) + nsig_visible, nsig_visible_err = get_visible_yield_error(obs, results, signal, nsignal) + nKstarPsi2S_visible = get_visible_yield(obs, results, kstarpsi2s , nKstarPsi2S) + nKstarPsi2S_visible_err = 0.0 + nKstarPlusPsi2S_visible = get_visible_yield(obs, results, kstarpluspsi2s , nKstarPlusPsi2S) + nKstarPlusPsi2S_visible_err = 0.0 + nKstarJpsi_visible, nKstarJpsi_visible_err = get_visible_yield_error(obs, results, kstarjpsi , nKstarJpsi) + nKJpsi_visible, nKJpsi_visible_err = get_visible_yield_error(obs, results,kjpsi , nKJpsi) + notherB_visible = get_visible_yield(obs, results, otherb , notherB) + notherB_visible_err = 0.0 + #nbkg_visible = ncomb_visible+nKstarPsi2S_visible+nKstarJpsi_visible+nKJpsi_visible+notherB_visible + #nbkg_visible = ncomb_visible+nKstarPsi2S_visible+nKJpsi_visible+notherB_visible + #nbkg_visible = ncomb_visible+nKstarPsi2S_visible+notherB_visible + #nbkg_visible = ncomb_visible+nKstarPsi2S_visible+nKstarJpsi_visible+notherB_visible + #nbkg_visible = ncomb_visible+nKstarPsi2S_visible+notherB_visible+nKstarPlusPsi2S_visible + nbkg_visible = ncomb_visible+nKstarPsi2S_visible+nKstarPlusPsi2S_visible + +# c1=canvas_create(xframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]') + n_param = results.floatParsFinal().getSize() + print "chi2",xframe.chiSquare(n_param),"ndof",n_param + print "edm",results.edm(),"log",results.minNll() + #c1=canvas_create(xframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]') + c1, top, bottom =canvas_create_pull(xframe,4.7,5.7,nbin_data,'m(e^{+}e^{-}K) [GeV]',theBMass) + top.cd() + + + legend = ROOT.TLegend(0.65,0.65,0.92,0.85) + legend.AddEntry(xframe.findObject("exp_comb"),"Combinatorial","l"); + legend.AddEntry(xframe.findObject("kstarpsi2s"),"B -> #psi(2S)K*","l"); + legend.AddEntry(xframe.findObject("kstarpluspsi2s"),"B -> #psi(2S)K*+","l"); + #legend.AddEntry(xframe.findObject("kstarjpsi"),"B -> J/#psiK*","l"); + #legend.AddEntry(xframe.findObject("kjpsi"),"B -> J/#psiK","l"); + legend.AddEntry(xframe.findObject("otherb"),"Other B","l"); + legend.AddEntry(xframe.findObject("signal"),"B -> #psi(2S)K","l"); + legend.SetLineColor(ROOT.kWhite) + legend.SetTextFont(42); + legend.SetTextSize(0.04); + legend.AddEntry(xframe.findObject("datas"),"Data","lpe"); + legend.Draw(); + #pt=pt_create(mvacut,nsig_visible,nsig_visible_err,nKstarPsi2S_visible+nKstarJpsi_visible+ncomb_visible+nKJpsi_visible+notherB_visible) + pt=pt_create(mvacut,nsig_visible,nsig_visible_err,nbkg_visible) + pt.Draw() + CMS_lumi() + c1.cd() + c1.Update() + c1.SaveAs('total_fit_'+outputfile+'.pdf') + print "signal",nsig_visible,"+/-", nsig_visible_err,"comb",ncomb_visible,"+/-", ncomb_visible_err,"K* Psi2S", nKstarPsi2S_visible, "+/-",nKstarPsi2S_visible_err,"K*+ Psi2S", nKstarPlusPsi2S_visible, "+/-",nKstarPlusPsi2S_visible_err,"K* J/psi", nKstarJpsi_visible, "+/-",nKstarJpsi_visible_err, "K J/psi", nKJpsi_visible, "+/-", nKJpsi_visible_err, "otherB", notherB_visible, "+/-",notherB_visible_err + residuals(xframe,theBMass,outputfile+"_poutana") + + saveWS = True + if saveWS: + # get likelihood + ''' + nll = model.createNLL(dataset) + ROOT.RooMinuit(nll).migrad() + nll_frame = nsignal.frame(RooFit.Bins(30),RooFit.Range(500,1000),RooFit.Title("LL and profileLL in nsignal")) ; + #nll.plotOn(nll_frame,RooFit.ShiftToZero()) + pll = nll.createProfile(ROOT.RooArgSet(nsignal)) + pll.plotOn(nll_frame,RooFit.LineColor(2),RooFit.ShiftToZero()) + nll_frame.SetMinimum(0); + nll_frame.SetMaximum(10) + c2 = canvas_create(nll_frame,0.0,0.0,0.0,'nsig') + CMS_lumi() + c2.cd() + c2.Update() + c2.SaveAs('nll_'+outputfile+'.pdf') + ''' + + wspace_output = ROOT.RooWorkspace('wspace') + getattr(wspace_output, "import")(model) + getattr(wspace_output, "import")(dataset) + params = model.getParameters(dataset) + wspace_output.saveSnapshot("nominal_values",params) + wspace_output.Print("V") + wspace_output.writeToFile('wspace_'+outputfile+'.root') + + csv_header = ['cut', 'nsig_total', 'nsig_total_unc', 'nKstarPsi2S_total', 'nKstarPsi2S_total_unc', 'nKstarPlusPsi2S_total', 'nKstarPlusPsi2S_total_unc', 'nsig', 'nbkg', 'ncomb', 'nKstarPsi2S', 'nKstarPlusPsi2S', 'nKstarJpsi', 'nKJpsi', 'notherB', 'snr', 'chi2'] + df = {} + df['cut'] = mvacut + df['nsig_total'] = nsignal.getVal() + df['nsig_total_unc'] = nsignal.getError() + df['nKstarPsi2S_total'] = nKstarPsi2S.getVal() + df['nKstarPsi2S_total_unc'] = nKstarPsi2S.getPropagatedError(results) + df['nKstarPlusPsi2S_total'] = nKstarPlusPsi2S.getVal() + df['nKstarPlusPsi2S_total_unc'] = nKstarPlusPsi2S.getPropagatedError(results) + df['nsig'] = nsig_visible + df['nbkg'] = nbkg_visible + df['ncomb'] = ncomb_visible + df['nKstarPsi2S'] = nKstarPsi2S_visible + df['nKstarPlusPsi2S'] = nKstarPlusPsi2S_visible + df['nKstarJpsi'] = nKstarJpsi_visible + df['nKJpsi'] = nKJpsi_visible + df['notherB'] = notherB_visible + df['snr'] = nsig_visible / np.sqrt(nsig_visible + nbkg_visible) + df['chi2'] = xframe.chiSquare(n_param) + csv_outputfile = log + file_exists = os.path.isfile(csv_outputfile) + with open (csv_outputfile, 'a+') as filedata: + writer = csv.DictWriter(filedata, delimiter=',', fieldnames=csv_header) + if not file_exists: + writer.writeheader() + writer.writerow(df) + + return (nsig_visible, ncomb_visible, nKstarPsi2S_visible, nKstarJpsi_visible, nKJpsi_visible, notherB_visible, nsignal.getVal() ) + + + +#################################### main ################################ +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser(description='Unbinned likelihood fit') + parser.add_argument("-i", "--inputfile", dest="inputfile", default="../BDT/TrainingCore/forMeas_xgbmodel_kee_v5.1_12B_Mu9_*_data.root", help="Input data file") + parser.add_argument("-o", "--outputfile", dest="outputfile", default="test", help="Output name") + parser.add_argument("--mvacut", dest="mva",default=6.2,type=float) + parser.add_argument("--isgn", "--isgnfile", dest="isgnfile", default="mc_files/reg/BParkingNANO_2021Mar05_BuToKJpsi_Toee_v2_BToKEEAnalyzer_2021Mar12_HLTMu9IP6_mc_tighterPreselectionWODmass_mva_pf.root", help="Input signal file") + parser.add_argument("--ibkg", dest="ibkg", default="../BDT/TrainingCore/forMeas_xgbmodel_kee_v5.1_12B_Mu9_*_samesign.root", help="Input combinatorial BKG file") + parser.add_argument("--iotherB", dest="iotherB_BKG", default="OtherB_BKGtree_KJpsiEE.root", help="Input combinatorial BKG file") + parser.add_argument("--iKstarPsi2S_BKG", dest="iKstarPsi2S_BKG", default="mc_files/reg/BParkingNANO_2021Mar05_BdToKstarJpsi_Toee_v2_BToKEEAnalyzer_2021Mar12_HLTMu9IP6_mc_tighterPreselectionWODmass_kaon_mva_pf.root", help="Input B->K*Psi(2S) BKG file") + parser.add_argument("--iKstarPlusPsi2S_BKG", dest="iKstarPlusPsi2S_BKG", default="mc_files/reg/BParkingNANO_2021Mar05_BdToKstarJpsi_Toee_v2_BToKEEAnalyzer_2021Mar12_HLTMu9IP6_mc_tighterPreselectionWODmass_kaon_mva_pf.root", help="Input combinatorial BKG file") + parser.add_argument("--iKstarJpsi_BKG", dest="iKstarJpsi_BKG", default="mc_files/reg/BParkingNANO_2021Mar05_BdToKstarJpsi_Toee_v2_BToKEEAnalyzer_2021Mar12_HLTMu9IP6_mc_tighterPreselectionWODmass_kaon_mva_pf.root", help="Input B->K*J/psi BKG file") + parser.add_argument("--iKJpsiee_BKG", dest="iKJpsiee_BKG", default="mc_files/reg/BParkingNANO_2021Mar05_BdToKstarJpsi_Toee_v2_BToKEEAnalyzer_2021Mar12_HLTMu9IP6_mc_tighterPreselectionWODmass_pion_mva_pf.root", help="Input B->KJ/psi BKG file") + parser.add_argument("--fit_primitive", dest="fit_primtv", default=False, action='store_true', help="primitive fits for fixing params or use defaults") + parser.add_argument("--skip_realfit", dest="skip_realfit", default=False, action='store_true', help="does not perform the final fit. useful for defining parameters, tests on pdfs") + parser.add_argument("--sel_primitive", dest="sel_primtv", default=None, help="runs only the selected primitive fits. Options: sgn bkg_comb bkg_otherb bkg_kstar_kee bkg_kstar_piee. they can be combined with ',' in strings. No spaces") + parser.add_argument("--partial_ratio", dest="partial_ratio", default=None, type=float, help="fixing the partially reco. yield") + parser.add_argument("--partial_ratio_kstarplus", dest="partial_ratio_kstarplus", default=None, type=float, help="fixing the partially reco. yield") + parser.add_argument("--minx", dest="minx", default=-1.0,type=float, help="minx for integral") + parser.add_argument("--maxx", dest="maxx", default=-1.0,type=float, help="maxx for integral") + parser.add_argument("--log", dest="log", default="log.csv", help="log of the fitting results") + args = parser.parse_args() + + branches=["Bmass","Mll","xgb","KLmassD0","Mu9_IP6"] + cuts = branches[2]+">"+str(args.mva)+" && 3.55<"+branches[1]+" && "+branches[1]+"<3.8" + " && " + branches[3] + ">2.0" #+ " && " + branches[4] + #cuts = branches[2]+">"+str(args.mva)+" && 0<"+branches[1]+" && "+branches[1]+"<5" + " && " + branches[3] + ">2.0" + cuts_otherb = branches[2]+">"+str(min(args.mva, 4.0))+" && 3.55<"+branches[1]+" && "+branches[1]+"<3.8" + " && " + branches[3] + ">2.0" #+ " && " + branches[4] + + if args.mva < 6.0: + cuts_samesign = branches[2]+">"+str(args.mva)+" && 3.55<"+branches[1]+" && "+branches[1]+"<3.8" + else: + cuts_samesign = branches[2]+"> 6.0 "+" && 3.55<"+branches[1]+" && "+branches[1]+"<3.8" + #cuts = branches[2]+">"+str(args.mva)+" && 3.55<"+branches[1]+" && "+branches[1]+"<3.8" + #cuts = branches[2]+">"+str(args.mva)+" && 3.55<"+branches[1]+" && "+branches[1]+"<3.8" + " && " + branches[3] + ">2.0" + args.outputfile+="_wp"+str(args.mva) + + otherB_parameters={'exp_alpha_otherb':-5.099} + #otherB_parameters={'exp_alpha_otherb':-7.099} + comb_parameters={'exp_alpha_comb':-1.50615} + + print "start" + if args.fit_primtv: + if args.sel_primtv!= None: + args.sel_primtv = args.sel_primtv.split(",") + else: + args.sel_primtv = ["sgn","bkg_comb","bkg_otherb","bkg_kstarjpsi","bkg_kstarpsi2s","bkg_kjpsi_ee","bkg_kstarpluspsi2s"] + print "primitive params" + if "sgn" in args.sel_primtv: + tree_sgn = ROOT.TChain('mytreefit') + tree_sgn.Add(args.isgnfile) + tree_sgn_cut=tree_sgn.CopyTree(cuts) + print tree_sgn_cut.GetEntries() + signal_parameters = signal_fit(tree_sgn_cut, args.outputfile+"_sgnMC", branches) + print "parameters SGN", signal_parameters['mean'], signal_parameters['width'],signal_parameters['alpha1'],signal_parameters['n1'],signal_parameters['frac'],signal_parameters['gauss_mean'],signal_parameters['gauss_width'] + + if "bkg_otherb" in args.sel_primtv: + tree_otherB = ROOT.TChain('mytreefit') + tree_otherB.Add(args.iotherB_BKG) + tree_otherB_cut=tree_otherB.CopyTree(cuts_otherb) + otherB_pdf = kde_fit(tree_otherB_cut, args.outputfile+"_otherBMC", branches, 'otherb', Bmass_min=4.5) + print "finished kde fit for other B" + + if "bkg_comb" in args.sel_primtv: + tree_bkg = ROOT.TChain('mytreefit') + tree_bkg.Add(args.ibkg) + tree_bkg_cut=tree_bkg.CopyTree(cuts_samesign) + comb_parameters = bkg_fit(tree_bkg_cut, args.outputfile+"_SameSign", branches) + print "parameters Combinatorial BKG", comb_parameters['exp_alpha_comb'] + + if "bkg_kstarpsi2s" in args.sel_primtv: + tree_KstarPsi2S = ROOT.TChain('mytreefit') + tree_KstarPsi2S.Add(args.iKstarPsi2S_BKG) + tree_KstarPsi2S_cut=tree_KstarPsi2S.CopyTree(cuts) + KstarPsi2S_pdf = kde_fit(tree_KstarPsi2S_cut, args.outputfile+"_KstarPsi2SMC", branches, 'kstarpsi2s') + print "finished kde fit for K* psi(2S)" + + if "bkg_kstarjpsi" in args.sel_primtv: + tree_KstarJpsi = ROOT.TChain('mytreefit') + tree_KstarJpsi.Add(args.iKstarJpsi_BKG) + tree_KstarJpsi_cut=tree_KstarJpsi.CopyTree(cuts) + KstarJpsi_pdf = kde_fit(tree_KstarJpsi_cut, args.outputfile+"_KstarJpsiMC", branches, 'kstarjpsi') + print "finished kde fit for K* J/psi" + + if "bkg_kjpsi_ee" in args.sel_primtv: + tree_KJpsiee = ROOT.TChain('mytreefit') + tree_KJpsiee.Add(args.iKJpsiee_BKG) + tree_KJpsiee_cut=tree_KJpsiee.CopyTree(cuts) + KJpsiee_pdf = kde_fit(tree_KJpsiee_cut, args.outputfile+"_KJpsieeMC", branches, 'kjpsi') + print "finished kde fit for K J/psi" + + if "bkg_kstarpluspsi2s" in args.sel_primtv: + tree_KstarPlusPsi2S = ROOT.TChain('mytreefit') + tree_KstarPlusPsi2S.Add(args.iKstarPlusPsi2S_BKG) + tree_KstarPlusPsi2S_cut=tree_KstarPlusPsi2S.CopyTree(cuts) + KstarPlusPsi2S_pdf = kde_fit(tree_KstarPlusPsi2S_cut, args.outputfile+"_KstarPlusPsi2SMC", branches, 'kstarpluspsi2s') + print "finished kde fit for K*+ J psi(2S)" + + else: + print "Need to provide MC template" + + if not args.skip_realfit: + tree = ROOT.TChain('mytreefit') + tree.Add(args.inputfile) + tree_cut=tree.CopyTree(cuts) + if args.minx==-1: args.minx=signal_parameters["mean"]-2*signal_parameters["width"] + if args.maxx==-1: args.maxx=signal_parameters["mean"]+2*signal_parameters["width"] + + nsig, nbkg, nKstarPsi2S, nKstarJpsi, nKJpsi, notherB, nsig_total =total_fit(tree_cut, args.outputfile, branches, signal_parameters, otherB_pdf, KstarPsi2S_pdf, KstarPlusPsi2S_pdf, KstarJpsi_pdf ,KJpsiee_pdf, comb_parameters, {"min":args.minx,"max":args.maxx},args.partial_ratio, args.partial_ratio_kstarplus, str(args.mva), args.log) + print "sig",nsig,"comb", nbkg,"K* Psi2S", nKstarPsi2S,"K* J/psi", nKstarJpsi,"K J/psi", nKJpsi, "otherB", notherB,"all sig", nsig_total + # combinatorial BKG parameters set but not fixed. +# print "sigma",float(nsig)/math.sqrt(nsig+nkjpsi+nbkg),"nsig",float(nsig),"nbkg",float(nbkg),"Kjpsi leak",float(nkjpsi) + + + diff --git a/fit/roofit_helper.py b/fit/roofit_helper.py new file mode 100644 index 0000000..0e3d332 --- /dev/null +++ b/fit/roofit_helper.py @@ -0,0 +1,120 @@ +import ROOT as rt +from math import sqrt + + +def CMS_lumi(): + mark = rt.TLatex() + mark.SetNDC() + lumistamp = '2018 (13 TeV)' + fontScale = 1.0 + cmsTextSize = 0.042 * fontScale * 1.25 + extraOverCmsTextSize = 0.76 + extraTextSize = extraOverCmsTextSize*cmsTextSize + + mark.SetTextAlign(11) + mark.SetTextSize(cmsTextSize) + mark.SetTextFont(61) + mark.DrawLatex(rt.gPad.GetLeftMargin(), 1 - (rt.gPad.GetTopMargin() - 0.017), "CMS") + mark.SetTextSize(0.042 * fontScale) + mark.SetTextFont(52) + mark.DrawLatex(rt.gPad.GetLeftMargin() + 0.09, 1 - (rt.gPad.GetTopMargin() - 0.017), "Preliminary") + mark.SetTextSize(extraTextSize) + mark.SetTextFont(42) + mark.SetTextAlign(31) + mark.DrawLatex(1 - rt.gPad.GetRightMargin(), 1 - ( rt.gPad.GetTopMargin() - 0.017), lumistamp) + return mark + + +def canvas_create(xframe,xmin,xmax,nbin,xtitle,boundYto0=True): + c2 = rt.TCanvas('fig_binnedFit', 'fit', 800, 600) + c2.SetGrid() + rt.gPad.SetLeftMargin(0.12) + rt.gPad.SetRightMargin(0.05) + rt.gPad.SetBottomMargin(0.15) + #xframe.GetYaxis().SetTitle("Events / {0:.0f} MeV".format((xmax - xmin)/nbin*1000.)) + xframe.GetXaxis().SetTitle(xtitle) + xframe.SetStats(0) + if (boundYto0): xframe.SetMinimum(0) + xframe.GetYaxis().SetLabelSize(0.045) + xframe.GetYaxis().SetLabelOffset(0.007) + xframe.GetYaxis().SetTitleSize(0.06) + xframe.GetYaxis().SetTitleOffset(0.90) + xframe.GetXaxis().SetLabelSize(0.045) + xframe.GetXaxis().SetLabelOffset(0.007) + xframe.GetXaxis().SetTitleSize(0.06) + xframe.GetXaxis().SetTitleOffset(0.95) + xframe.SetTitle("") + xframe.Draw() + return c2 + +def canvas_create_pull(xframe,xmin,xmax,nbin,xtitle,var,boundYto0=True): + c2 = rt.TCanvas('fig_binnedFit', 'fit', 800, 800) + c2.cd() + c2.SetGrid() + top = rt.TPad("top", "top", 0., 0.25, 1., 1.) + top.SetGrid() + top.SetLeftMargin(0.12) + top.SetRightMargin(0.05) + top.SetBottomMargin(0.0) + top.Draw() + top.cd() + #xframe.GetYaxis().SetTitle("Events / {0:.0f} MeV".format((xmax - xmin)/nbin*1000.)) + #xframe.GetXaxis().SetTitle(xtitle) + xframe.SetStats(0) + if (boundYto0): xframe.SetMinimum(0) + xframe.GetYaxis().SetLabelSize(0.045) + xframe.GetYaxis().SetLabelOffset(0.007) + xframe.GetYaxis().SetTitleSize(0.06) + xframe.GetYaxis().SetTitleOffset(0.90) + xframe.GetXaxis().SetLabelSize(0.045) + xframe.GetXaxis().SetLabelOffset(0.007) + xframe.GetXaxis().SetTitleSize(0.06) + xframe.GetXaxis().SetTitleOffset(0.95) + xframe.SetTitle("") + xframe.Draw() + + hpull = xframe.pullHist() + xframe3 = var.frame() + xframe3.addPlotable(hpull,"P") + + scale = 3.0 + c2.cd() + bottom = rt.TPad("bottom", "bottom", 0., 0., 1., 0.25) + bottom.SetGrid() + bottom.SetLeftMargin(0.12) + bottom.SetRightMargin(0.05) + bottom.SetBottomMargin(0.4) + bottom.SetTopMargin(0.03) + bottom.Draw() + bottom.cd() + xframe3.GetXaxis().SetTitle(xtitle) + xframe3.SetStats(0) + xframe3.GetYaxis().SetLabelSize(0.045*scale) + xframe3.GetYaxis().SetLabelOffset(0.007) + xframe3.GetYaxis().SetTitleSize(0.06*scale) + xframe3.GetYaxis().SetTitleOffset(0.90/scale) + xframe3.GetXaxis().SetLabelSize(0.045*scale) + xframe3.GetXaxis().SetLabelOffset(0.007) + xframe3.GetXaxis().SetTitleSize(0.06*scale) + xframe3.GetXaxis().SetTitleOffset(0.95) + xframe3.SetTitle("") + xframe3.GetYaxis().SetTitle("Pull") + xframe3.SetMinimum(-3.5) + xframe3.SetMaximum(3.5) + + xframe3.Draw() + + return c2, top, bottom + +def pt_create(mva,nsig,nsigError,nbkg): + pt = rt.TPaveText(0.72,0.37,0.92,0.63,"brNDC") + pt.SetFillColor(0) + pt.SetBorderSize(1) + pt.SetTextFont(42); + pt.SetTextSize(0.04); + pt.SetTextAlign(12) + pt.AddText("MVA cut: {0}".format(mva)) + pt.AddText("S: {0:.1f}#pm{1:.1f}".format(nsig,nsigError)) + pt.AddText("B: {0:.1f}".format(nbkg)) + pt.AddText("S/#sqrt{{S+B}}: {0:.2f}".format(nsig/sqrt(nsig + nbkg))) + return pt diff --git a/fit/roofit_models.py b/fit/roofit_models.py new file mode 100644 index 0000000..e24ac2e --- /dev/null +++ b/fit/roofit_models.py @@ -0,0 +1,23 @@ +root_function_DoubleSidedCB=""" + +double DoubleSidedCB2(double x, double mu, double width, double a1, double p1, double a2, double p2) +{ + double u = (x-mu)/width; + double A1 = TMath::Power(p1/TMath::Abs(a1),p1)*TMath::Exp(-a1*a1/2); + double A2 = TMath::Power(p2/TMath::Abs(a2),p2)*TMath::Exp(-a2*a2/2); + double B1 = p1/TMath::Abs(a1) - TMath::Abs(a1); + double B2 = p2/TMath::Abs(a2) - TMath::Abs(a2); + + double result(1); + if (u<-a1) result *= A1*TMath::Power(B1-u,-p1); + else if (u {})'.format(jpsi_mva_wp)])).shape[0]) / float(jpsi_mc_branches[i].query(selection['jpsi']).shape[0]) for i in nparts]) + #eff['jpsi_bdt'] = np.mean([float(jpsi_mc_branches[i].query(' and '.join([selection['jpsi'], selection['Dmass'], selection['hlt'], '(xgb > {})'.format(jpsi_mva_wp)])).shape[0]) / float(jpsi_mc_branches[i].query(selection['jpsi']).shape[0]) for i in nparts]) + + if eleType == 'pf': + #mvaCut = np.linspace(8.0, 8.7, 8) + mvaCut = np.array([8.3, ]) + else: + #mvaCut = np.linspace(8.3, 9.0, 8) + mvaCut = np.array([8.6, ]) + + for cut in mvaCut: + eff_lowq2_bdt = np.mean([float(nonresonant_mc_branches[i].query(' and '.join([selection['lowq2'], '(xgb > @cut)', selection['Dmass']])).shape[0]) / float(nonresonant_mc_branches[i].query(selection['lowq2']).shape[0]) for i in nparts]) + #eff_lowq2_bdt = np.mean([float(nonresonant_mc_branches[i].query(' and '.join([selection['lowq2'], selection['hlt'], '(xgb > @cut)', selection['Dmass']])).shape[0]) / float(nonresonant_mc_branches[i].query(selection['lowq2']).shape[0]) for i in nparts]) + + expected_signal = rk_electron * n_data_jpsi * eff['lowq2_presel'] * eff['lowq2_q2'] * eff_lowq2_bdt / (eff['jpsi_presel'] * eff['jpsi_q2'] * eff['jpsi_bdt']) + + if num_mctoys is not None: + com = 'python KEE_lowq2_roofit_plb_pull_modified.py -i {0} -o lowq2_{1} --isgn={2} --ikjpsi={3} --sel_primitive="sgn,bkg_kjpsi" --fit_primitive --mvacut={4} --set_expected_sgn={5} --number_of_mctoys={6} --log={7}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['ikjpsi'], cut, expected_signal, num_mctoys, log) + else: + com = 'python KEE_lowq2_roofit_plb_pull_modified_kde.py -i {0} -o lowq2_{1} --isgn={2} --ikjpsi={3} --ikstaree={4} --sel_primitive="sgn,bkg_kjpsi,bkg_kstaree" --fit_primitive --mvacut={5} --set_expected_sgn={6} --log={8}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['ikjpsi'], info[eleType]['ikstaree'], cut, expected_signal, num_mctoys, log) + #com = 'python KEE_lowq2_roofit_plb_pull_modified_kde.py -i {0} -o lowq2_{1} --isgn={2} --ikjpsi={3} --sel_primitive="sgn,bkg_kjpsi" --fit_primitive --mvacut={4} --set_expected_sgn={5} --log={7}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['ikjpsi'], cut, expected_signal, num_mctoys, log) + + os.system(com) + print('cut: {} \n \t expected signal: {} \n \t lowq2 bdt eff: {}'.format(cut, expected_signal, eff_lowq2_bdt)) + print('\t {}, {}'.format(eff['lowq2_presel'], eff['lowq2_q2'])) + print('\t overall eff: {}'.format(eff['lowq2_presel'] * eff['lowq2_q2'] * eff_lowq2_bdt)) + + for key, value in eff.items(): + print('{}: {}'.format(key, value)) + + + + diff --git a/fit/run_fit_KJpsi_fixedPartial.py b/fit/run_fit_KJpsi_fixedPartial.py new file mode 100644 index 0000000..6c8cfe2 --- /dev/null +++ b/fit/run_fit_KJpsi_fixedPartial.py @@ -0,0 +1,137 @@ +import uproot +import pandas as pd +import numpy as np +from collections import OrderedDict, defaultdict +from scipy import interp +from rootpy.io import root_open +from rootpy.plotting import Hist +from root_numpy import fill_hist, array2root, array2tree +from root_pandas import to_root +import itertools +import PyPDF2 +#import makePlot_fitPeak_unbinned as fit_unbinned +import os, sys, copy +import xgboost as xgb + +LOWQ2_LOW = 1.05 +LOWQ2_UP = 2.45 +JPSI_LOW = 2.8 +JPSI_UP = 3.25 +PSI2S_LOW = 3.45 +PSI2S_UP = 3.8 +HIGHQ2_LOW = 4.0 +HIGHQ2_UP = 4.87 + +def get_df(root_file_name, tree='mytreefit', branches=['*']): + print('Opening file {}...'.format(root_file_name)) + f = uproot.open(root_file_name) + if len(f.allkeys()) == 0: + return pd.DataFrame() + print('Not an null file') + #df = uproot.open(root_file_name)["tree"].pandas.df() + #df = pd.DataFrame(uproot.open(root_file_name)["tree"].arrays(namedecode="utf-8")) + df = pd.DataFrame(f[tree].arrays(branches=branches)) + print('Finished opening file {}...'.format(root_file_name)) + return df + +if __name__ == "__main__": + eleType = 'pf' + log = 'log_jpsi_bparkPU_v7.3_{}_nonreg_floating_mean_tightWP_otherB.csv'.format(eleType) + info = defaultdict(dict) + + br_b2kjpsi = 1.02e-3 + br_b2kstarjpsi = 1.27e-3 * 2./3. + br_b2kstarplusjpsi = 1.43e-3 + + nparts = range(8) + + # PF-PF nonreg + info['pf']['inputfile'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_data_mvaCut0.root' + info['pf']['jpsi_mc'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_{}_MCres.root'.format('marker') + info['pf']['partial_mc'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_{}_MC_kstarjpsi.root'.format('marker') + info['pf']['kstarplus_mc'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_{}_MC_kstarplusjpsi.root'.format('marker') + info['pf']['isgn'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_0_MCres.root' + info['pf']['iKstarJpsi_BKG'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_0_MC_kstarjpsi.root' + info['pf']['iKstarPlusJpsi_BKG'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_0_MC_kstarplusjpsi.root' + info['pf']['n_mc_jpsi'] = 211912.0 + info['pf']['n_mc_partial'] = 379086.0 + info['pf']['n_mc_kstarplus'] = 314672.0 + info['pf']['ibkg'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_samesign_mvaCut0.root' + info['pf']['iotherB'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_0_MC_otherb.root' + + # PF-LP + info['mix']['inputfile'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_data_mvaCut0.root' + info['mix']['jpsi_mc'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_{}_MCres.root'.format('marker') + info['mix']['partial_mc'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_{}_MC_kstarjpsi.root'.format('marker') + info['mix']['kstarplus_mc'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_{}_MC_kstarplusjpsi.root'.format('marker') + info['mix']['isgn'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_0_MCres.root' + info['mix']['iKstarJpsi_BKG'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_0_MC_kstarjpsi.root' + info['mix']['iKstarPlusJpsi_BKG'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_0_MC_kstarplusjpsi.root' + info['mix']['n_mc_jpsi'] = 211912.0 + info['mix']['n_mc_partial'] = 379086.0 + info['mix']['n_mc_kstarplus'] = 314672.0 + info['mix']['ibkg'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_samesign_mvaCut0.root' + info['mix']['iotherB'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_0_MC_otherb.root' + + selection = {} + + selection['jpsi'] = '(Mll > 2.9) and (Mll < 3.2)' + selection['psi2s'] = '(Mll > 3.55) and (Mll < 3.8)' + selection['Dmass'] = '(KLmassD0 > 2.0)' + + mc_branches = ['Bmass', 'Mll', 'xgb', 'KLmassD0'] + + jpsi_mc_branches = [get_df(info[eleType]['jpsi_mc'].replace('marker', str(i)), branches=mc_branches) for i in nparts] + partial_mc_branches = [get_df(info[eleType]['partial_mc'].replace('marker', str(i)), branches=mc_branches) for i in nparts] + kstarplus_mc_branches = [get_df(info[eleType]['kstarplus_mc'].replace('marker', str(i)), branches=mc_branches) for i in nparts] + + + if eleType == 'pf': + #mvaCut = np.linspace(4.0, 6.0, 11) + #mvaCut = np.linspace(8.0, 8.7, 8) + mvaCut = np.array([8.3, ]) + + else: + #mvaCut = np.linspace(4.0, 6.0, 11) + #mvaCut = np.linspace(8.3, 9.0, 8) + mvaCut = np.array([8.6, ]) + + for cut in mvaCut: + eff_sig_bdt = np.mean([float(jpsi_mc_branches[i].query(' and '.join([selection['jpsi'], selection['Dmass'], '(xgb > @cut)'])).shape[0]) / info[eleType]['n_mc_jpsi'] for i in nparts]) + eff_partial_bdt = np.mean([float(partial_mc_branches[i].query(' and '.join([selection['jpsi'], selection['Dmass'], '(xgb > @cut)'])).shape[0]) / info[eleType]['n_mc_partial'] for i in nparts]) + eff_kstarplus_bdt = np.mean([float(kstarplus_mc_branches[i].query(' and '.join([selection['jpsi'], selection['Dmass'], '(xgb > @cut)'])).shape[0]) / info[eleType]['n_mc_kstarplus'] for i in nparts]) + + frac_ratio = (eff_partial_bdt / eff_sig_bdt) * (br_b2kstarjpsi / br_b2kjpsi) + #frac_ratio_kstarplus = (eff_kstarplus_bdt / eff_sig_bdt) * (br_b2kstarplusjpsi / br_b2kjpsi) + frac_ratio_kstarplus = (eff_kstarplus_bdt / eff_partial_bdt) * (br_b2kstarplusjpsi / br_b2kstarjpsi) + total_ratio = ((eff_partial_bdt + eff_kstarplus_bdt) / eff_sig_bdt) * ((br_b2kstarjpsi + br_b2kstarplusjpsi) / br_b2kjpsi) + + print(frac_ratio, frac_ratio_kstarplus) + #print(total_ratio) + + if eleType == 'pf': + # fixed partial ratio + #com = 'python KJpsi_roofit_plb_modified_kde_kstarPlus.py -i {} -o jpsi_fixedPartial_{} --isgn={} --iKstarJpsi_BKG={} --iKstarPlusJpsi_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarjpsi,bkg_kstarplusjpsi,bkg_comb" --fit_primitive --partial_ratio={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKstarPlusJpsi_BKG'], info[eleType]['ibkg'], frac_ratio, cut, log) + # not fixing partial ratio + #com = 'python KJpsi_roofit_plb_modified_kde_fixedPartial.py -i {} -o jpsi_fixedPartial_{} --isgn={} --iKstarJpsi_BKG={} --iKstarPlusJpsi_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarjpsi,bkg_kstarplusjpsi,bkg_comb" --fit_primitive --partial_ratio={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKstarPlusJpsi_BKG'], info[eleType]['ibkg'], frac_ratio, cut, log) + #com = 'python KJpsi_roofit_plb_modified_kde_fixedPartial.py -i {} -o jpsi_fixedPartial_{} --isgn={} --iKstarJpsi_BKG={} --iKstarPlusJpsi_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarjpsi,bkg_kstarplusjpsi,bkg_comb" --fit_primitive --partial_ratio={} --partial_ratio_kstarplus={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKstarPlusJpsi_BKG'], info[eleType]['ibkg'], frac_ratio, frac_ratio_kstarplus, cut, log) + com = 'python KJpsi_roofit_plb_modified_kde_fixedPartial.py -i {} -o jpsi_fixedPartial_{} --isgn={} --iotherB={} --iKstarJpsi_BKG={} --iKstarPlusJpsi_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarjpsi,bkg_kstarplusjpsi,bkg_otherb,bkg_comb" --fit_primitive --partial_ratio={} --partial_ratio_kstarplus={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iotherB'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKstarPlusJpsi_BKG'], info[eleType]['ibkg'], frac_ratio, frac_ratio_kstarplus, cut, log) + #com = 'python KJpsi_roofit_plb_modified_kde_fixedPartial_v1.py -i {} -o jpsi_fixedPartial_{} --isgn={} --iotherB={} --iKstarJpsi_BKG={} --iKstarPlusJpsi_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarjpsi,bkg_kstarplusjpsi,bkg_otherb,bkg_comb" --fit_primitive --partial_ratio={} --partial_ratio_kstarplus={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iotherB'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKstarPlusJpsi_BKG'], info[eleType]['ibkg'], frac_ratio, frac_ratio_kstarplus, cut, log) + + + # without same-sign + #com = 'python KJpsi_roofit_plb_modified_kde_fixedPartial.py -i {} -o jpsi_fixedPartial_{} --isgn={} --iKstarJpsi_BKG={} --sel_primitive="sgn,bkg_kstarjpsi" --fit_primitive --partial_ratio={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarJpsi_BKG'], frac_ratio, cut, log) + + + else: + #com = 'python KJpsi_roofit_plb_modified_kde_fixedPartial.py -i {} -o jpsi_fixedPartial_{} --isgn={} --iKstarJpsi_BKG={} --sel_primitive="sgn,bkg_kstarjpsi" --fit_primitive --partial_ratio={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarJpsi_BKG'], frac_ratio, cut, log) + #com = 'python KJpsi_roofit_plb_modified_kde_fixedPartial.py -i {} -o jpsi_fixedPartial_{} --isgn={} --iKstarJpsi_BKG={} --iKstarPlusJpsi_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarjpsi,bkg_kstarplusjpsi,bkg_comb" --fit_primitive --partial_ratio={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKstarPlusJpsi_BKG'], info[eleType]['ibkg'], frac_ratio, cut, log) + #com = 'python KJpsi_roofit_plb_modified_kde_fixedPartial.py -i {} -o jpsi_fixedPartial_{} --isgn={} --iKstarJpsi_BKG={} --iKstarPlusJpsi_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarjpsi,bkg_kstarplusjpsi,bkg_comb" --fit_primitive --partial_ratio={} --partial_ratio_kstarplus={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKstarPlusJpsi_BKG'], info[eleType]['ibkg'], frac_ratio, frac_ratio_kstarplus, cut, log) + com = 'python KJpsi_roofit_plb_modified_kde_fixedPartial.py -i {} -o jpsi_fixedPartial_{} --isgn={} --iotherB={} --iKstarJpsi_BKG={} --iKstarPlusJpsi_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarjpsi,bkg_kstarplusjpsi,bkg_otherb,bkg_comb" --fit_primitive --partial_ratio={} --partial_ratio_kstarplus={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iotherB'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKstarPlusJpsi_BKG'], info[eleType]['ibkg'], frac_ratio, frac_ratio_kstarplus, cut, log) + #com = 'python KJpsi_roofit_plb_modified_kde_fixedPartial_v1.py -i {} -o jpsi_fixedPartial_{} --isgn={} --iotherB={} --iKstarJpsi_BKG={} --iKstarPlusJpsi_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarjpsi,bkg_kstarplusjpsi,bkg_otherb,bkg_comb" --fit_primitive --partial_ratio={} --partial_ratio_kstarplus={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iotherB'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKstarPlusJpsi_BKG'], info[eleType]['ibkg'], frac_ratio, frac_ratio_kstarplus, cut, log) + + + os.system(com) + + + diff --git a/fit/run_fit_KPsi2S_fixedPartial.py b/fit/run_fit_KPsi2S_fixedPartial.py new file mode 100644 index 0000000..626e173 --- /dev/null +++ b/fit/run_fit_KPsi2S_fixedPartial.py @@ -0,0 +1,136 @@ +import uproot +import pandas as pd +import numpy as np +from collections import OrderedDict, defaultdict +from scipy import interp +from rootpy.io import root_open +from rootpy.plotting import Hist +from root_numpy import fill_hist, array2root, array2tree +from root_pandas import to_root +import itertools +import PyPDF2 +#import makePlot_fitPeak_unbinned as fit_unbinned +import os, sys, copy +import xgboost as xgb + +LOWQ2_LOW = 1.05 +LOWQ2_UP = 2.45 +JPSI_LOW = 2.8 +JPSI_UP = 3.25 +PSI2S_LOW = 3.45 +PSI2S_UP = 3.8 +HIGHQ2_LOW = 4.0 +HIGHQ2_UP = 4.87 + +def get_df(root_file_name, tree='mytreefit', branches=['*']): + print('Opening file {}...'.format(root_file_name)) + f = uproot.open(root_file_name) + if len(f.allkeys()) == 0: + return pd.DataFrame() + print('Not an null file') + #df = uproot.open(root_file_name)["tree"].pandas.df() + #df = pd.DataFrame(uproot.open(root_file_name)["tree"].arrays(namedecode="utf-8")) + df = pd.DataFrame(f[tree].arrays(branches=branches)) + print('Finished opening file {}...'.format(root_file_name)) + return df + +if __name__ == "__main__": + eleType = 'pf' + log = 'log_psi2s_bparkPU_v7.3_{}_nonreg_tightWP_otherB.csv'.format(eleType) + info = defaultdict(dict) + + br_b2kpsi2s = 6.24e-4 + br_b2kstarpsi2s = 5.9e-4 * 2./3. + br_b2kstarpluspsi2s = 6.7e-4 + br_b2kstarjpsi = 1.27e-3 * 2./3. + br_psi2s2ee = 7.93e-3 + br_jpsi2ee = 0.05971 + + nparts = range(8) + + # PF-PF nonreg + info['pf']['inputfile'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_data_mvaCut0.root' + info['pf']['psi2s_mc'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_{}_MCPsi2S.root'.format('marker') + info['pf']['partial_mc'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_{}_MC_kstarpsi2s.root'.format('marker') + info['pf']['kstarplus_mc'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_{}_MC_kstarpluspsi2s.root'.format('marker') + info['pf']['isgn'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_0_MCPsi2S.root' + info['pf']['iKstarPsi2S_BKG'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_0_MC_kstarpsi2s.root' + info['pf']['iKstarPlusPsi2S_BKG'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_0_MC_kstarpluspsi2s.root' + info['pf']['iKstarJpsi_BKG'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_0_MC_kstarjpsi.root' + info['pf']['iKJpsiee_BKG'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_0_MCres.root' + info['pf']['n_mc_psi2s'] = 180840.0 + info['pf']['n_mc_partial'] = 443318.0 + info['pf']['n_mc_kstarplus'] = 395456.0 + info['pf']['ibkg'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_samesign_mvaCut0.root' + info['pf']['iotherB'] = '../data/data_PFe_v7.3_nonreg_ottoCut/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_PFe_v7.3_nonreg_ottoCut_0_MC_otherb.root' + + + # PF-LP nonreg + info['mix']['inputfile'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_data_mvaCut0.root' + info['mix']['psi2s_mc'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_{}_MCPsi2S.root'.format('marker') + info['mix']['partial_mc'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_{}_MC_kstarpsi2s.root'.format('marker') + info['mix']['kstarplus_mc'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_{}_MC_kstarpluspsi2s.root'.format('marker') + info['mix']['isgn'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_0_MCPsi2S.root' + info['mix']['iKstarPsi2S_BKG'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_0_MC_kstarpsi2s.root' + info['mix']['iKstarPlusPsi2S_BKG'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_0_MC_kstarpluspsi2s.root' + info['mix']['iKstarJpsi_BKG'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_0_MC_kstarjpsi.root' + info['mix']['iKJpsiee_BKG'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_0_MCres.root' + info['mix']['n_mc_psi2s'] = 180840.0 + info['mix']['n_mc_partial'] = 443318.0 + info['mix']['n_mc_kstarplus'] = 395456.0 + info['mix']['ibkg'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_samesign_mvaCut0.root' + info['mix']['iotherB'] = '../data/data_LowPtPF_v7.3_nonreg/forMeas_xgbmodel_kee_12B_kee_correct_pu_Depth17_LowPtPF_v7.3_nonreg_0_MC_otherb.root' + + selection = {} + + selection['jpsi'] = '(Mll > 2.9) and (Mll < 3.2)' + selection['psi2s'] = '(Mll > 3.55) and (Mll < 3.8)' + selection['Dmass'] = '(KLmassD0 > 2.0)' + + mc_branches = ['Bmass', 'Mll', 'xgb', 'KLmassD0'] + + psi2s_mc_branches = [get_df(info[eleType]['psi2s_mc'].replace('marker', str(i)), branches=mc_branches) for i in nparts] + partial_mc_branches = [get_df(info[eleType]['partial_mc'].replace('marker', str(i)), branches=mc_branches) for i in nparts] + kstarplus_mc_branches = [get_df(info[eleType]['kstarplus_mc'].replace('marker', str(i)), branches=mc_branches) for i in nparts] + + + if eleType == 'pf': + #mvaCut = np.linspace(4.0, 6.0, 11) + #mvaCut = np.linspace(8.0, 8.7, 8) + mvaCut = np.array([8.3,]) + else: + #mvaCut = np.linspace(4.0, 6.0, 11) + #mvaCut = np.linspace(8.3, 9.0, 8) + mvaCut = np.array([8.6,]) + + for cut in mvaCut: + eff_sig_bdt = np.mean([float(psi2s_mc_branches[i].query(' and '.join([selection['psi2s'], selection['Dmass'], '(xgb > @cut)'])).shape[0]) / info[eleType]['n_mc_psi2s'] for i in nparts]) + eff_partial_bdt = np.mean([float(partial_mc_branches[i].query(' and '.join([selection['psi2s'], selection['Dmass'], '(xgb > @cut)'])).shape[0]) / info[eleType]['n_mc_partial'] for i in nparts]) + eff_kstarplus_bdt = np.mean([float(kstarplus_mc_branches[i].query(' and '.join([selection['psi2s'], selection['Dmass'], '(xgb > @cut)'])).shape[0]) / info[eleType]['n_mc_kstarplus'] for i in nparts]) + + frac_ratio = (eff_partial_bdt / eff_sig_bdt) * (br_b2kstarpsi2s / br_b2kpsi2s) + #frac_ratio = (eff_partial_bdt / eff_sig_bdt) * ((br_b2kstarjpsi*br_jpsi2ee) / (br_b2psi2s*br_psi2s2ee)) + #frac_ratio_kstarplus = (eff_kstarplus_bdt / eff_sig_bdt) * (br_b2kstarpluspsi2s / br_b2kpsi2s) + frac_ratio_kstarplus = (eff_kstarplus_bdt / eff_partial_bdt) * (br_b2kstarpluspsi2s / br_b2kstarpsi2s) + + print(frac_ratio, frac_ratio_kstarplus, eff_partial_bdt, eff_kstarplus_bdt, eff_sig_bdt) + + if eleType == 'pf': + #com = 'python KPsi2S_roofit_plb_modified_kde_fixedPartial.py -i {} -o psi2s_fixedPartial_{} --isgn={} --iKstarPsi2S_BKG={} --iKstarJpsi_BKG={} --iKJpsiee_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarpsi2s,bkg_kstarjpsi,bkg_kjpsi_ee,bkg_comb" --fit_primitive --partial_ratio={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarPsi2S_BKG'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKJpsiee_BKG'], info[eleType]['ibkg'], frac_ratio, cut, log) + #com = 'python KPsi2S_roofit_plb_modified_kde_fixedPartial.py -i {} -o psi2s_fixedPartial_{} --isgn={} --iKstarPsi2S_BKG={} --iKstarJpsi_BKG={} --iKJpsiee_BKG={} --sel_primitive="sgn,bkg_kstarpsi2s,bkg_kstarjpsi,bkg_kjpsi_ee" --fit_primitive --partial_ratio={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarPsi2S_BKG'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKJpsiee_BKG'], frac_ratio, cut, log) + #com = 'python KPsi2S_roofit_plb_modified_kde_fixedPartial.py -i {} -o psi2s_fixedPartial_{} --isgn={} --iKstarPsi2S_BKG={} --iKstarPlusPsi2S_BKG={} --iKstarJpsi_BKG={} --iKJpsiee_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarpsi2s,bkg_kstarjpsi,bkg_kstarpluspsi2s,bkg_kjpsi_ee,bkg_comb" --fit_primitive --partial_ratio={} --partial_ratio_kstarplus={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarPsi2S_BKG'], info[eleType]['iKstarPlusPsi2S_BKG'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKJpsiee_BKG'], info[eleType]['ibkg'], frac_ratio, frac_ratio_kstarplus, cut, log) + com = 'python KPsi2S_roofit_plb_modified_kde_fixedPartial.py -i {} -o psi2s_fixedPartial_{} --isgn={} --iotherB={} --iKstarPsi2S_BKG={} --iKstarPlusPsi2S_BKG={} --iKstarJpsi_BKG={} --iKJpsiee_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarpsi2s,bkg_kstarjpsi,bkg_kstarpluspsi2s,bkg_kjpsi_ee,bkg_comb,bkg_otherb" --fit_primitive --partial_ratio={} --partial_ratio_kstarplus={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iotherB'], info[eleType]['iKstarPsi2S_BKG'], info[eleType]['iKstarPlusPsi2S_BKG'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKJpsiee_BKG'], info[eleType]['ibkg'], frac_ratio, frac_ratio_kstarplus, cut, log) + + + else: + #com = 'python KPsi2S_roofit_plb_modified_kde_fixedPartial.py -i {} -o psi2s_fixedPartial_{} --isgn={} --iKstarPsi2S_BKG={} --iKstarJpsi_BKG={} --iKJpsiee_BKG={} --sel_primitive="sgn,bkg_kstarpsi2s,bkg_kstarjpsi,bkg_kjpsi_ee" --fit_primitive --partial_ratio={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarPsi2S_BKG'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKJpsiee_BKG'], frac_ratio, cut, log) + #com = 'python KPsi2S_roofit_plb_modified_kde_fixedPartial.py -i {} -o psi2s_fixedPartial_{} --isgn={} --iKstarPsi2S_BKG={} --iKstarPlusPsi2S_BKG={} --iKstarJpsi_BKG={} --iKJpsiee_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarpsi2s,bkg_kstarjpsi,bkg_kstarpluspsi2s,bkg_kjpsi_ee,bkg_comb" --fit_primitive --partial_ratio={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarPsi2S_BKG'], info[eleType]['iKstarPlusPsi2S_BKG'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKJpsiee_BKG'], info[eleType]['ibkg'], frac_ratio, cut, log) + #com = 'python KPsi2S_roofit_plb_modified_kde_fixedPartial.py -i {} -o psi2s_fixedPartial_{} --isgn={} --iKstarPsi2S_BKG={} --iKstarPlusPsi2S_BKG={} --iKstarJpsi_BKG={} --iKJpsiee_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarpsi2s,bkg_kstarjpsi,bkg_kstarpluspsi2s,bkg_kjpsi_ee,bkg_comb" --fit_primitive --partial_ratio={} --partial_ratio_kstarplus={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iKstarPsi2S_BKG'], info[eleType]['iKstarPlusPsi2S_BKG'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKJpsiee_BKG'], info[eleType]['ibkg'], frac_ratio, frac_ratio_kstarplus, cut, log) + com = 'python KPsi2S_roofit_plb_modified_kde_fixedPartial.py -i {} -o psi2s_fixedPartial_{} --isgn={} --iotherB={} --iKstarPsi2S_BKG={} --iKstarPlusPsi2S_BKG={} --iKstarJpsi_BKG={} --iKJpsiee_BKG={} --ibkg={} --sel_primitive="sgn,bkg_kstarpsi2s,bkg_kstarjpsi,bkg_kstarpluspsi2s,bkg_kjpsi_ee,bkg_comb,bkg_otherb" --fit_primitive --partial_ratio={} --partial_ratio_kstarplus={} --mvacut={} --log={}'.format(info[eleType]['inputfile'], eleType, info[eleType]['isgn'], info[eleType]['iotherB'], info[eleType]['iKstarPsi2S_BKG'], info[eleType]['iKstarPlusPsi2S_BKG'], info[eleType]['iKstarJpsi_BKG'], info[eleType]['iKJpsiee_BKG'], info[eleType]['ibkg'], frac_ratio, frac_ratio_kstarplus, cut, log) + + + + os.system(com) + + + diff --git a/helper.py b/helper.py deleted file mode 100644 index 39b58e9..0000000 --- a/helper.py +++ /dev/null @@ -1,27 +0,0 @@ -import numpy as np - -ELECTRON_MASS = 0.000511 -K_MASS = 0.493677 -PI_MASS = 0.139570 -NR_LOW = np.sqrt(1.1) -JPSI_MC = 3.08991 -JPSI_SIGMA_MC = 0.04205 -JPSI_LOW = np.sqrt(6.0) -JPSI_UP = JPSI_MC + 3.0*JPSI_SIGMA_MC -B_MC = 5.2694 -B_SIGMA_MC = 0.06187 -B_LOW = B_MC - 3.0*B_SIGMA_MC -B_UP = B_MC + 3.0*B_SIGMA_MC -B_SB_LOW = B_MC - 6.0*B_SIGMA_MC -B_SB_UP = B_MC + 6.0*B_SIGMA_MC -BLIND_LOW = B_LOW -BLIND_UP = B_UP -B_MIN = 4.5 -B_MAX = 6.0 -FIT_LOW = 4.7 -FIT_UP = 6.0 -D_MASS_CUT = 1.9 -BR_BToKJpsi = 1.01e-3 -BR_JpsiToLL = 0.0597 -BR_BToKLL = 4.51e-7 - diff --git a/makePlot_fitPeak_unbinned.py b/makePlot_fitPeak_unbinned.py deleted file mode 100644 index 9922054..0000000 --- a/makePlot_fitPeak_unbinned.py +++ /dev/null @@ -1,414 +0,0 @@ -#!/usr/bin/env python -import os -from time import sleep -import math -import ROOT -from ROOT import RooFit -import numpy as np -ROOT.gROOT.ProcessLine(open('models.cc').read()) -from ROOT import DoubleCBFast -from helper import * -ROOT.gErrorIgnoreLevel=ROOT.kError -ROOT.RooMsgService.instance().setGlobalKillBelow(RooFit.FATAL) - -def CMS_lumi(isMC): - mark = ROOT.TLatex() - mark.SetNDC() - lumistamp = '2018 (13 TeV)' - fontScale = 1.0 - cmsTextSize = 0.042 * fontScale * 1.25 - extraOverCmsTextSize = 0.76 - extraTextSize = extraOverCmsTextSize*cmsTextSize - - mark.SetTextAlign(11) - mark.SetTextSize(cmsTextSize) - mark.SetTextFont(61) - mark.DrawLatex(ROOT.gPad.GetLeftMargin(), 1 - (ROOT.gPad.GetTopMargin() - 0.017), "CMS") - mark.SetTextSize(0.042 * fontScale) - mark.SetTextFont(52) - mark.DrawLatex(ROOT.gPad.GetLeftMargin() + 0.09, 1 - (ROOT.gPad.GetTopMargin() - 0.017), "Simulation Preliminary" if isMC else "Preliminary") - mark.SetTextSize(extraTextSize) - mark.SetTextFont(42) - mark.SetTextAlign(31) - mark.DrawLatex(1 - ROOT.gPad.GetRightMargin(), 1 - (ROOT.gPad.GetTopMargin() - 0.017), lumistamp) - - -def fit(tree, outputfile, sigPDF=3, bkgPDF=2, fitJpsi=False, isMC=False, doPartial=False, partialinputfile='part_workspace.root', drawSNR=False, mvaCut=0.0, blinded=False, expS=100): - msgservice = ROOT.RooMsgService.instance() - msgservice.setGlobalKillBelow(RooFit.FATAL) - wspace = ROOT.RooWorkspace('myWorkSpace') - ROOT.gStyle.SetOptFit(0000); - ROOT.gROOT.SetBatch(True); - ROOT.gROOT.SetStyle("Plain"); - ROOT.gStyle.SetGridStyle(3); - ROOT.gStyle.SetOptStat(000000); - ROOT.gStyle.SetOptTitle(0) - - thevars = ROOT.RooArgSet() - - if fitJpsi: - xmin, xmax = 2.5, 3.5 - bMass = ROOT.RooRealVar("BToKEE_mll_fullfit", "m(e^{+}e^{-})", 2.0, 4.0, "GeV") - wspace.factory('mean[3.096916, 2.9, 3.3]') - - else: - bMass = ROOT.RooRealVar("BToKEE_fit_mass", "m(K^{+}e^{+}e^{-})", 4.0, 6.0, "GeV") - dieleMass = ROOT.RooRealVar("BToKEE_mll_fullfit", "m(e^{+}e^{-})", 2.0, 4.0, "GeV") - if isMC: - xmin, xmax = 4.5, 6.0 - wspace.factory('mean[5.272e+00, 5.22e+00, 5.3e+00]') - else: - xmin, xmax = FIT_LOW, FIT_UP - wspace.factory('mean[5.2694, 5.2694, 5.2694]') - #wspace.factory('mean[5.2681, 5.2681, 5.2681]') - thevars.add(dieleMass) - - thevars.add(bMass) - - fulldata = ROOT.RooDataSet('fulldata', 'fulldata', tree, ROOT.RooArgSet(thevars)) - theBMassfunc = ROOT.RooFormulaVar("x", "x", "@0", ROOT.RooArgList(bMass) ) - theBMass = fulldata.addColumn(theBMassfunc) ; - theBMass.setRange(xmin,xmax); - thevars.add(theBMass) - - cut = '' - - #print cut - data = fulldata.reduce(thevars, cut) - getattr(wspace,'import')(data, RooFit.Rename("data")) - - if not blinded: - wspace.factory('nsig[5000.0, 0.0, 1000000.0]') - else: - wspace.factory('nsig[{0}, {0}, {0}]'.format(expS)) - wspace.factory('nbkg[10000.0, 0.0, 1000000.0]') - wspace.factory('npartial[1000.0, 0.0, 100000.0]') - - if sigPDF == 0: - # Voigtian - wspace.factory('width[1.000e-02, 1.000e-04, 1.000e-01]') - wspace.factory('sigma[7.1858e-02, 1.e-3, 1.e-1]') - wspace.factory('Voigtian::sig(x,mean,width,sigma)') - - if sigPDF == 1: - # Gaussian - wspace.factory('sigma[7.1858e-02, 1.0e-3, 5.0e-1]') - wspace.factory('Gaussian::sig(x,mean,sigma)') - - if sigPDF == 2: - # Crystal-ball - wspace.factory('sigma[7.1858e-02, 1.0e-6, 5.0e-1]') - wspace.factory('alpha[1.0, 0.0, 10.0]') - wspace.factory('n[2, 1, 10]') - wspace.factory('CBShape::sig(x,mean,sigma,alpha,n)') - - if sigPDF == 3: - # Double-sided Crystal-ball - if isMC: - wspace.factory('width[4.1858e-02, 1.0e-6, 5.0e-1]') - wspace.factory('alpha1[1.0, 0.0, 10.0]') - wspace.factory('n1[1.0, 1.0, 10.0]') - wspace.factory('alpha2[1.0, 0.0, 10.0]') - wspace.factory('n2[1.0, 1.0, 10.0]') - else: - # PF - wspace.factory('width[0.06187, 0.06187, 0.06187]') - wspace.factory('alpha1[0.667, 0.667, 0.667]') - wspace.factory('n1[2.39, 2.39, 2.39]') - wspace.factory('alpha2[2.442, 2.442, 2.442]') - wspace.factory('n2[3.09, 3.09, 3.09]') - - # Mix - #wspace.factory('width[0.0561, 0.0561, 0.0561]') - #wspace.factory('alpha1[0.642, 0.642, 0.642]') - #wspace.factory('n1[2.31, 2.31, 2.31]') - #wspace.factory('alpha2[1.700, 1.700, 1.700]') - #wspace.factory('n2[10.0, 10.0, 10.0]') - - wspace.factory('GenericPdf::sig("DoubleCBFast(x,mean,width,alpha1,n1,alpha2,n2)", {x,mean,width,alpha1,n1,alpha2,n2})') - - if sigPDF == 4: - # Two Double-sided Crystal-ball - wspace.factory('width[7.1858e-02, 1.0e-6, 5.0e-1]') - wspace.factory('alpha1[1.0, 0.0, 10.0]') - wspace.factory('n1[2.0, 1.0, 10.0]') - wspace.factory('alpha2[1.0, 0.0, 10.0]') - wspace.factory('n2[2.0, 1.0, 10.0]') - wspace.factory('GenericPdf::cb("DoubleCBFast(x,mean,width,alpha1,n1,alpha2,n2)", {x,mean,width,alpha1,n1,alpha2,n2})') - wspace.factory('sigma[7.1858e-03, 1.0e-6, 5.0e-1]') - wspace.factory('Gaussian::gaus(x,mean,sigma)') - wspace.factory('f1[0.5, 0.0, 1.0]') - wspace.factory('SUM::sig(f1*cb, gaus)') - - if bkgPDF == 0: - # Polynomial - wspace.factory('c0[1.0, -1.0, 1.0]') - wspace.factory('c1[-0.1, -1.0, 1.0]') - wspace.factory('c2[-0.1, -1.0, 1.0]') - wspace.factory('Chebychev::bkg(x,{c0,c1,c2})') - - if bkgPDF == 1: - wspace.factory('c1[0.0, -100.0, 100.0]') - wspace.factory('Polynomial::bkg(x,{c1})') - - if bkgPDF == 2: - # Exponential - wspace.factory('exp_alpha[-3.0, -100.0, -1.0e-5]') - alpha = wspace.var('alpha') - wspace.factory('Exponential::bkg(x,exp_alpha)') - - if not isMC: - if doPartial: - wpf = ROOT.TFile(partialinputfile,"READ") - wp = wpf.Get("myPartialWorkSpace") - partial = wp.pdf("partial") - getattr(wspace, "import")(partial, RooFit.Rename("partial")) - wspace.factory('SUM::model1(f1[0.5,0.0,1.0]*partial,bkg)') - print('Finished loading KDE!') - wspace.factory('SUM::model(nsig*sig,nbkg*model1)') - - else: - wspace.factory('SUM::model(nsig*sig,nbkg*bkg)') - else: - wspace.factory('ExtendPdf::model(sig,nsig)') - - model = wspace.pdf('model') - bkg = wspace.pdf('model1') - sig = wspace.pdf('sig') - nsig = wspace.var('nsig') - nbkg = wspace.var('nbkg') - - # define the set obs = (x) - wspace.defineSet('obs', 'x') - - # make the set obs known to Python - obs = wspace.set('obs') - - theBMass.setRange("window",B_LOW,B_UP) - theBMass.setRange("SB1",FIT_LOW,BLIND_LOW) - theBMass.setRange("SB2",BLIND_UP,FIT_UP) - - ## fit the model to the data. - print('Fitting data...') - if not blinded: - results = model.fitTo(data, RooFit.Extended(True), RooFit.Save(), RooFit.Range(xmin,xmax), RooFit.PrintLevel(-1)) - else: - results = model.fitTo(data, RooFit.Extended(True), RooFit.Save(), RooFit.Range("SB1,SB2"), RooFit.PrintLevel(-1)) - - results.Print() - - if not isMC: - fracBkgRange = bkg.createIntegral(obs,obs,"window") ; - fracBkgRangeErr = fracBkgRange.getPropagatedError(results, obs) - nbkgWindow = nbkg.getVal() * fracBkgRange.getVal() - #print(nbkg.getVal(), fracBkgRange.getVal()) - #print(fracBkgRange.getVal(), fracBkgRange.getPropagatedError(results, obs)) - fb = fracBkgRange.getVal() - dfb = fracBkgRangeErr - nb = nbkg.getVal() - dnb = nbkg.getError() - #print(nb*fb*np.sqrt(pow(dfb/fb,2)+pow(dnb/nb,2))) - print("Number of signals: %f, Number of background: %f, S/sqrt(S+B): %f"%(nsig.getVal(), nbkgWindow, nsig.getVal()/np.sqrt(nsig.getVal() + nbkgWindow))) - else: - fracSigRange = sig.createIntegral(obs,obs,"window") ; - print(data.sumEntries(),fracSigRange.getVal()) - - # Plot results of fit on a different frame - c2 = ROOT.TCanvas('fig_binnedFit', 'fit', 800, 600) - c2.SetGrid() - c2.cd() - ROOT.gPad.SetLeftMargin(0.10) - ROOT.gPad.SetRightMargin(0.05) - - #xframe = wspace.var('x').frame(RooFit.Title("PF electron")) - xframe = theBMass.frame() - nbin_data = 30 if blinded else 50 - - if isMC: - data.plotOn(xframe, RooFit.Binning(nbin_data), RooFit.Name("data")) - model.plotOn(xframe,RooFit.Name("global"),RooFit.Range("Full"),RooFit.LineColor(2),RooFit.MoveToBack()) # this will show fit overlay on canvas - model.paramOn(xframe,RooFit.Layout(0.15,0.45,0.85)) - xframe.getAttText().SetTextSize(0.03) - - else: - if blinded: - nd = data.reduce('((BToKEE_fit_mass > {}) & (BToKEE_fit_mass < {})) | ((BToKEE_fit_mass > {}) & (BToKEE_fit_mass < {}))'.format(FIT_LOW, BLIND_LOW, BLIND_UP, FIT_UP)).sumEntries() / data.reduce('(BToKEE_fit_mass > {}) & (BToKEE_fit_mass < {})'.format(FIT_LOW, FIT_UP)).sumEntries() - data.plotOn(xframe, RooFit.Binning(nbin_data), RooFit.CutRange("SB1,SB2"), RooFit.Name("data")) - else: - nd = 1.0 - data.plotOn(xframe, RooFit.Binning(nbin_data), RooFit.Name("data")) - model.plotOn(xframe,RooFit.Name("global"),RooFit.Range("Full"),RooFit.Normalization(nd, ROOT.RooAbsReal.Relative),RooFit.LineColor(2),RooFit.MoveToBack()) # this will show fit overlay on canvas - model.plotOn(xframe,RooFit.Name("bkg"),RooFit.Components("bkg"),RooFit.Range("Full"),RooFit.Normalization(nd, ROOT.RooAbsReal.Relative),RooFit.DrawOption("F"),RooFit.VLines(),RooFit.FillColor(42),RooFit.LineColor(42),RooFit.LineWidth(1),RooFit.MoveToBack()) - if doPartial: - model.plotOn(xframe,RooFit.Name("partial"),RooFit.Components("bkg,partial"),RooFit.Range("Full"),RooFit.Normalization(nd, ROOT.RooAbsReal.Relative),RooFit.DrawOption("F"),RooFit.VLines(),RooFit.FillColor(40),RooFit.LineColor(40),RooFit.LineWidth(1),RooFit.MoveToBack()) ; - model.plotOn(xframe,RooFit.Name("sig"),RooFit.Components("sig"),RooFit.Range("Full"),RooFit.Normalization(nd, ROOT.RooAbsReal.Relative),RooFit.DrawOption("L"),RooFit.LineStyle(2),RooFit.LineColor(1)) ; - - - xframe.GetYaxis().SetTitleOffset(0.9) - xframe.GetYaxis().SetTitleFont(42) - xframe.GetYaxis().SetTitleSize(0.05) - xframe.GetYaxis().SetLabelSize(0.04) - xframe.GetYaxis().SetLabelFont(42) - xframe.GetXaxis().SetTitleOffset(0.9) - xframe.GetXaxis().SetTitleFont(42) - xframe.GetXaxis().SetTitleSize(0.05) - xframe.GetXaxis().SetLabelSize(0.04) - xframe.GetXaxis().SetLabelFont(42) - - xframe.GetYaxis().SetTitle("Events") - xframe.GetXaxis().SetTitle("m(e^{+}e^{-}) [GeV]" if fitJpsi else "m(K^{+}e^{+}e^{-}) [GeV]") - xframe.SetStats(0) - xframe.SetMinimum(0) - xframe.Draw() - - CMS_lumi(isMC) - - if isMC: - legend = ROOT.TLegend(0.65,0.75,0.92,0.85); - legend.AddEntry(xframe.findObject("global"),"Total Fit","l"); - pt = ROOT.TPaveText(0.72,0.38,0.92,0.50,"brNDC") - - else: - legend = ROOT.TLegend(0.60,0.65,0.92,0.85); - legend.AddEntry(xframe.findObject("bkg"),"Combinatorial","f"); - pt = ROOT.TPaveText(0.72,0.38,0.92,0.63,"brNDC") - if doPartial: - legend.AddEntry(xframe.findObject("partial"),"Partially Reco.","f"); - legend.AddEntry(xframe.findObject("sig"),"B^{+}#rightarrow K^{+} J/#psi(#rightarrow e^{+}e^{-})","l"); - - legend.SetTextFont(42); - legend.SetTextSize(0.04); - legend.AddEntry(xframe.findObject("data"),"Data","lpe"); - legend.Draw(); - - if drawSNR: - pt.SetFillColor(0) - pt.SetBorderSize(1) - pt.SetTextFont(42); - pt.SetTextSize(0.04); - pt.SetTextAlign(12) - pt.AddText("MVA cut: {0:.2f}".format(mvaCut)) - pt.AddText("S: {0:.0f}#pm{1:.0f}".format(nsig.getVal(),nsig.getError())) - if not isMC: - pt.AddText("B: {0:.0f}".format(nbkgWindow)) - pt.AddText("S/#sqrt{{S+B}}: {0:.1f}".format(nsig.getVal()/np.sqrt(nsig.getVal() + nbkgWindow))) - pt.Draw() - - - c2.cd() - c2.Update() - - c2.SaveAs(outputfile) - print("="*80) - if not isMC: - return nsig.getVal(), nsig.getError(), nbkgWindow - else: - return 0.0, 0.0, 0.0 - -def fit_kde(tree, outputfile, isMC=True): - #msgservice = ROOT.RooMsgService.instance() - #msgservice.setGlobalKillBelow(RooFit.FATAL) - wspace = ROOT.RooWorkspace('myPartialWorkSpace') - ROOT.gStyle.SetOptFit(0000); - #ROOT.gStyle.SetOptFit(1); - ROOT.gROOT.SetBatch(True); - ROOT.gROOT.SetStyle("Plain"); - ROOT.gStyle.SetGridStyle(3); - ROOT.gStyle.SetOptStat(000000); - ROOT.gStyle.SetOptTitle(0) - - xmin, xmax = 4.5, 6.0 - bMass = ROOT.RooRealVar("BToKEE_fit_mass", "m(K^{+}e^{+}e^{-})", 4.0, 6.0, "GeV") - - thevars = ROOT.RooArgSet() - thevars.add(bMass) - - fulldata = ROOT.RooDataSet('fulldata', 'fulldata', tree, ROOT.RooArgSet(thevars)) - theBMassfunc = ROOT.RooFormulaVar("x", "x", "@0", ROOT.RooArgList(bMass) ) - theBMass = fulldata.addColumn(theBMassfunc) ; - theBMass.setRange(xmin,xmax); - thevars.add(theBMass) - - cut = '' - print cut - data = fulldata.reduce(thevars, cut) - getattr(wspace,'import')(data, RooFit.Rename("data")) - - - # define the set obs = (x) - wspace.defineSet('obs', 'x') - - # make the set obs known to Python - obs = wspace.set('obs') - #wspace.factory('KeysPdf::partial(x,data,MirrorBoth,2.0)') - wspace.factory('KeysPdf::partial(x,data,MirrorLeft,2.0)') - model = wspace.pdf('partial') - - # Plot results of fit on a different frame - c2 = ROOT.TCanvas('fig_binnedFit', 'fit', 800, 600) - c2.SetGrid() - c2.cd() - ROOT.gPad.SetLeftMargin(0.10) - ROOT.gPad.SetRightMargin(0.05) - - #xframe = wspace.var('x').frame(RooFit.Title("PF electron")) - xframe = theBMass.frame() - data.plotOn(xframe, RooFit.Binning(50), RooFit.Name("data")) - model.plotOn(xframe,RooFit.Name("global"),RooFit.LineColor(2),RooFit.MoveToBack()) # this will show fit overlay on canvas - - xframe.GetYaxis().SetTitleOffset(0.9) - xframe.GetYaxis().SetTitleFont(42) - xframe.GetYaxis().SetTitleSize(0.05) - xframe.GetYaxis().SetLabelSize(0.04) - xframe.GetYaxis().SetLabelFont(42) - xframe.GetXaxis().SetTitleOffset(0.9) - xframe.GetXaxis().SetTitleFont(42) - xframe.GetXaxis().SetTitleSize(0.05) - xframe.GetXaxis().SetLabelSize(0.04) - xframe.GetXaxis().SetLabelFont(42) - - xframe.GetYaxis().SetTitle("Events") - xframe.GetXaxis().SetTitle("m(K^{+}e^{+}e^{-}) [GeV]") - xframe.SetStats(0) - xframe.SetMinimum(0) - xframe.Draw() - - CMS_lumi(isMC) - - legend = ROOT.TLegend(0.65,0.75,0.92,0.85); - #legend = ROOT.TLegend(0.65,0.15,0.92,0.35); - legend.SetTextFont(72); - legend.SetTextSize(0.04); - legend.AddEntry(xframe.findObject("data"),"Data","lpe"); - legend.AddEntry(xframe.findObject("global"),"Global Fit","l"); - legend.Draw(); - - c2.cd() - c2.Update() - - c2.SaveAs(outputfile.replace('.root','')+'.pdf') - #wf = ROOT.TFile("part_workspace.root", "RECREATE") - wf = ROOT.TFile(outputfile.replace('.root','')+'.root', "RECREATE") - wspace.Write() - wf.Close() - - print("="*80) - -if __name__ == "__main__": - import argparse - parser = argparse.ArgumentParser(description='Unbinned likelihood fit') - parser.add_argument("-i", "--inputfile", dest="inputfile", default="", help="Input file") - parser.add_argument("-o", "--outputfile", dest="outputfile", default="", help="Output file") - parser.add_argument("-p", "--partial", dest="partial", action="store_true", help="Fit partially reconstructed background") - args = parser.parse_args() - - tree = ROOT.TChain('tree') - tree.AddFile(args.inputfile) - if not args.partial: - fit(tree, args.outputfile, fitJpsi=False, isMC=True) - #fit(tree, args.outputfile, doPartial=True) - #fit(tree, args.outputfile, doPartial=True, drawSNR=True, mvaCut=2.0) - else: - fit_kde(tree, args.outputfile) - - diff --git a/measurement/helper.py b/measurement/helper.py new file mode 100644 index 0000000..6d7bda3 --- /dev/null +++ b/measurement/helper.py @@ -0,0 +1,118 @@ +import numpy as np +import uproot +import pandas as pd +import ROOT + +ELECTRON_MASS = 0.000511 +K_MASS = 0.493677 +PI_MASS = 0.139570 +NR_LOW = np.sqrt(0.045) +JPSI_MC = 3.08991 +JPSI_SIGMA_MC = 0.04205 +JPSI_LOW = np.sqrt(6.5) +JPSI_UP = 3.25 +PSI2S_UP = 3.85 +NR_UP = np.sqrt(25.0) +PHI_SIGMA_MC = 0.0026836 +PHI_LOW = 1.01957 - 4.0*PHI_SIGMA_MC +PHI_UP = 1.01957 + 4.0*PHI_SIGMA_MC +B_MC = 5.2676 +B_SIGMA_MC = 0.06070 +B_LOW = 5.05 +B_UP = 5.45 +BS_LOW = 5.15 +BS_UP = 5.55 +B_SB_LOW = B_MC - 6.0*B_SIGMA_MC +B_SB_UP = B_MC + 6.0*B_SIGMA_MC +BLIND_LOW = B_LOW +BLIND_UP = B_UP +B_FOM_LOW = 5.05 +B_FOM_UP = 5.45 +B_MIN = 4.5 +B_MAX = 6.0 +FIT_LOW = 4.7 +FIT_UP = 6.0 +D_MASS_CUT = 1.9 +BR_BToKJpsi = 1.01e-3 +BR_JpsiToLL = 0.0597 +BR_BToKLL = 4.51e-7 +BR_BToPhiJpsi = 1.08e-3 +BR_PhiToKK = 0.492 +BR_BToPhiLL = 8.2e-7 + +params_jpsitri_pf = {'mean': 5.2671, 'width': 0.0637, 'alpha1': 0.683, 'n1': 2.02, 'alpha2': 1.692, 'n2': 10.0} +params_jpsi_pf = {'mean': 5.2676, 'width': 0.06070, 'alpha1': 0.677, 'n1': 1.56, 'alpha2': 1.440, 'n2': 8.9} +params_jpsi_mix = {'mean': 5.2660, 'width': 0.0636, 'alpha1': 0.60, 'n1': 2.20, 'alpha2': 1.387, 'n2': 20.0} +params_jpsi_low = {'mean': 5.2654, 'width': 0.0638, 'alpha1': 0.655, 'n1': 1.75, 'alpha2': 1.509, 'n2': 9.85} +params_psi2stri_pf = {'mean': 5.2628, 'width': 0.0753, 'alpha1': 0.642, 'n1': 10.0, 'alpha2': 4.6, 'n2': 6.4} +params_psi2s_pf = {'mean': 5.2646, 'width': 0.0726, 'alpha1': 0.591, 'n1': 10.0, 'alpha2': 1.87, 'n2': 10.0} +params_psi2s_mix = {'mean': 5.2544, 'width': 0.0838, 'alpha1': 0.577, 'n1': 20, 'alpha2': 9.93, 'n2': 9.7} +params_psi2s_low = {'mean': 5.25464, 'width': 0.0822, 'alpha1': 0.642, 'n1': 9.76, 'alpha2': 6.0, 'n2': 2.94} +params_jpsi_cutbased_pf = {'mean': 5.2621, 'width': 0.0658, 'alpha1': 0.945, 'n1': 1.065, 'alpha2': 1.59704, 'n2': 9.962} + +params_rphi_jpsi_pf = {'mean': 5.35897, 'width': 0.05558, 'alpha1': 0.5363, 'n1': 2.76, 'alpha2': 1.269, 'n2': 20} +params_rphi_jpsi_low = {'mean': 5.3546, 'width': 0.0609, 'alpha1': 0.560, 'n1': 2.98, 'alpha2': 1.400, 'n2': 20} + +triCut_jpsi_mll_mean_pf = 3.00233244896 +triCut_jpsi_mKee_mean_pf = 5.17609024048 +triCut_jpsi_rotMatrix_pf = np.array([[0.74743241, -0.66433786], [0.66433786, 0.74743241]]) +triCut_jpsi_lower_bound_pf = -0.0977517530843 +triCut_jpsi_upper_bound_pf = 0.0824238599635 + +triCut_psi2s_mll_mean_pf = 3.58506560326 +triCut_psi2s_mKee_mean_pf = 5.17640161514 +triCut_psi2s_rotMatrix_pf = np.array([[0.72047561, -0.69348028], [0.69348028, 0.72047561]]) +triCut_psi2s_lower_bound_pf = -0.0704979038994 +triCut_psi2s_upper_bound_pf = 0.059937465045 + +def Punzi(B, a, b): + return (b*b)/2.0 + a*np.sqrt(B) + (b/2.0)*np.sqrt(b*b + 4.0*a*np.sqrt(B) + 4.0*B) + +def Punzi_simplify(eff, B, dB, a): + return eff / ((a/2.0) + np.sqrt(B + dB*dB)) + +def Significance(S, B, dB): + return S / np.sqrt(S + B + dB*dB) + +def get_df(root_file_name, tree='tree', branches=['*']): + print('Opening file {}...'.format(root_file_name)) + f = uproot.open(root_file_name) + if len(f.allkeys()) == 0: + return pd.DataFrame() + print('Not an null file') + #df = uproot.open(root_file_name)["tree"].pandas.df() + #df = pd.DataFrame(uproot.open(root_file_name)["tree"].arrays(namedecode="utf-8")) + df = pd.DataFrame(f[tree].arrays(branches=branches)) + print('Finished opening file {}...'.format(root_file_name)) + return df + +def get_diagonalCut_var(branches, mll_mean, fit_mass_mean, diagCut_lower_bound, diagCut_jpsi_upper_bound, eigVecs): + branches['BToKEE_mll_fullfit_centered'] = branches['BToKEE_mll_fullfit'] - mll_mean + branches['BToKEE_fit_mass_centered'] = branches['BToKEE_fit_mass'] - fit_mass_mean + data_centered = np.array([branches['BToKEE_fit_mass_centered'],branches['BToKEE_mll_fullfit_centered']]).T + eigVecs_jpsi = triCut_jpsi_rotMatrix_pf + data_decorr = data_centered.dot(eigVecs) + return data_decorr[:,0], data_decorr[:,1] + +def CMS_lumi(isMC): + mark = ROOT.TLatex() + mark.SetNDC() + lumistamp = '2018 (13 TeV)' + fontScale = 1.0 + cmsTextSize = 0.042 * fontScale * 1.25 + extraOverCmsTextSize = 0.76 + extraTextSize = extraOverCmsTextSize*cmsTextSize + + mark.SetTextAlign(11) + mark.SetTextSize(cmsTextSize) + mark.SetTextFont(61) + mark.DrawLatex(ROOT.gPad.GetLeftMargin(), 1 - (ROOT.gPad.GetTopMargin() - 0.017), "CMS") + mark.SetTextSize(0.042 * fontScale) + mark.SetTextFont(52) + mark.DrawLatex(ROOT.gPad.GetLeftMargin() + 0.09, 1 - (ROOT.gPad.GetTopMargin() - 0.017), "Simulation Preliminary" if isMC else "Preliminary") + mark.SetTextSize(extraTextSize) + mark.SetTextFont(42) + mark.SetTextAlign(31) + mark.DrawLatex(1 - ROOT.gPad.GetRightMargin(), 1 - (ROOT.gPad.GetTopMargin() - 0.017), lumistamp) + + diff --git a/measurement/maximum_likelihood_rjpsi_combinedEleCh_effRatio.py b/measurement/maximum_likelihood_rjpsi_combinedEleCh_effRatio.py new file mode 100644 index 0000000..381d2fb --- /dev/null +++ b/measurement/maximum_likelihood_rjpsi_combinedEleCh_effRatio.py @@ -0,0 +1,218 @@ +import os,sys,re +import time +from time import sleep +import math +from uncertainties import ufloat +import ROOT as rt +import ROOT +from ROOT import RooFit +from roofit_models import root_function_DoubleSidedCB +ROOT.gInterpreter.Declare(root_function_DoubleSidedCB) +from roofit_models import root_function_RightSidedCB +ROOT.gInterpreter.Declare(root_function_RightSidedCB) +rt.gROOT.SetBatch(True); +rt.gROOT.SetStyle("Plain"); +from utils_likelihood import analyzeWorkspace, plot_likelihood, importWorkspace + +def createWorkspace(wsname, wsfilename, + wsfilename_pfe_jpsi, + wsfilename_mixe_jpsi, + wsfilename_mu_jpsi, + eff_pfe_to_mu_jpsi=0.0, deff_pfe_to_mu_jpsi=0.0, + eff_mixe_to_mu_jpsi=0.0, deff_mixe_to_mu_jpsi=0.0, + ): + + wspace = rt.RooWorkspace(wsname) + wspace = importWorkspace(wspace, wsfilename_pfe_jpsi, 'pfe_jpsi') + wspace = importWorkspace(wspace, wsfilename_mixe_jpsi, 'mixe_jpsi') + wspace = importWorkspace(wspace, wsfilename_mu_jpsi, 'mu_jpsi') + + wspace.factory('cat[pfe_jpsi,mixe_jpsi,mu_jpsi]') + x = wspace.var("x") + data = rt.RooDataSet('data', 'data', rt.RooArgSet(x), RooFit.Index(wspace.cat('cat')), + RooFit.Import('pfe_jpsi', wspace.data('data_pfe_jpsi')), + RooFit.Import('mixe_jpsi', wspace.data('data_mixe_jpsi')), + RooFit.Import('mu_jpsi', wspace.data('data_mu_jpsi')), + ) + getattr(wspace, 'import')(data, rt.RooCmdArg()) + + br_jpsi_ee, dbr_jpsi_ee= 0.05971, 0.00032 + br_psi2s_ee, dbr_psi2s_ee = 7.93e-3, 0.17e-3 + br_jpsi_mumu, dbr_jpsi_mumu= 0.05961, 0.00033 + br_psi2s_mumu, dbr_psi2s_mumu = 8.0e-3, 0.6e-3 + r_br, dr_br = 0.6117647, 0.022678 + + ### Create parameters + # observations + params = [ + # efficiency of PF-PF electron J/psi channel estimate + ('eff_hat_pfe_to_mu_jpsi', eff_pfe_to_mu_jpsi, 1.e-6, 1), + ('deff_pfe_to_mu_jpsi', deff_pfe_to_mu_jpsi, 1.e-6, 1), + # efficiency of PF-LP electron J/psi channel estimate + ('eff_hat_mixe_to_mu_jpsi', eff_mixe_to_mu_jpsi, 1.e-6, 1), + ('deff_mixe_to_mu_jpsi', deff_mixe_to_mu_jpsi, 1.e-6, 1), + # nuisance parameters + #('eff_pfe_to_mu_jpsi', eff_pfe_to_mu_jpsi, eff_pfe_to_mu_jpsi-5.0*deff_pfe_to_mu_jpsi, eff_pfe_to_mu_jpsi+5.0*deff_pfe_to_mu_jpsi), + #('eff_mixe_to_mu_jpsi', eff_mixe_to_mu_jpsi, eff_mixe_to_mu_jpsi-5.0*deff_mixe_to_mu_jpsi, eff_mixe_to_mu_jpsi+5.0*deff_mixe_to_mu_jpsi), + ('eff_pfe_to_mu_jpsi', eff_pfe_to_mu_jpsi, eff_pfe_to_mu_jpsi-5.0*deff_pfe_to_mu_jpsi, 1), + ('eff_mixe_to_mu_jpsi', eff_mixe_to_mu_jpsi, eff_mixe_to_mu_jpsi-5.0*deff_mixe_to_mu_jpsi, 1), + ('n_mu_jpsi', 7.7399e+05, 0, 10000000), + # parameter of interest + ('R', 1.00, 0.5, 1.5), + ] + + for t in params: + cmd = '%s[%f, %f, %f]' % t + wspace.factory(cmd) + wspace.var('R').SetTitle('R') + + # fix all background and signal parameters + for t in params[0:-4]: + name = t[0] + print '=> make %8s = %5.5f constant' % (name, + wspace.var(name).getVal()) + wspace.var(name).setConstant() + + wspace.var('ncomb_mixe_jpsi').setConstant() + wspace.var('ncomb_pfe_jpsi').setConstant() + wspace.var('ncomb_mu_jpsi').setConstant() + #wspace.var('notherB_pfe_jpsi').setConstant() + #wspace.var('notherB_mixe_jpsi').setConstant() + + + ### Create expressions + express = [ + # PF-PF electron + 'n_pfe_jpsi("(n_mu_jpsi/R)*(eff_pfe_to_mu_jpsi)", n_mu_jpsi, R, eff_pfe_to_mu_jpsi)', + 'nKstarJpsi_pfe_jpsi_modified("frac_partial_pfe_jpsi*n_pfe_jpsi", frac_partial_pfe_jpsi, n_pfe_jpsi)', + 'nKstarPlusJpsi_pfe_jpsi_modified("frac_kstarplus_pfe_jpsi*nKstarJpsi_pfe_jpsi_modified", frac_kstarplus_pfe_jpsi, nKstarJpsi_pfe_jpsi_modified)', + # PF-LP electron + 'n_mixe_jpsi("(n_mu_jpsi/R)*(eff_mixe_to_mu_jpsi)", n_mu_jpsi, R, eff_mixe_to_mu_jpsi)', + 'nKstarJpsi_mixe_jpsi_modified("frac_partial_mixe_jpsi*n_mixe_jpsi", frac_partial_mixe_jpsi, n_mixe_jpsi)', + 'nKstarPlusJpsi_mixe_jpsi_modified("frac_kstarplus_mixe_jpsi*nKstarJpsi_mixe_jpsi_modified", frac_kstarplus_mixe_jpsi, nKstarJpsi_mixe_jpsi_modified)', + ] + + for t in express: + cmd = 'expr::%s' % t + wspace.factory(cmd) + + edit = [ + # PF-PF electron + 'model_pfe_jpsi_modified(model_pfe_jpsi, nsignal_pfe_jpsi=n_pfe_jpsi, nKstarJpsi_pfe_jpsi=nKstarJpsi_pfe_jpsi_modified, nKstarPlusJpsi_pfe_jpsi=nKstarPlusJpsi_pfe_jpsi_modified)', + # PF-LP electron + 'model_mixe_jpsi_modified(model_mixe_jpsi, nsignal_mixe_jpsi=n_mixe_jpsi, nKstarJpsi_mixe_jpsi=nKstarJpsi_mixe_jpsi_modified, nKstarPlusJpsi_mixe_jpsi=nKstarPlusJpsi_mixe_jpsi_modified)', + # muon + 'model_mu_jpsi_modified(model_mu_jpsi, nsignal_mu_jpsi=n_mu_jpsi)', + ] + + for t in edit: + cmd = 'EDIT::%s' % t + wspace.factory(cmd) + + wspace.Print("V") + ### Create pdfs + pdfs = [ + # PF-PF electron + ('Gaussian','peff_pfe_to_mu_jpsi', '(eff_hat_pfe_to_mu_jpsi, eff_pfe_to_mu_jpsi, deff_pfe_to_mu_jpsi)'), + # PF-LP electron + ('Gaussian','peff_mixe_to_mu_jpsi', '(eff_hat_mixe_to_mu_jpsi, eff_mixe_to_mu_jpsi, deff_mixe_to_mu_jpsi)'), + ] + + prodpdf = '' + for t in pdfs: + wspace.factory('%s::%s%s' % t) + name = t[1] + prodpdf += "%s, " % name + prodpdf = prodpdf[:-2] # remove last ", " + + + # multiply the pdfs together. use upper case PROD to + # do this + wspace.factory("SIMUL:jointModel(cat,pfe_jpsi=model_pfe_jpsi_modified,mixe_jpsi=model_mixe_jpsi_modified,mu_jpsi=model_mu_jpsi_modified)") + wspace.factory('PROD::model({},{})'.format(prodpdf, 'jointModel')) + + nuis_excluded = ['x', 'R', 'cat', + 'deff_pfe_to_mu_jpsi', 'eff_hat_pfe_to_mu_jpsi', + 'deff_mixe_to_mu_jpsi', 'eff_hat_mixe_to_mu_jpsi', + ] + + ### Define global observables + ### they are not being fitted and they are not loaded from a dataset, + ### but some knowledge exists that allows to set them to a specific value + ### Global Observables are generated once per toy + #globs = ['eff_pfe_to_mu_jpsi', 'eff_mixe_to_mu_jpsi' + globs = ['eff_hat_pfe_to_mu_jpsi', 'eff_hat_mixe_to_mu_jpsi' + ] + + nuis = [] + params = wspace.pdf('model').getVariables() + params_iter = params.createIterator() + param = params_iter.Next() + while param : + if param.GetName() not in (nuis_excluded+globs): + nuis.append(param.GetName()) + param = params_iter.Next() + nuis = ','.join(nuis) + globs = ','.join(globs) + + sets = [('obs', 'x'), # observations + ('poi', 'R'), # parameter of interest + ('nuis', nuis), + ('globs', globs), + ] # nuisance parameters (leave no spaces) + #('nuis', 'n_pfe_jpsi,eff_pfe_psi2s,eff_pfe_jpsi')] # nuisance parameters (leave no spaces) + + for t in sets: + name, parlist = t + wspace.defineSet(name, parlist) + + + #----------------------------------------------------- + # Create model configuration. This is needed for the + # statistical analyses + #----------------------------------------------------- + cfg = rt.RooStats.ModelConfig('cfg') + cfg.SetWorkspace(wspace) + cfg.SetPdf(wspace.pdf('model')) + cfg.SetParametersOfInterest(wspace.set('poi')) + cfg.SetNuisanceParameters(wspace.set('nuis')) + #cfg.SetGlobalObservables(wspace.set('globs')) + + # import model configuration into workspace + getattr(wspace, 'import')(cfg) + + wspace.Print() + + # write out workspace + wspace.writeToFile(wsfilename) + + +if __name__ == "__main__": + + eff_pfe_jpsi, deff_pfe_jpsi = 5.3779e-6, 2.90e-7 + eff_mixe_jpsi, deff_mixe_jpsi = 2.3538e-6, 1.28e-7 + eff_mu_jpsi, deff_mu_jpsi = 12.69e-4, 0.1e-4 + R_SM = 1.0 + R_min, R_max = 0.88, 1.2 + xlabel = 'R_{J/#psi}' + + wsfilename_pfe_jpsi = 'wspace_jpsi_fixedPartial_pf_wp8.3_HLT_Mu9_IP6.root' + wsfilename_mixe_jpsi = 'wspace_jpsi_fixedPartial_mix_wp8.6_HLT_Mu9_IP6.root' + wsfilename_mu_jpsi = 'wspace_jpsi_muon.root' + wsfilename = 'wspace_rjpsi_combinedEleCh.root' + + u_eff_pfe_jpsi = ufloat(eff_pfe_jpsi, deff_pfe_jpsi) + u_eff_mixe_jpsi = ufloat(eff_mixe_jpsi, deff_mixe_jpsi) + u_eff_mu_jpsi = ufloat(eff_mu_jpsi, deff_mu_jpsi) + u_eff_pfe_to_mu_jpsi = u_eff_pfe_jpsi / u_eff_mu_jpsi + u_eff_mixe_to_mu_jpsi = u_eff_mixe_jpsi / u_eff_mu_jpsi + print(u_eff_pfe_to_mu_jpsi, u_eff_mixe_to_mu_jpsi) + print(u_eff_pfe_to_mu_jpsi.n, u_eff_pfe_to_mu_jpsi.s, u_eff_mixe_to_mu_jpsi.n, u_eff_mixe_to_mu_jpsi.s) + + createWorkspace('R_jpsi', wsfilename, wsfilename_pfe_jpsi, wsfilename_mixe_jpsi, wsfilename_mu_jpsi, + eff_pfe_to_mu_jpsi=u_eff_pfe_to_mu_jpsi.n, deff_pfe_to_mu_jpsi=u_eff_pfe_to_mu_jpsi.s, + eff_mixe_to_mu_jpsi=u_eff_mixe_to_mu_jpsi.n, deff_mixe_to_mu_jpsi=u_eff_mixe_to_mu_jpsi.s, + ) + plccanvas = analyzeWorkspace('R_jpsi', wsfilename, x_SM=R_SM, x_min=R_min, x_max=R_max, xlabel=xlabel, plot=True, unbinned=False, NPoints=50) + + diff --git a/measurement/maximum_likelihood_rpsi2s.py b/measurement/maximum_likelihood_rpsi2s.py new file mode 100644 index 0000000..2429fd9 --- /dev/null +++ b/measurement/maximum_likelihood_rpsi2s.py @@ -0,0 +1,219 @@ +import os,sys,re +from time import sleep +import math +import ROOT as rt +from ROOT import RooFit +rt.gROOT.SetBatch(True); +rt.gROOT.SetStyle("Plain"); +from utils_likelihood import analyzeWorkspace, plot_likelihood, importWorkspace + +def createWorkspace(wsname, wsfilename, wsfilename_ele_psi2s, wsfilename_ele_jpsi, wsfilename_mu_psi2s, wsfilename_mu_jpsi, + eff_ele_psi2s=0.0, deff_ele_psi2s=0.0, eff_ele_jpsi=0.0, deff_ele_jpsi=0.0, + eff_mu_psi2s=0.0, deff_mu_psi2s=0.0, eff_mu_jpsi=0.0, deff_mu_jpsi=0.0, + ): + + wspace = rt.RooWorkspace(wsname) + wspace = importWorkspace(wspace, wsfilename_ele_psi2s, 'ele_psi2s') + wspace = importWorkspace(wspace, wsfilename_ele_jpsi, 'ele_jpsi') + wspace = importWorkspace(wspace, wsfilename_mu_psi2s, 'mu_psi2s') + wspace = importWorkspace(wspace, wsfilename_mu_jpsi, 'mu_jpsi') + + wspace.factory('cat[ele_psi2s,ele_jpsi,mu_psi2s,mu_jpsi]') + x = wspace.var("x") + data = rt.RooDataSet('data', 'data', rt.RooArgSet(x), RooFit.Index(wspace.cat('cat')), + RooFit.Import('ele_psi2s', wspace.data('data_ele_psi2s')), RooFit.Import('ele_jpsi', wspace.data('data_ele_jpsi')), + RooFit.Import('mu_psi2s', wspace.data('data_mu_psi2s')), RooFit.Import('mu_jpsi', wspace.data('data_mu_jpsi')), + ) + getattr(wspace, 'import')(data, rt.RooCmdArg()) + + br_jpsi_ee, dbr_jpsi_ee= 0.05971, 0.00032 + br_psi2s_ee, dbr_psi2s_ee = 7.93e-3, 0.17e-3 + br_jpsi_mumu, dbr_jpsi_mumu= 0.05961, 0.00033 + br_psi2s_mumu, dbr_psi2s_mumu = 8.0e-3, 0.6e-3 + + + ### Create parameters + # observations + params = [ + # efficiency of electron psi(2S) estimate + ('eff_hat_ele_psi2s', eff_ele_psi2s, 1.e-6, 1), + ('deff_ele_psi2s', deff_ele_psi2s, 1.e-6, 1), + # efficiency of electron J/psi channel estimate + ('eff_hat_ele_jpsi', eff_ele_jpsi, 1.e-6, 1), + ('deff_ele_jpsi', deff_ele_jpsi, 1.e-6, 1), + # branching fraction of J/psi -> ee + ('br_hat_jpsi_ee', br_jpsi_ee, 1.e-6, 1), + ('dbr_jpsi_ee', dbr_jpsi_ee, 1.e-6, 1), + # branching fraction of psi(2S) -> ee + ('br_hat_psi2s_ee', br_psi2s_ee, 1.e-6, 1), + ('dbr_psi2s_ee', dbr_psi2s_ee, 1.e-6, 1), + # efficiency of muon psi(2S) estimate + ('eff_hat_mu_psi2s', eff_mu_psi2s, 1.e-6, 1), + ('deff_mu_psi2s', deff_mu_psi2s, 1.e-6, 1), + # efficiency of muon J/psi channel estimate + ('eff_hat_mu_jpsi', eff_mu_jpsi, 1.e-6, 1), + ('deff_mu_jpsi', deff_mu_jpsi, 1.e-6, 1), + # branching fraction of J/psi -> mu mu + ('br_hat_jpsi_mumu', br_jpsi_mumu, 1.e-6, 1), + ('dbr_jpsi_mumu', dbr_jpsi_mumu, 1.e-6, 1), + # branching fraction of psi(2S) -> mu mu + ('br_hat_psi2s_mumu', br_psi2s_mumu, 1.e-6, 1), + ('dbr_psi2s_mumu', dbr_psi2s_mumu, 1.e-6, 1), + # nuisance parameters + ('n_ele_jpsi', 9117, 8000, 11000), + ('eff_ele_psi2s', eff_ele_psi2s, eff_ele_psi2s-5.0*deff_ele_psi2s, eff_ele_psi2s+5.0*deff_ele_psi2s), + ('eff_ele_jpsi', eff_ele_jpsi, eff_ele_jpsi-5.0*deff_ele_jpsi, eff_ele_jpsi+5.0*deff_ele_jpsi), + ('br_psi2s_ee', br_psi2s_ee, br_psi2s_ee-5.0*dbr_psi2s_ee, br_psi2s_ee+5.0*dbr_psi2s_ee), + ('br_jpsi_ee', br_jpsi_ee, br_jpsi_ee-5.0*dbr_jpsi_ee, br_jpsi_ee+5.0*dbr_jpsi_ee), + ('n_mu_jpsi', 9117, 8000, 11000), + ('eff_mu_psi2s', eff_mu_psi2s, eff_mu_psi2s-5.0*deff_mu_psi2s, eff_mu_psi2s+5.0*deff_mu_psi2s), + ('eff_mu_jpsi', eff_mu_jpsi, eff_mu_jpsi-5.0*deff_mu_jpsi, eff_mu_jpsi+5.0*deff_mu_jpsi), + ('br_psi2s_mumu', br_psi2s_mumu, br_psi2s_mumu-5.0*dbr_psi2s_mumu, br_psi2s_mumu+5.0*dbr_psi2s_mumu), + ('br_jpsi_mumu', br_jpsi_mumu, br_jpsi_mumu-5.0*dbr_jpsi_mumu, br_jpsi_mumu+5.0*dbr_jpsi_mumu), + # parameter of interest + ('r_br', 0.8, 0.3, 1.5), + ('R', 1.0, 0.5, 1.5), + ] + + for t in params: + cmd = '%s[%f, %f, %f]' % t + wspace.factory(cmd) + wspace.var('R').SetTitle('R') + + # fix all background and signal parameters + for t in params[0:-12]: + name = t[0] + print '=> make %8s = %5.5f constant' % (name, + wspace.var(name).getVal()) + wspace.var(name).setConstant() + + ### Create expressions + express = ['n_ele_psi2s("(r_br/R)*n_ele_jpsi*(br_psi2s_ee/br_jpsi_ee)*(eff_ele_psi2s/eff_ele_jpsi)", r_br, R, n_ele_jpsi, br_psi2s_ee, br_jpsi_ee, eff_ele_psi2s, eff_ele_jpsi)', + 'nKstarPsi2S_ele_psi2s_modified("frac_partial_ele_psi2s*n_ele_psi2s", frac_partial_ele_psi2s, n_ele_psi2s)', + 'nKstarJpsi_ele_jpsi_modified("frac_partial_ele_jpsi*n_ele_jpsi", frac_partial_ele_jpsi, n_ele_jpsi)', + 'n_mu_psi2s("r_br*n_mu_jpsi*(br_psi2s_mumu/br_jpsi_mumu)*(eff_mu_psi2s/eff_mu_jpsi)", r_br, n_mu_jpsi, br_psi2s_mumu, br_jpsi_mumu, eff_mu_psi2s, eff_mu_jpsi)', + 'nKstarPsi2S_mu_psi2s_modified("frac_partial_mu_psi2s*n_mu_psi2s", frac_partial_mu_psi2s, n_mu_psi2s)', + 'nKstarJpsi_mu_jpsi_modified("frac_partial_mu_jpsi*n_mu_jpsi", frac_partial_mu_jpsi, n_mu_jpsi)', + ] + + for t in express: + cmd = 'expr::%s' % t + wspace.factory(cmd) + + edit = ['model_ele_psi2s_modified(model_ele_psi2s, nsignal_ele_psi2s=n_ele_psi2s, nKstarPsi2S_ele_psi2s=nKstarPsi2S_ele_psi2s_modified)', + 'model_ele_jpsi_modified(model_ele_jpsi, nsignal_ele_jpsi=n_ele_jpsi, nKstarJpsi_ele_jpsi=nKstarJpsi_ele_jpsi_modified)', + 'model_mu_psi2s_modified(model_mu_psi2s, nsignal_mu_psi2s=n_mu_psi2s, nKstarPsi2S_mu_psi2s=nKstarPsi2S_mu_psi2s_modified)', + 'model_mu_jpsi_modified(model_mu_jpsi, nsignal_mu_jpsi=n_mu_jpsi, nKstarJpsi_mu_jpsi=nKstarJpsi_mu_jpsi_modified)', + ] + + for t in edit: + cmd = 'EDIT::%s' % t + wspace.factory(cmd) + + wspace.Print("V") + ### Create pdfs + pdfs = [('Gaussian','peff_ele_psi2s', '(eff_hat_ele_psi2s, eff_ele_psi2s, deff_ele_psi2s)'), + ('Gaussian','peff_ele_jpsi', '(eff_hat_ele_jpsi, eff_ele_jpsi, deff_ele_jpsi)'), + ('Gaussian','peff_br_psi2s_ee', '(br_hat_psi2s_ee, br_psi2s_ee, dbr_psi2s_ee)'), + ('Gaussian','peff_br_jpsi_ee', '(br_hat_jpsi_ee, br_jpsi_ee, dbr_jpsi_ee)'), + ('Gaussian','peff_mu_psi2s', '(eff_hat_mu_psi2s, eff_mu_psi2s, deff_mu_psi2s)'), + ('Gaussian','peff_mu_jpsi', '(eff_hat_mu_jpsi, eff_mu_jpsi, deff_mu_jpsi)'), + ('Gaussian','peff_br_psi2s_mumu', '(br_hat_psi2s_mumu, br_psi2s_mumu, dbr_psi2s_mumu)'), + ('Gaussian','peff_br_jpsi_mumu', '(br_hat_jpsi_mumu, br_jpsi_mumu, dbr_jpsi_mumu)'), + ] + + prodpdf = '' + for t in pdfs: + wspace.factory('%s::%s%s' % t) + name = t[1] + prodpdf += "%s, " % name + prodpdf = prodpdf[:-2] # remove last ", " + + + # multiply the pdfs together. use upper case PROD to + # do this + wspace.factory("SIMUL:jointModel(cat,ele_psi2s=model_ele_psi2s_modified,ele_jpsi=model_ele_jpsi_modified,mu_psi2s=model_mu_psi2s_modified,mu_jpsi=model_mu_jpsi_modified)") + wspace.factory('PROD::model({},{})'.format(prodpdf, 'jointModel')) + + nuis_excluded = ['x', 'R', 'cat', + 'deff_ele_jpsi', 'deff_ele_psi2s', 'eff_hat_ele_jpsi', 'eff_hat_ele_psi2s', + 'dbr_jpsi_ee', 'dbr_psi2s_ee', 'br_hat_jpsi_ee', 'br_hat_psi2s_ee' + 'deff_mu_jpsi', 'deff_mu_psi2s', 'eff_hat_mu_jpsi', 'eff_hat_mu_psi2s', + 'dbr_jpsi_mumu', 'dbr_psi2s_mumu', 'br_hat_jpsi_mumu', 'br_hat_psi2s_mumu' + ] + + ### Define global observables + ### they are not being fitted and they are not loaded from a dataset, + ### but some knowledge exists that allows to set them to a specific value + ### Global Observables are generated once per toy + globs = ['eff_ele_psi2s', 'eff_ele_jpsi', 'br_psi2s_ee', 'br_jpsi_ee', + 'eff_mu_psi2s', 'eff_mu_jpsi', 'br_psi2s_mumu', 'br_jpsi_mumu', + ] + + nuis = [] + params = wspace.pdf('model').getVariables() + params_iter = params.createIterator() + param = params_iter.Next() + while param : + if param.GetName() not in (nuis_excluded+globs): + nuis.append(param.GetName()) + param = params_iter.Next() + nuis = ','.join(nuis) + globs = ','.join(globs) + + sets = [('obs', 'x'), # observations + ('poi', 'R'), # parameter of interest + ('nuis', nuis), # nuisance parameters (leave no spaces) + ('globs', globs), + ] + #('nuis', 'n_ele_jpsi,eff_ele_psi2s,eff_ele_jpsi')] # nuisance parameters (leave no spaces) + + for t in sets: + name, parlist = t + wspace.defineSet(name, parlist) + + + #----------------------------------------------------- + # Create model configuration. This is needed for the + # statistical analyses + #----------------------------------------------------- + cfg = rt.RooStats.ModelConfig('cfg') + cfg.SetWorkspace(wspace) + cfg.SetPdf(wspace.pdf('model')) + cfg.SetParametersOfInterest(wspace.set('poi')) + cfg.SetNuisanceParameters(wspace.set('nuis')) + cfg.SetGlobalObservables(wspace.set('globs')) + + # import model configuration into workspace + getattr(wspace, 'import')(cfg) + + wspace.Print() + + # write out workspace + wspace.writeToFile(wsfilename) + + + +if __name__ == "__main__": + + eff_ele_psi2s, deff_ele_psi2s = 0.034559096817, 0.000245498985637 + eff_ele_jpsi, deff_ele_jpsi = 0.0387281944237, 0.000242298195912 + eff_mu_psi2s, deff_mu_psi2s = 0.034559096817, 0.000245498985637 + eff_mu_jpsi, deff_mu_jpsi = 0.0387281944237, 0.000242298195912 + R_SM = 1.0 + R_min, R_max = 0.8, 1.2 + xlabel = 'R_{#psi(2S)}' + + wsfilename_ele_psi2s = 'wspace_psi2s_fixedPartial_pf_wp5.0.root' + wsfilename_ele_jpsi = 'wspace_jpsi_fixedPartial_pf_wp5.0.root' + wsfilename_mu_psi2s = 'wspace_psi2s_fixedPartial_pf_wp5.0.root' + wsfilename_mu_jpsi = 'wspace_jpsi_fixedPartial_pf_wp5.0.root' + wsfilename = 'wspace_rpsi2s.root' + + createWorkspace('R_psi2s', wsfilename, wsfilename_ele_psi2s, wsfilename_ele_jpsi, wsfilename_mu_psi2s, wsfilename_mu_jpsi, + eff_ele_psi2s=eff_ele_psi2s, deff_ele_psi2s=deff_ele_psi2s, eff_ele_jpsi=eff_ele_jpsi, deff_ele_jpsi=deff_ele_jpsi, + eff_mu_psi2s=eff_mu_psi2s, deff_mu_psi2s=deff_mu_psi2s, eff_mu_jpsi=eff_mu_jpsi, deff_mu_jpsi=deff_mu_jpsi, + ) + plccanvas = analyzeWorkspace('R_psi2s', wsfilename, x_SM=R_SM, x_min=R_min, x_max=R_max, xlabel=xlabel, plot=True) + + diff --git a/measurement/maximum_likelihood_rpsi2s_combinedEleCh.py b/measurement/maximum_likelihood_rpsi2s_combinedEleCh.py new file mode 100644 index 0000000..3ba33f3 --- /dev/null +++ b/measurement/maximum_likelihood_rpsi2s_combinedEleCh.py @@ -0,0 +1,301 @@ +import os,sys,re +import time +from time import sleep +import math +import ROOT as rt +import ROOT +from ROOT import RooFit +from roofit_models import root_function_DoubleSidedCB +ROOT.gInterpreter.Declare(root_function_DoubleSidedCB) +from roofit_models import root_function_RightSidedCB +ROOT.gInterpreter.Declare(root_function_RightSidedCB) +rt.gROOT.SetBatch(True); +rt.gROOT.SetStyle("Plain"); +from utils_likelihood import analyzeWorkspace, plot_likelihood, importWorkspace + +def createWorkspace(wsname, wsfilename, + wsfilename_pfe_psi2s, wsfilename_pfe_jpsi, + wsfilename_mixe_psi2s, wsfilename_mixe_jpsi, + wsfilename_mu_psi2s, wsfilename_mu_jpsi, + eff_pfe_psi2s=0.0, deff_pfe_psi2s=0.0, eff_pfe_jpsi=0.0, deff_pfe_jpsi=0.0, + eff_mixe_psi2s=0.0, deff_mixe_psi2s=0.0, eff_mixe_jpsi=0.0, deff_mixe_jpsi=0.0, + eff_mu_psi2s=0.0, deff_mu_psi2s=0.0, eff_mu_jpsi=0.0, deff_mu_jpsi=0.0, + ): + + wspace = rt.RooWorkspace(wsname) + wspace = importWorkspace(wspace, wsfilename_pfe_psi2s, 'pfe_psi2s') + wspace = importWorkspace(wspace, wsfilename_pfe_jpsi, 'pfe_jpsi') + wspace = importWorkspace(wspace, wsfilename_mixe_psi2s, 'mixe_psi2s') + wspace = importWorkspace(wspace, wsfilename_mixe_jpsi, 'mixe_jpsi') + wspace = importWorkspace(wspace, wsfilename_mu_psi2s, 'mu_psi2s') + wspace = importWorkspace(wspace, wsfilename_mu_jpsi, 'mu_jpsi') + + wspace.factory('cat[pfe_psi2s,pfe_jpsi,mixe_psi2s,mixe_jpsi,mu_psi2s,mu_jpsi]') + x = wspace.var("x") + data = rt.RooDataSet('data', 'data', rt.RooArgSet(x), RooFit.Index(wspace.cat('cat')), + RooFit.Import('pfe_psi2s', wspace.data('data_pfe_psi2s')), RooFit.Import('pfe_jpsi', wspace.data('data_pfe_jpsi')), + RooFit.Import('mixe_psi2s', wspace.data('data_mixe_psi2s')), RooFit.Import('mixe_jpsi', wspace.data('data_mixe_jpsi')), + RooFit.Import('mu_psi2s', wspace.data('data_mu_psi2s')), RooFit.Import('mu_jpsi', wspace.data('data_mu_jpsi')), + ) + getattr(wspace, 'import')(data, rt.RooCmdArg()) + + br_jpsi_ee, dbr_jpsi_ee= 0.05971, 0.00032 + br_psi2s_ee, dbr_psi2s_ee = 7.93e-3, 0.17e-3 + br_jpsi_mumu, dbr_jpsi_mumu= 0.05961, 0.00033 + br_psi2s_mumu, dbr_psi2s_mumu = 8.0e-3, 0.6e-3 + r_br, dr_br = 0.6117647, 0.022678 + + ### Create parameters + # observations + params = [ + # efficiency of PF-PF electron psi(2S) estimate + ('eff_hat_pfe_psi2s', eff_pfe_psi2s, 1.e-6, 1), + ('deff_pfe_psi2s', deff_pfe_psi2s, 1.e-6, 1), + # efficiency of PF-PF electron J/psi channel estimate + ('eff_hat_pfe_jpsi', eff_pfe_jpsi, 1.e-6, 1), + ('deff_pfe_jpsi', deff_pfe_jpsi, 1.e-6, 1), + # efficiency of PF-LP electron psi(2S) estimate + ('eff_hat_mixe_psi2s', eff_mixe_psi2s, 1.e-6, 1), + ('deff_mixe_psi2s', deff_mixe_psi2s, 1.e-6, 1), + # efficiency of PF-LP electron J/psi channel estimate + ('eff_hat_mixe_jpsi', eff_mixe_jpsi, 1.e-6, 1), + ('deff_mixe_jpsi', deff_mixe_jpsi, 1.e-6, 1), + # branching fraction of J/psi -> ee + ('br_hat_jpsi_ee', br_jpsi_ee, 1.e-6, 1), + ('dbr_jpsi_ee', dbr_jpsi_ee, 1.e-6, 1), + # branching fraction of psi(2S) -> ee + ('br_hat_psi2s_ee', br_psi2s_ee, 1.e-6, 1), + ('dbr_psi2s_ee', dbr_psi2s_ee, 1.e-6, 1), + # efficiency of muon psi(2S) estimate + ('eff_hat_mu_psi2s', eff_mu_psi2s, 1.e-6, 1), + ('deff_mu_psi2s', deff_mu_psi2s, 1.e-6, 1), + # efficiency of muon J/psi channel estimate + ('eff_hat_mu_jpsi', eff_mu_jpsi, 1.e-6, 1), + ('deff_mu_jpsi', deff_mu_jpsi, 1.e-6, 1), + # branching fraction of J/psi -> mu mu + ('br_hat_jpsi_mumu', br_jpsi_mumu, 1.e-6, 1), + ('dbr_jpsi_mumu', dbr_jpsi_mumu, 1.e-6, 1), + # branching fraction of psi(2S) -> mu mu + ('br_hat_psi2s_mumu', br_psi2s_mumu, 1.e-6, 1), + ('dbr_psi2s_mumu', dbr_psi2s_mumu, 1.e-6, 1), + # branching fraction of B -> psi(2S) / B -> J/psi + ('r_br_hat', r_br, 1.e-6, 1), + ('dr_br', dr_br, 1.e-6, 1), + # nuisance parameters + #('n_pfe_jpsi', 4.7656e+03 , 0, 10000), + #('eff_pfe_psi2s', eff_pfe_psi2s, eff_pfe_psi2s-5.0*deff_pfe_psi2s, eff_pfe_psi2s+5.0*deff_pfe_psi2s), + #('eff_pfe_jpsi', eff_pfe_jpsi, eff_pfe_jpsi-5.0*deff_pfe_jpsi, eff_pfe_jpsi+5.0*deff_pfe_jpsi), + #('n_mixe_jpsi', 2.0379e+03, 0, 10000), + #('eff_mixe_psi2s', eff_mixe_psi2s, eff_mixe_psi2s-5.0*deff_mixe_psi2s, eff_mixe_psi2s+5.0*deff_mixe_psi2s), + #('eff_mixe_jpsi', eff_mixe_jpsi, eff_mixe_jpsi-5.0*deff_mixe_jpsi, eff_mixe_jpsi+5.0*deff_mixe_jpsi), + #('br_psi2s_ee', br_psi2s_ee, br_psi2s_ee-5.0*dbr_psi2s_ee, br_psi2s_ee+5.0*dbr_psi2s_ee), + #('br_jpsi_ee', br_jpsi_ee, br_jpsi_ee-5.0*dbr_jpsi_ee, br_jpsi_ee+5.0*dbr_jpsi_ee), + #('n_mu_jpsi', 7.7098e+05, 0, 5000000), + #('eff_mu_psi2s', eff_mu_psi2s, eff_mu_psi2s-5.0*deff_mu_psi2s, eff_mu_psi2s+5.0*deff_mu_psi2s), + #('eff_mu_jpsi', eff_mu_jpsi, eff_mu_jpsi-5.0*deff_mu_jpsi, eff_mu_jpsi+5.0*deff_mu_jpsi), + #('br_psi2s_mumu', br_psi2s_mumu, br_psi2s_mumu-5.0*dbr_psi2s_mumu, br_psi2s_mumu+5.0*dbr_psi2s_mumu), + #('br_jpsi_mumu', br_jpsi_mumu, br_jpsi_mumu-5.0*dbr_jpsi_mumu, br_jpsi_mumu+5.0*dbr_jpsi_mumu), + ('n_pfe_jpsi', 4.7656e+03 , 0, 10000), + ('eff_pfe_psi2s', eff_pfe_psi2s, -1.0, 1.0), + ('eff_pfe_jpsi', eff_pfe_jpsi, -1.0, 1.0), + ('n_mixe_jpsi', 2.0379e+03, 0, 10000), + ('eff_mixe_psi2s', eff_mixe_psi2s, -1.0, 1.0), + ('eff_mixe_jpsi', eff_mixe_jpsi, -1.0, 1.0), + ('br_psi2s_ee', br_psi2s_ee, br_psi2s_ee-50.0*dbr_psi2s_ee, br_psi2s_ee+50.0*dbr_psi2s_ee), + ('br_jpsi_ee', br_jpsi_ee, br_jpsi_ee-50.0*dbr_jpsi_ee, br_jpsi_ee+50.0*dbr_jpsi_ee), + ('n_mu_jpsi', 7.7098e+05, 0, 5000000), + ('eff_mu_psi2s', eff_mu_psi2s, -1.0, 1.0), + ('eff_mu_jpsi', eff_mu_jpsi, -1.0, 1.0), + ('br_psi2s_mumu', br_psi2s_mumu, br_psi2s_mumu-50.0*dbr_psi2s_mumu, br_psi2s_mumu+50.0*dbr_psi2s_mumu), + ('br_jpsi_mumu', br_jpsi_mumu, br_jpsi_mumu-50.0*dbr_jpsi_mumu, br_jpsi_mumu+50.0*dbr_jpsi_mumu), + + # parameter of interest + ('r_br', r_br, r_br-50.0*dr_br, r_br+50.0*dr_br), + ('R', 1.0, 0.1, 2.0), + ] + + for t in params: + cmd = '%s[%f, %f, %f]' % t + wspace.factory(cmd) + wspace.var('R').SetTitle('R') + + # fix all background and signal parameters + for t in params[0:-15]: + name = t[0] + print '=> make %8s = %5.5f constant' % (name, + wspace.var(name).getVal()) + wspace.var(name).setConstant() + + wspace.var("ncomb_pfe_jpsi").setConstant() + wspace.var("ncomb_mixe_jpsi").setConstant() + wspace.var("ncomb_mu_jpsi").setConstant() + + + ### Create expressions + express = [ + # PF-PF electron + 'n_pfe_psi2s("(r_br/R)*n_pfe_jpsi*(br_psi2s_ee/br_jpsi_ee)*(eff_pfe_psi2s/eff_pfe_jpsi)", r_br, R, n_pfe_jpsi, br_psi2s_ee, br_jpsi_ee, eff_pfe_psi2s, eff_pfe_jpsi)', + 'nKstarPsi2S_pfe_psi2s_modified("frac_partial_pfe_psi2s*n_pfe_psi2s", frac_partial_pfe_psi2s, n_pfe_psi2s)', + 'nKstarJpsi_pfe_jpsi_modified("frac_partial_pfe_jpsi*n_pfe_jpsi", frac_partial_pfe_jpsi, n_pfe_jpsi)', + 'nKstarPlusPsi2S_pfe_psi2s_modified("frac_kstarplus_pfe_psi2s*nKstarPsi2S_pfe_psi2s_modified", frac_kstarplus_pfe_psi2s, nKstarPsi2S_pfe_psi2s_modified)', + 'nKstarPlusJpsi_pfe_jpsi_modified("frac_kstarplus_pfe_jpsi*nKstarJpsi_pfe_jpsi_modified", frac_kstarplus_pfe_jpsi, nKstarJpsi_pfe_jpsi_modified)', + # PF-LP electron + 'n_mixe_psi2s("(r_br/R)*n_mixe_jpsi*(br_psi2s_ee/br_jpsi_ee)*(eff_mixe_psi2s/eff_mixe_jpsi)", r_br, R, n_mixe_jpsi, br_psi2s_ee, br_jpsi_ee, eff_mixe_psi2s, eff_mixe_jpsi)', + 'nKstarPsi2S_mixe_psi2s_modified("frac_partial_mixe_psi2s*n_mixe_psi2s", frac_partial_mixe_psi2s, n_mixe_psi2s)', + 'nKstarJpsi_mixe_jpsi_modified("frac_partial_mixe_jpsi*n_mixe_jpsi", frac_partial_mixe_jpsi, n_mixe_jpsi)', + 'nKstarPlusPsi2S_mixe_psi2s_modified("frac_kstarplus_mixe_psi2s*nKstarPsi2S_mixe_psi2s_modified", frac_kstarplus_mixe_psi2s, nKstarPsi2S_mixe_psi2s_modified)', + 'nKstarPlusJpsi_mixe_jpsi_modified("frac_kstarplus_mixe_jpsi*nKstarJpsi_mixe_jpsi_modified", frac_kstarplus_mixe_jpsi, nKstarJpsi_mixe_jpsi_modified)', + # muon + 'n_mu_psi2s("r_br*n_mu_jpsi*(br_psi2s_mumu/br_jpsi_mumu)*(eff_mu_psi2s/eff_mu_jpsi)", r_br, n_mu_jpsi, br_psi2s_mumu, br_jpsi_mumu, eff_mu_psi2s, eff_mu_jpsi)', + #'nKstarPsi2S_mu_psi2s_modified("frac_partial_mu_psi2s*n_mu_psi2s", frac_partial_mu_psi2s, n_mu_psi2s)', + #'nKstarJpsi_mu_jpsi_modified("frac_partial_mu_jpsi*n_mu_jpsi", frac_partial_mu_jpsi, n_mu_jpsi)', + ] + + for t in express: + cmd = 'expr::%s' % t + wspace.factory(cmd) + + edit = [ + # PF-PF electron + 'model_pfe_psi2s_modified(model_pfe_psi2s, nsignal_pfe_psi2s=n_pfe_psi2s, nKstarPsi2S_pfe_psi2s=nKstarPsi2S_pfe_psi2s_modified, nKstarPlusPsi2S_pfe_psi2s=nKstarPlusPsi2S_pfe_psi2s_modified)', + 'model_pfe_jpsi_modified(model_pfe_jpsi, nsignal_pfe_jpsi=n_pfe_jpsi, nKstarJpsi_pfe_jpsi=nKstarJpsi_pfe_jpsi_modified, nKstarPlusJpsi_pfe_jpsi=nKstarPlusJpsi_pfe_jpsi_modified)', + # PF-LP electron + 'model_mixe_psi2s_modified(model_mixe_psi2s, nsignal_mixe_psi2s=n_mixe_psi2s, nKstarPsi2S_mixe_psi2s=nKstarPsi2S_mixe_psi2s_modified, nKstarPlusPsi2S_mixe_psi2s=nKstarPlusPsi2S_mixe_psi2s_modified)', + 'model_mixe_jpsi_modified(model_mixe_jpsi, nsignal_mixe_jpsi=n_mixe_jpsi, nKstarJpsi_mixe_jpsi=nKstarJpsi_mixe_jpsi_modified, nKstarPlusJpsi_mixe_jpsi=nKstarPlusJpsi_mixe_jpsi_modified)', + # muon + 'model_mu_psi2s_modified(model_mu_psi2s, nsignal_mu_psi2s=n_mu_psi2s)', + 'model_mu_jpsi_modified(model_mu_jpsi, nsignal_mu_jpsi=n_mu_jpsi)', + ] + + for t in edit: + cmd = 'EDIT::%s' % t + wspace.factory(cmd) + + wspace.Print("V") + ### Create pdfs + pdfs = [ + # PF-PF electron + ('Gaussian','peff_pfe_psi2s', '(eff_hat_pfe_psi2s, eff_pfe_psi2s, deff_pfe_psi2s)'), + ('Gaussian','peff_pfe_jpsi', '(eff_hat_pfe_jpsi, eff_pfe_jpsi, deff_pfe_jpsi)'), + # PF-LP electron + ('Gaussian','peff_mixe_psi2s', '(eff_hat_mixe_psi2s, eff_mixe_psi2s, deff_mixe_psi2s)'), + ('Gaussian','peff_mixe_jpsi', '(eff_hat_mixe_jpsi, eff_mixe_jpsi, deff_mixe_jpsi)'), + ('Gaussian','peff_br_psi2s_ee', '(br_hat_psi2s_ee, br_psi2s_ee, dbr_psi2s_ee)'), + ('Gaussian','peff_br_jpsi_ee', '(br_hat_jpsi_ee, br_jpsi_ee, dbr_jpsi_ee)'), + # muon + ('Gaussian','peff_mu_psi2s', '(eff_hat_mu_psi2s, eff_mu_psi2s, deff_mu_psi2s)'), + ('Gaussian','peff_mu_jpsi', '(eff_hat_mu_jpsi, eff_mu_jpsi, deff_mu_jpsi)'), + ('Gaussian','peff_br_psi2s_mumu', '(br_hat_psi2s_mumu, br_psi2s_mumu, dbr_psi2s_mumu)'), + ('Gaussian','peff_br_jpsi_mumu', '(br_hat_jpsi_mumu, br_jpsi_mumu, dbr_jpsi_mumu)'), + # r_br + ('Gaussian','pr_br', '(r_br_hat, r_br, dr_br)'), + ] + + prodpdf = '' + for t in pdfs: + wspace.factory('%s::%s%s' % t) + name = t[1] + prodpdf += "%s, " % name + prodpdf = prodpdf[:-2] # remove last ", " + + + # multiply the pdfs together. use upper case PROD to + # do this + wspace.factory("SIMUL:jointModel(cat,pfe_psi2s=model_pfe_psi2s_modified,pfe_jpsi=model_pfe_jpsi_modified,mixe_psi2s=model_mixe_psi2s_modified,mixe_jpsi=model_mixe_jpsi_modified,mu_psi2s=model_mu_psi2s_modified,mu_jpsi=model_mu_jpsi_modified)") + wspace.factory('PROD::model({},{})'.format(prodpdf, 'jointModel')) + + nuis_excluded = ['x', 'R', 'cat', + 'deff_pfe_jpsi', 'deff_pfe_psi2s', 'eff_hat_pfe_jpsi', 'eff_hat_pfe_psi2s', + 'deff_mixe_jpsi', 'deff_mixe_psi2s', 'eff_hat_mixe_jpsi', 'eff_hat_mixe_psi2s', + 'dbr_jpsi_ee', 'dbr_psi2s_ee', 'br_hat_jpsi_ee', 'br_hat_psi2s_ee' + 'deff_mu_jpsi', 'deff_mu_psi2s', 'eff_hat_mu_jpsi', 'eff_hat_mu_psi2s', + 'dbr_jpsi_mumu', 'dbr_psi2s_mumu', 'br_hat_jpsi_mumu', 'br_hat_psi2s_mumu' + 'dr_br', 'r_br_hat' + ] + + ### Define global observables + ### they are not being fitted and they are not loaded from a dataset, + ### but some knowledge exists that allows to set them to a specific value + ### Global Observables are generated once per toy + #globs = ['eff_pfe_psi2s', 'eff_pfe_jpsi', 'br_psi2s_ee', 'br_jpsi_ee', + # 'eff_mixe_psi2s', 'eff_mixe_jpsi', + # 'eff_mu_psi2s', 'eff_mu_jpsi', 'br_psi2s_mumu', 'br_jpsi_mumu', + # 'r_br' + # ] + globs = ['eff_hat_pfe_psi2s', 'eff_hat_pfe_jpsi', 'br_hat_psi2s_ee', 'br_hat_jpsi_ee', + 'eff_hat_mixe_psi2s', 'eff_hat_mixe_jpsi', + 'eff_hat_mu_psi2s', 'eff_hat_mu_jpsi', 'br_hat_psi2s_mumu', 'br_hat_jpsi_mumu', + ] + + + nuis = [] + params = wspace.pdf('model').getVariables() + params_iter = params.createIterator() + param = params_iter.Next() + while param : + if param.GetName() not in (nuis_excluded+globs): + nuis.append(param.GetName()) + param = params_iter.Next() + nuis = ','.join(nuis) + globs = ','.join(globs) + + sets = [('obs', 'x'), # observations + ('poi', 'R'), # parameter of interest + ('nuis', nuis), + ('globs', globs), + ] # nuisance parameters (leave no spaces) + #('nuis', 'n_pfe_jpsi,eff_pfe_psi2s,eff_pfe_jpsi')] # nuisance parameters (leave no spaces) + + for t in sets: + name, parlist = t + wspace.defineSet(name, parlist) + + + #----------------------------------------------------- + # Create model configuration. This is needed for the + # statistical analyses + #----------------------------------------------------- + cfg = rt.RooStats.ModelConfig('cfg') + cfg.SetWorkspace(wspace) + cfg.SetPdf(wspace.pdf('model')) + cfg.SetParametersOfInterest(wspace.set('poi')) + cfg.SetNuisanceParameters(wspace.set('nuis')) + #cfg.SetGlobalObservables(wspace.set('globs')) + + # import model configuration into workspace + getattr(wspace, 'import')(cfg) + + wspace.Print() + + # write out workspace + wspace.writeToFile(wsfilename) + + +if __name__ == "__main__": + + eff_pfe_psi2s, deff_pfe_psi2s = 0.01822, 0.00023 + eff_pfe_jpsi, deff_pfe_jpsi = 0.02479, 0.00025 + eff_mixe_psi2s, deff_mixe_psi2s = 0.00680, 0.00011 + eff_mixe_jpsi, deff_mixe_jpsi = 0.01085, 0.00014 + eff_mu_psi2s, deff_mu_psi2s = 14.81e-4, 0.11e-4 + eff_mu_jpsi, deff_mu_jpsi = 12.69e-4, 0.1e-4 + R_SM = 1.0 + R_min, R_max = 0.75, 1.25 + xlabel = 'R_{#psi(2S)}' + + wsfilename_pfe_psi2s = 'wspace_psi2s_fixedPartial_pf_wp8.3_fixedpartial.root' + wsfilename_pfe_jpsi = 'wspace_jpsi_fixedPartial_pf_wp8.3_fixedpartial.root' + wsfilename_mixe_psi2s = 'wspace_psi2s_fixedPartial_mix_wp8.6_fixedpartial.root' + wsfilename_mixe_jpsi = 'wspace_jpsi_fixedPartial_mix_wp8.6_fixedpartial.root' + wsfilename_mu_psi2s = 'wspace_psi2s_muon.root' + wsfilename_mu_jpsi = 'wspace_jpsi_muon.root' + wsfilename = 'wspace_rpsi2s_combinedEleCh.root' + + createWorkspace('R_psi2s', wsfilename, wsfilename_pfe_psi2s, wsfilename_pfe_jpsi, wsfilename_mixe_psi2s, wsfilename_mixe_jpsi, wsfilename_mu_psi2s, wsfilename_mu_jpsi, + eff_pfe_psi2s=eff_pfe_psi2s, deff_pfe_psi2s=deff_pfe_psi2s, eff_pfe_jpsi=eff_pfe_jpsi, deff_pfe_jpsi=deff_pfe_jpsi, + eff_mixe_psi2s=eff_mixe_psi2s, deff_mixe_psi2s=deff_mixe_psi2s, eff_mixe_jpsi=eff_mixe_jpsi, deff_mixe_jpsi=deff_mixe_jpsi, + eff_mu_psi2s=eff_mu_psi2s, deff_mu_psi2s=deff_mu_psi2s, eff_mu_jpsi=eff_mu_jpsi, deff_mu_jpsi=deff_mu_jpsi, + ) + plccanvas = analyzeWorkspace('R_psi2s', wsfilename, x_SM=R_SM, x_min=R_min, x_max=R_max, xlabel=xlabel, plot=False, unbinned=False, NPoints=50) + + diff --git a/measurement/maximum_likelihood_singleChannel.py b/measurement/maximum_likelihood_singleChannel.py new file mode 100644 index 0000000..c90a7aa --- /dev/null +++ b/measurement/maximum_likelihood_singleChannel.py @@ -0,0 +1,165 @@ +import os,sys,re +from time import sleep +import math +import ROOT as rt +from ROOT import RooFit +rt.gROOT.SetBatch(True); +rt.gROOT.SetStyle("Plain"); +from utils_likelihood import analyzeWorkspace, plot_likelihood, importWorkspace + +def createWorkspace(wsname, wsfilename, wsfilename_tar, wsfilename_norm, eff_tar=0.0, deff_tar=0.0, eff_norm=0.0, deff_norm=0.0): + wspace = rt.RooWorkspace(wsname) + wspace = importWorkspace(wspace, wsfilename_tar, 'tar') + wspace = importWorkspace(wspace, wsfilename_norm, 'norm') + + wspace.factory('cat[tar,norm]') + x = wspace.var("x") + data = rt.RooDataSet('data', 'data', rt.RooArgSet(x), RooFit.Index(wspace.cat('cat')), RooFit.Import('tar', wspace.data('data_tar')), RooFit.Import('norm', wspace.data('data_norm'))) + getattr(wspace, 'import')(data, rt.RooCmdArg()) + + + ### Create parameters + # observations + params = [ + # efficiency of target channel estimate + ('eff_hat_tar', eff_tar, 0, 1), + ('deff_tar', deff_tar, 0, 1), + # efficiency of normalization channel estimate + ('eff_hat_norm', eff_norm, 0, 1), + ('deff_norm', deff_norm, 0, 1), + # nuisance parameters + #('n_norm', 4779.12, 0, 10000), + ('n_norm', 2084.77, 0, 10000), + ('eff_tar', eff_tar, eff_tar-5.0*deff_tar, eff_tar+5.0*deff_tar), + ('eff_norm', eff_norm, eff_norm-5.0*deff_norm, eff_norm+5.0*deff_norm), + # parameter of interest + ('R', 7.2486e-02, 0.01, 0.15)] + + for t in params: + cmd = '%s[%f, %f, %f]' % t + wspace.factory(cmd) + wspace.var('R').SetTitle('R') + + # fix all background and signal parameters + for t in params[0:-4]: + name = t[0] + print '=> make %8s = %5.5f constant' % (name, + wspace.var(name).getVal()) + wspace.var(name).setConstant() + + ### Create expressions + express = ['n_tar("R*n_norm*(eff_tar/eff_norm)", R, n_norm, eff_tar, eff_norm)', + 'nKstarPsi2S_tar_modified("frac_partial_tar*n_tar", frac_partial_tar, n_tar)', + 'nKstarJpsi_norm_modified("frac_partial_norm*n_norm", frac_partial_norm, n_norm)', + 'nKstarPlusPsi2S_tar_modified("frac_kstarplus_tar*nKstarPsi2S_tar_modified", frac_kstarplus_tar, nKstarPsi2S_tar_modified)', + 'nKstarPlusJpsi_norm_modified("frac_kstarplus_norm*nKstarJpsi_norm_modified", frac_kstarplus_norm, nKstarJpsi_norm_modified)', + ] + + for t in express: + cmd = 'expr::%s' % t + wspace.factory(cmd) + + edit = ['model_tar_modified(model_tar, nsignal_tar=n_tar, nKstarPsi2S_tar=nKstarPsi2S_tar_modified, nKstarPlusPsi2S_tar=nKstarPlusPsi2S_tar_modified)', + 'model_norm_modified(model_norm, nsignal_norm=n_norm, nKstarJpsi_norm=nKstarJpsi_norm_modified, nKstarPlusJpsi_norm=nKstarPlusJpsi_norm_modified)', + ] + + for t in edit: + cmd = 'EDIT::%s' % t + wspace.factory(cmd) + + wspace.Print("V") + ### Create pdfs + pdfs = [('Gaussian','peff_tar', '(eff_hat_tar, eff_tar, deff_tar)'), + ('Gaussian','peff_norm', '(eff_hat_norm, eff_norm, deff_norm)'), + ] + + prodpdf = '' + for t in pdfs: + wspace.factory('%s::%s%s' % t) + name = t[1] + prodpdf += "%s, " % name + prodpdf = prodpdf[:-2] # remove last ", " + + + # multiply the pdfs together. use upper case PROD to + # do this + wspace.factory("SIMUL:jointModel(cat,tar=model_tar_modified,norm=model_norm_modified)") + wspace.factory('PROD::model({},{})'.format(prodpdf, 'jointModel')) + + nuis_excluded = ['x', 'R', 'cat', 'deff_norm', 'deff_tar', 'eff_hat_norm', 'eff_hat_tar'] + + ### Define global observables + ### they are not being fitted and they are not loaded from a dataset, + ### but some knowledge exists that allows to set them to a specific value + ### Global Observables are generated once per toy + globs = ['eff_tar', 'eff_norm'] + + nuis = [] + params = wspace.pdf('model').getVariables() + params_iter = params.createIterator() + param = params_iter.Next() + while param : + if param.GetName() not in (nuis_excluded+globs): + nuis.append(param.GetName()) + param = params_iter.Next() + nuis = ','.join(nuis) + globs = ','.join(globs) + + sets = [('obs', 'x'), # observations + ('poi', 'R'), # parameter of interest + ('nuis', nuis), # nuisance parameters (leave no spaces) + ('globs', globs), + ] + #('nuis', 'n_norm,eff_tar,eff_norm')] # nuisance parameters (leave no spaces) + + for t in sets: + name, parlist = t + wspace.defineSet(name, parlist) + + + #----------------------------------------------------- + # Create model configuration. This is needed for the + # statistical analyses + #----------------------------------------------------- + cfg = rt.RooStats.ModelConfig('cfg') + cfg.SetWorkspace(wspace) + cfg.SetPdf(wspace.pdf('model')) + cfg.SetParametersOfInterest(wspace.set('poi')) + cfg.SetNuisanceParameters(wspace.set('nuis')) + cfg.SetGlobalObservables(wspace.set('globs')) + + # import model configuration into workspace + getattr(wspace, 'import')(cfg) + + wspace.Print() + + # write out workspace + wspace.writeToFile(wsfilename) + + +if __name__ == "__main__": + + # pf + #eff_tar, deff_tar = 0.01822, 0.00023 + #eff_norm, deff_norm = 0.02479, 0.00025 + #R_min, R_max = 0.075, 0.105 + #wsfilename_tar = 'wspace_psi2s_fixedPartial_pf_wp8.3_fixedpartial.root' + #wsfilename_norm = 'wspace_jpsi_fixedPartial_pf_wp8.3_fixedpartial.root' + + # mix + eff_tar, deff_tar = 0.00680, 0.00011 + eff_norm, deff_norm = 0.01085, 0.00014 + R_min, R_max = 0.05, 0.095 + wsfilename_tar = 'wspace_psi2s_fixedPartial_mix_wp8.6_fixedpartial.root' + wsfilename_norm = 'wspace_jpsi_fixedPartial_mix_wp8.6_fixedpartial.root' + + R_SM = 0.0812 + + xlabel = 'R_{#psi (2S)}^{e}' + + wsfilename = 'wspace_rpsi2s_electron.root' + + createWorkspace('R_psi2s', wsfilename, wsfilename_tar, wsfilename_norm, eff_tar=eff_tar, deff_tar=deff_tar, eff_norm=eff_norm, deff_norm=deff_norm) + plccanvas = analyzeWorkspace('R_psi2s', wsfilename, x_SM=R_SM, x_min=R_min, x_max=R_max, xlabel=xlabel, plot=True) + + diff --git a/measurement/maximum_likelihood_singleChannel_combinedEleCh.py b/measurement/maximum_likelihood_singleChannel_combinedEleCh.py new file mode 100644 index 0000000..484f2c0 --- /dev/null +++ b/measurement/maximum_likelihood_singleChannel_combinedEleCh.py @@ -0,0 +1,196 @@ +import os,sys,re +from time import sleep +import math +import ROOT as rt +from ROOT import RooFit +rt.gROOT.SetBatch(True); +rt.gROOT.SetStyle("Plain"); +from utils_likelihood import analyzeWorkspace, plot_likelihood, importWorkspace + +def createWorkspace(wsname, wsfilename, wsfilename_ele_psi2s, wsfilename_ele_jpsi, wsfilename_mu_psi2s, wsfilename_mu_jpsi, + eff_ele_psi2s=0.0, deff_ele_psi2s=0.0, eff_ele_jpsi=0.0, deff_ele_jpsi=0.0, + eff_mu_psi2s=0.0, deff_mu_psi2s=0.0, eff_mu_jpsi=0.0, deff_mu_jpsi=0.0, + ): + + wspace = rt.RooWorkspace(wsname) + wspace = importWorkspace(wspace, wsfilename_ele_psi2s, 'ele_psi2s') + wspace = importWorkspace(wspace, wsfilename_ele_jpsi, 'ele_jpsi') + wspace = importWorkspace(wspace, wsfilename_mu_psi2s, 'mu_psi2s') + wspace = importWorkspace(wspace, wsfilename_mu_jpsi, 'mu_jpsi') + + wspace.factory('cat[ele_psi2s,ele_jpsi,mu_psi2s,mu_jpsi]') + x = wspace.var("x") + data = rt.RooDataSet('data', 'data', rt.RooArgSet(x), RooFit.Index(wspace.cat('cat')), + RooFit.Import('ele_psi2s', wspace.data('data_ele_psi2s')), RooFit.Import('ele_jpsi', wspace.data('data_ele_jpsi')), + RooFit.Import('mu_psi2s', wspace.data('data_mu_psi2s')), RooFit.Import('mu_jpsi', wspace.data('data_mu_jpsi')), + ) + getattr(wspace, 'import')(data, rt.RooCmdArg()) + + + ### Create parameters + # observations + params = [ + # efficiency of electron psi(2S) estimate + ('eff_hat_ele_psi2s', eff_ele_psi2s, 1.e-6, 1), + ('deff_ele_psi2s', deff_ele_psi2s, 1.e-6, 1), + # efficiency of electron J/psi channel estimate + ('eff_hat_ele_jpsi', eff_ele_jpsi, 1.e-6, 1), + ('deff_ele_jpsi', deff_ele_jpsi, 1.e-6, 1), + # efficiency of muon psi(2S) estimate + ('eff_hat_mu_psi2s', eff_mu_psi2s, 1.e-6, 1), + ('deff_mu_psi2s', deff_mu_psi2s, 1.e-6, 1), + # efficiency of muon J/psi channel estimate + ('eff_hat_mu_jpsi', eff_mu_jpsi, 1.e-6, 1), + ('deff_mu_jpsi', deff_mu_jpsi, 1.e-6, 1), + # nuisance parameters + ('n_ele_jpsi', 9117, 0, 11000), + ('eff_ele_psi2s', eff_ele_psi2s, eff_ele_psi2s-5.0*deff_ele_psi2s, eff_ele_psi2s+5.0*deff_ele_psi2s), + ('eff_ele_jpsi', eff_ele_jpsi, eff_ele_jpsi-5.0*deff_ele_jpsi, eff_ele_jpsi+5.0*deff_ele_jpsi), + ('n_mu_jpsi', 9117, 0, 11000), + ('eff_mu_psi2s', eff_mu_psi2s, eff_mu_psi2s-5.0*deff_mu_psi2s, eff_mu_psi2s+5.0*deff_mu_psi2s), + ('eff_mu_jpsi', eff_mu_jpsi, eff_mu_jpsi-5.0*deff_mu_jpsi, eff_mu_jpsi+5.0*deff_mu_jpsi), + # parameter of interest + ('R', 7.2486e-02, 0.01, 0.15)] + + for t in params: + cmd = '%s[%f, %f, %f]' % t + wspace.factory(cmd) + wspace.var('R').SetTitle('R') + + # fix all background and signal parameters + for t in params[0:-7]: + name = t[0] + print '=> make %8s = %5.5f constant' % (name, + wspace.var(name).getVal()) + wspace.var(name).setConstant() + + ### Create expressions + express = ['n_ele_psi2s("R*n_ele_jpsi*(eff_ele_psi2s/eff_ele_jpsi)", R, n_ele_jpsi, eff_ele_psi2s, eff_ele_jpsi)', + 'nKstarPsi2S_ele_psi2s_modified("frac_partial_ele_psi2s*n_ele_psi2s", frac_partial_ele_psi2s, n_ele_psi2s)', + 'nKstarJpsi_ele_jpsi_modified("frac_partial_ele_jpsi*n_ele_jpsi", frac_partial_ele_jpsi, n_ele_jpsi)', + 'nKstarPlusPsi2S_ele_psi2s_modified("frac_kstarplus_ele_psi2s*nKstarPsi2S_ele_psi2s_modified", frac_kstarplus_ele_psi2s, nKstarPsi2S_ele_psi2s_modified)', + 'nKstarPlusJpsi_ele_jpsi_modified("frac_kstarplus_ele_jpsi*nKstarJpsi_ele_jpsi_modified", frac_kstarplus_ele_jpsi, nKstarJpsi_ele_jpsi_modified)', + 'n_mu_psi2s("R*n_mu_jpsi*(eff_mu_psi2s/eff_mu_jpsi)", R, n_mu_jpsi, eff_mu_psi2s, eff_mu_jpsi)', + 'nKstarPsi2S_mu_psi2s_modified("frac_partial_mu_psi2s*n_mu_psi2s", frac_partial_mu_psi2s, n_mu_psi2s)', + 'nKstarJpsi_mu_jpsi_modified("frac_partial_mu_jpsi*n_mu_jpsi", frac_partial_mu_jpsi, n_mu_jpsi)', + 'nKstarPlusPsi2S_mu_psi2s_modified("frac_kstarplus_mu_psi2s*nKstarPsi2S_mu_psi2s_modified", frac_kstarplus_mu_psi2s, nKstarPsi2S_mu_psi2s_modified)', + 'nKstarPlusJpsi_mu_jpsi_modified("frac_kstarplus_mu_jpsi*nKstarJpsi_mu_jpsi_modified", frac_kstarplus_mu_jpsi, nKstarJpsi_mu_jpsi_modified)', + ] + + for t in express: + cmd = 'expr::%s' % t + wspace.factory(cmd) + + edit = ['model_ele_psi2s_modified(model_ele_psi2s, nsignal_ele_psi2s=n_ele_psi2s, nKstarPsi2S_ele_psi2s=nKstarPsi2S_ele_psi2s_modified, nKstarPlusPsi2S_ele_psi2s=nKstarPlusPsi2S_ele_psi2s_modified)', + 'model_ele_jpsi_modified(model_ele_jpsi, nsignal_ele_jpsi=n_ele_jpsi, nKstarJpsi_ele_jpsi=nKstarJpsi_ele_jpsi_modified, nKstarPlusJpsi_ele_jpsi=nKstarPlusJpsi_ele_jpsi_modified)', + 'model_mu_psi2s_modified(model_mu_psi2s, nsignal_mu_psi2s=n_mu_psi2s, nKstarPsi2S_mu_psi2s=nKstarPsi2S_mu_psi2s_modified, nKstarPlusPsi2S_mu_psi2s=nKstarPlusPsi2S_mu_psi2s_modified)', + 'model_mu_jpsi_modified(model_mu_jpsi, nsignal_mu_jpsi=n_mu_jpsi, nKstarJpsi_mu_jpsi=nKstarJpsi_mu_jpsi_modified, nKstarPlusJpsi_mu_jpsi=nKstarPlusJpsi_mu_jpsi_modified)', + ] + + for t in edit: + cmd = 'EDIT::%s' % t + wspace.factory(cmd) + + wspace.Print("V") + ### Create pdfs + pdfs = [('Gaussian','peff_ele_psi2s', '(eff_hat_ele_psi2s, eff_ele_psi2s, deff_ele_psi2s)'), + ('Gaussian','peff_ele_jpsi', '(eff_hat_ele_jpsi, eff_ele_jpsi, deff_ele_jpsi)'), + ('Gaussian','peff_mu_psi2s', '(eff_hat_mu_psi2s, eff_mu_psi2s, deff_mu_psi2s)'), + ('Gaussian','peff_mu_jpsi', '(eff_hat_mu_jpsi, eff_mu_jpsi, deff_mu_jpsi)'), + ] + + prodpdf = '' + for t in pdfs: + wspace.factory('%s::%s%s' % t) + name = t[1] + prodpdf += "%s, " % name + prodpdf = prodpdf[:-2] # remove last ", " + + + # multiply the pdfs together. use upper case PROD to + # do this + wspace.factory("SIMUL:jointModel(cat,ele_psi2s=model_ele_psi2s_modified,ele_jpsi=model_ele_jpsi_modified,mu_psi2s=model_mu_psi2s_modified,mu_jpsi=model_mu_jpsi_modified)") + wspace.factory('PROD::model({},{})'.format(prodpdf, 'jointModel')) + + nuis_excluded = ['x', 'R', 'cat', + 'deff_ele_jpsi', 'deff_ele_psi2s', 'eff_hat_ele_jpsi', 'eff_hat_ele_psi2s', + 'deff_mu_jpsi', 'deff_mu_psi2s', 'eff_hat_mu_jpsi', 'eff_hat_mu_psi2s', + ] + + ### Define global observables + ### they are not being fitted and they are not loaded from a dataset, + ### but some knowledge exists that allows to set them to a specific value + ### Global Observables are generated once per toy + globs = ['eff_ele_psi2s', 'eff_ele_jpsi', + 'eff_mu_psi2s', 'eff_mu_jpsi', + ] + + nuis = [] + params = wspace.pdf('model').getVariables() + params_iter = params.createIterator() + param = params_iter.Next() + while param : + if param.GetName() not in (nuis_excluded+globs): + nuis.append(param.GetName()) + param = params_iter.Next() + nuis = ','.join(nuis) + globs = ','.join(globs) + + sets = [('obs', 'x'), # observations + ('poi', 'R'), # parameter of interest + ('nuis', nuis), # nuisance parameters (leave no spaces) + ('globs', globs), + ] + #('nuis', 'n_ele_jpsi,eff_ele_psi2s,eff_ele_jpsi')] # nuisance parameters (leave no spaces) + + for t in sets: + name, parlist = t + wspace.defineSet(name, parlist) + + + #----------------------------------------------------- + # Create model configuration. This is needed for the + # statistical analyses + #----------------------------------------------------- + cfg = rt.RooStats.ModelConfig('cfg') + cfg.SetWorkspace(wspace) + cfg.SetPdf(wspace.pdf('model')) + cfg.SetParametersOfInterest(wspace.set('poi')) + cfg.SetNuisanceParameters(wspace.set('nuis')) + cfg.SetGlobalObservables(wspace.set('globs')) + + # import model configuration into workspace + getattr(wspace, 'import')(cfg) + + wspace.Print() + + # write out workspace + wspace.writeToFile(wsfilename) + + + +if __name__ == "__main__": + + eff_ele_psi2s, deff_ele_psi2s = 0.01822, 0.00023 + eff_ele_jpsi, deff_ele_jpsi = 0.02479, 0.00025 + + eff_mu_psi2s, deff_mu_psi2s = 0.00680, 0.00011 + eff_mu_jpsi, deff_mu_jpsi = 0.01085, 0.00014 + + R_SM = 0.0812 + R_min, R_max = 0.07, 0.10 + xlabel = 'R_{#psi(2S)}^{e}' + + wsfilename_ele_psi2s = 'wspace_psi2s_fixedPartial_pf_wp8.3_fixedpartial.root' + wsfilename_ele_jpsi = 'wspace_jpsi_fixedPartial_pf_wp8.3_fixedpartial.root' + wsfilename_mu_psi2s = 'wspace_psi2s_fixedPartial_mix_wp8.6_fixedpartial.root' + wsfilename_mu_jpsi = 'wspace_jpsi_fixedPartial_mix_wp8.6_fixedpartial.root' + wsfilename = 'wspace_rpsi2s.root' + + createWorkspace('R_psi2s', wsfilename, wsfilename_ele_psi2s, wsfilename_ele_jpsi, wsfilename_mu_psi2s, wsfilename_mu_jpsi, + eff_ele_psi2s=eff_ele_psi2s, deff_ele_psi2s=deff_ele_psi2s, eff_ele_jpsi=eff_ele_jpsi, deff_ele_jpsi=deff_ele_jpsi, + eff_mu_psi2s=eff_mu_psi2s, deff_mu_psi2s=deff_mu_psi2s, eff_mu_jpsi=eff_mu_jpsi, deff_mu_jpsi=deff_mu_jpsi, + ) + plccanvas = analyzeWorkspace('R_psi2s', wsfilename, x_SM=R_SM, x_min=R_min, x_max=R_max, xlabel=xlabel, plot=True) + + diff --git a/measurement/maximum_likelihood_single_ratio_rpsi_combinedEleCh_effRatio.py b/measurement/maximum_likelihood_single_ratio_rpsi_combinedEleCh_effRatio.py new file mode 100644 index 0000000..eb570e3 --- /dev/null +++ b/measurement/maximum_likelihood_single_ratio_rpsi_combinedEleCh_effRatio.py @@ -0,0 +1,221 @@ +import os,sys,re +import time +from time import sleep +import math +from uncertainties import ufloat +import ROOT as rt +import ROOT +from ROOT import RooFit +from roofit_models import root_function_DoubleSidedCB +ROOT.gInterpreter.Declare(root_function_DoubleSidedCB) +from roofit_models import root_function_RightSidedCB +ROOT.gInterpreter.Declare(root_function_RightSidedCB) +rt.gROOT.SetBatch(True); +rt.gROOT.SetStyle("Plain"); +from utils_likelihood import analyzeWorkspace, plot_likelihood, importWorkspace + +def createWorkspace(wsname, wsfilename, + wsfilename_pfe_jpsi, + wsfilename_mixe_jpsi, + wsfilename_mu_jpsi, + eff_pfe_to_mu_jpsi=0.0, deff_pfe_to_mu_jpsi=0.0, + eff_mixe_to_mu_jpsi=0.0, deff_mixe_to_mu_jpsi=0.0, + ): + + wspace = rt.RooWorkspace(wsname) + wspace = importWorkspace(wspace, wsfilename_pfe_jpsi, 'pfe_jpsi') + wspace = importWorkspace(wspace, wsfilename_mixe_jpsi, 'mixe_jpsi') + wspace = importWorkspace(wspace, wsfilename_mu_jpsi, 'mu_jpsi') + + wspace.factory('cat[pfe_jpsi,mixe_jpsi,mu_jpsi]') + x = wspace.var("x") + data = rt.RooDataSet('data', 'data', rt.RooArgSet(x), RooFit.Index(wspace.cat('cat')), + RooFit.Import('pfe_jpsi', wspace.data('data_pfe_jpsi')), + RooFit.Import('mixe_jpsi', wspace.data('data_mixe_jpsi')), + RooFit.Import('mu_jpsi', wspace.data('data_mu_jpsi')), + ) + getattr(wspace, 'import')(data, rt.RooCmdArg()) + + br_jpsi_ee, dbr_jpsi_ee= 0.05971, 0.00032 + br_psi2s_ee, dbr_psi2s_ee = 7.93e-3, 0.17e-3 + br_jpsi_mumu, dbr_jpsi_mumu= 0.05961, 0.00033 + br_psi2s_mumu, dbr_psi2s_mumu = 8.0e-3, 0.6e-3 + r_br, dr_br = 0.6117647, 0.022678 + + ### Create parameters + # observations + params = [ + # efficiency of PF-PF electron J/psi channel estimate + ('eff_hat_pfe_to_mu_jpsi', eff_pfe_to_mu_jpsi, 1.e-6, 1), + ('deff_pfe_to_mu_jpsi', deff_pfe_to_mu_jpsi, 1.e-6, 1), + # efficiency of PF-LP electron J/psi channel estimate + ('eff_hat_mixe_to_mu_jpsi', eff_mixe_to_mu_jpsi, 1.e-6, 1), + ('deff_mixe_to_mu_jpsi', deff_mixe_to_mu_jpsi, 1.e-6, 1), + # nuisance parameters + #('eff_pfe_to_mu_jpsi', eff_pfe_to_mu_jpsi, eff_pfe_to_mu_jpsi-5.0*deff_pfe_to_mu_jpsi, eff_pfe_to_mu_jpsi+5.0*deff_pfe_to_mu_jpsi), + #('eff_mixe_to_mu_jpsi', eff_mixe_to_mu_jpsi, eff_mixe_to_mu_jpsi-5.0*deff_mixe_to_mu_jpsi, eff_mixe_to_mu_jpsi+5.0*deff_mixe_to_mu_jpsi), + #('eff_pfe_to_mu_jpsi', eff_pfe_to_mu_jpsi, eff_pfe_to_mu_jpsi-20.0*deff_pfe_to_mu_jpsi, 1), + #('eff_mixe_to_mu_jpsi', eff_mixe_to_mu_jpsi, eff_mixe_to_mu_jpsi-20.0*deff_mixe_to_mu_jpsi, 1), + ('eff_pfe_to_mu_jpsi', eff_pfe_to_mu_jpsi, -1, 1), + ('eff_mixe_to_mu_jpsi', eff_mixe_to_mu_jpsi, -1, 1), + + ('n_mu_jpsi', 68329, 0, 1000000), + # parameter of interest + ('R', 0.91, 0.0, 1.2), + ] + + for t in params: + cmd = '%s[%f, %f, %f]' % t + wspace.factory(cmd) + wspace.var('R').SetTitle('R') + + # fix all background and signal parameters + for t in params[0:-4]: + name = t[0] + print '=> make %8s = %5.5f constant' % (name, + wspace.var(name).getVal()) + wspace.var(name).setConstant() + + #wspace.var('ncomb_mixe_jpsi').setConstant() + #wspace.var('ncomb_pfe_jpsi').setConstant() + #wspace.var('ncomb_mu_jpsi').setConstant() + #wspace.var('npartial_pfe_jpsi').setConstant() + #wspace.var('npartial_mixe_jpsi').setConstant() + + + ### Create expressions + express = [ + # PF-PF electron + 'n_pfe_jpsi("(n_mu_jpsi/R)*(eff_pfe_to_mu_jpsi)", n_mu_jpsi, R, eff_pfe_to_mu_jpsi)', + 'nKstarPsi2S_pfe_jpsi_modified("frac_partial_pfe_jpsi*n_pfe_jpsi", frac_partial_pfe_jpsi, n_pfe_jpsi)', + 'nKstarPlusPsi2S_pfe_jpsi_modified("frac_kstarplus_pfe_jpsi*nKstarPsi2S_pfe_jpsi_modified", frac_kstarplus_pfe_jpsi, nKstarPsi2S_pfe_jpsi_modified)', + # PF-LP electron + 'n_mixe_jpsi("(n_mu_jpsi/R)*(eff_mixe_to_mu_jpsi)", n_mu_jpsi, R, eff_mixe_to_mu_jpsi)', + 'nKstarPsi2S_mixe_jpsi_modified("frac_partial_mixe_jpsi*n_mixe_jpsi", frac_partial_mixe_jpsi, n_mixe_jpsi)', + 'nKstarPlusPsi2S_mixe_jpsi_modified("frac_kstarplus_mixe_jpsi*nKstarPsi2S_mixe_jpsi_modified", frac_kstarplus_mixe_jpsi, nKstarPsi2S_mixe_jpsi_modified)', + ] + + for t in express: + cmd = 'expr::%s' % t + wspace.factory(cmd) + + edit = [ + # PF-PF electron + 'model_pfe_jpsi_modified(model_pfe_jpsi, nsignal_pfe_jpsi=n_pfe_jpsi, nKstarPsi2S_pfe_jpsi=nKstarPsi2S_pfe_jpsi_modified, nKstarPlusPsi2S_pfe_jpsi=nKstarPlusPsi2S_pfe_jpsi_modified)', + # PF-LP electron + 'model_mixe_jpsi_modified(model_mixe_jpsi, nsignal_mixe_jpsi=n_mixe_jpsi, nKstarPsi2S_mixe_jpsi=nKstarPsi2S_mixe_jpsi_modified, nKstarPlusPsi2S_mixe_jpsi=nKstarPlusPsi2S_mixe_jpsi_modified)', + # muon + 'model_mu_jpsi_modified(model_mu_jpsi, nsignal_mu_jpsi=n_mu_jpsi)', + ] + + for t in edit: + cmd = 'EDIT::%s' % t + wspace.factory(cmd) + + wspace.Print("V") + ### Create pdfs + pdfs = [ + # PF-PF electron + ('Gaussian','peff_pfe_to_mu_jpsi', '(eff_hat_pfe_to_mu_jpsi, eff_pfe_to_mu_jpsi, deff_pfe_to_mu_jpsi)'), + # PF-LP electron + ('Gaussian','peff_mixe_to_mu_jpsi', '(eff_hat_mixe_to_mu_jpsi, eff_mixe_to_mu_jpsi, deff_mixe_to_mu_jpsi)'), + ] + + prodpdf = '' + for t in pdfs: + wspace.factory('%s::%s%s' % t) + name = t[1] + prodpdf += "%s, " % name + prodpdf = prodpdf[:-2] # remove last ", " + + + # multiply the pdfs together. use upper case PROD to + # do this + wspace.factory("SIMUL:jointModel(cat,pfe_jpsi=model_pfe_jpsi_modified,mixe_jpsi=model_mixe_jpsi_modified,mu_jpsi=model_mu_jpsi_modified)") + wspace.factory('PROD::model({},{})'.format(prodpdf, 'jointModel')) + + nuis_excluded = ['x', 'R', 'cat', + 'deff_pfe_to_mu_jpsi', 'eff_hat_pfe_to_mu_jpsi', + 'deff_mixe_to_mu_jpsi', 'eff_hat_mixe_to_mu_jpsi', + ] + + ### Define global observables + ### they are not being fitted and they are not loaded from a dataset, + ### but some knowledge exists that allows to set them to a specific value + ### Global Observables are generated once per toy + #globs = ['eff_pfe_to_mu_jpsi', 'eff_mixe_to_mu_jpsi' + globs = ['eff_hat_pfe_to_mu_jpsi', 'eff_hat_mixe_to_mu_jpsi' + ] + + nuis = [] + params = wspace.pdf('model').getVariables() + params_iter = params.createIterator() + param = params_iter.Next() + while param : + if param.GetName() not in (nuis_excluded+globs): + nuis.append(param.GetName()) + param = params_iter.Next() + nuis = ','.join(nuis) + globs = ','.join(globs) + + sets = [('obs', 'x'), # observations + ('poi', 'R'), # parameter of interest + ('nuis', nuis), + ('globs', globs), + ] # nuisance parameters (leave no spaces) + #('nuis', 'n_pfe_jpsi,eff_pfe_psi2s,eff_pfe_jpsi')] # nuisance parameters (leave no spaces) + + for t in sets: + name, parlist = t + wspace.defineSet(name, parlist) + + + #----------------------------------------------------- + # Create model configuration. This is needed for the + # statistical analyses + #----------------------------------------------------- + cfg = rt.RooStats.ModelConfig('cfg') + cfg.SetWorkspace(wspace) + cfg.SetPdf(wspace.pdf('model')) + cfg.SetParametersOfInterest(wspace.set('poi')) + cfg.SetNuisanceParameters(wspace.set('nuis')) + #cfg.SetGlobalObservables(wspace.set('globs')) + + # import model configuration into workspace + getattr(wspace, 'import')(cfg) + + wspace.Print() + + # write out workspace + wspace.writeToFile(wsfilename) + + +if __name__ == "__main__": + + eff_pfe_jpsi, deff_pfe_jpsi = 3.9526e-6, 2.15e-7 + eff_mixe_jpsi, deff_mixe_jpsi = 1.4752e-6, 8.18e-8 + eff_mu_jpsi, deff_mu_jpsi = 14.81e-4, 0.11e-4 + R_SM = 1.0 + R_min, R_max = 0.7, 1.2 + xlabel = 'R_{#psi(2S)}^{signle ratio}' + + wsfilename_pfe_jpsi = 'wspace_psi2s_fixedPartial_pf_wp8.3_HLT_Mu9_IP6.root' + wsfilename_mixe_jpsi = 'wspace_psi2s_fixedPartial_mix_wp8.6_HLT_Mu9_IP6.root' + wsfilename_mu_jpsi = 'wspace_psi2s_muon.root' + wsfilename = 'wspace_single_ratio_rpsi2s_combinedEleCh.root' + + u_eff_pfe_jpsi = ufloat(eff_pfe_jpsi, deff_pfe_jpsi) + u_eff_mixe_jpsi = ufloat(eff_mixe_jpsi, deff_mixe_jpsi) + u_eff_mu_jpsi = ufloat(eff_mu_jpsi, deff_mu_jpsi) + u_eff_pfe_to_mu_jpsi = u_eff_pfe_jpsi / u_eff_mu_jpsi + u_eff_mixe_to_mu_jpsi = u_eff_mixe_jpsi / u_eff_mu_jpsi + print(u_eff_pfe_to_mu_jpsi, u_eff_mixe_to_mu_jpsi) + print(u_eff_pfe_to_mu_jpsi.n, u_eff_pfe_to_mu_jpsi.s, u_eff_mixe_to_mu_jpsi.n, u_eff_mixe_to_mu_jpsi.s) + + createWorkspace('R_psi2s', wsfilename, wsfilename_pfe_jpsi, wsfilename_mixe_jpsi, wsfilename_mu_jpsi, + eff_pfe_to_mu_jpsi=u_eff_pfe_to_mu_jpsi.n, deff_pfe_to_mu_jpsi=u_eff_pfe_to_mu_jpsi.s, + eff_mixe_to_mu_jpsi=u_eff_mixe_to_mu_jpsi.n, deff_mixe_to_mu_jpsi=u_eff_mixe_to_mu_jpsi.s, + ) + plccanvas = analyzeWorkspace('R_psi2s', wsfilename, x_SM=R_SM, x_min=R_min, x_max=R_max, xlabel=xlabel, plot=True, unbinned=False, NPoints=50) + + diff --git a/measurement/plotting.py b/measurement/plotting.py new file mode 100644 index 0000000..d324fa1 --- /dev/null +++ b/measurement/plotting.py @@ -0,0 +1,294 @@ +import uproot +import pandas as pd +import numpy as np +from collections import OrderedDict +from scipy import interp +from rootpy.io import root_open +from rootpy.plotting import Hist, Hist2D +from root_numpy import fill_hist, array2root, array2tree +from root_pandas import to_root +import ROOT +from ROOT import RooFit +import itertools +import PyPDF2 +import os, sys, copy +from helper import * + +#ROOT.gErrorIgnoreLevel=ROOT.kError +#ROOT.RooMsgService.instance().setGlobalKillBelow(RooFit.FATAL) +ROOT.gROOT.SetBatch(ROOT.kTRUE) +ROOT.gStyle.SetOptStat(0) + +''' +import matplotlib as mpl +mpl.use('agg') +import matplotlib.font_manager +from matplotlib import pyplot as plt +from matplotlib import rc +#.Allow for using TeX mode in matplotlib Figures +rc('font',**{'family':'sans-serif','sans-serif':['Computer Modern Roman']}) +rc('text', usetex=True) +plt.rcParams['text.latex.preamble']=[r"\usepackage{lmodern}"] + +ratio=5.0/7.0 +fig_width_pt = 3*246.0 # Get this from LaTeX using \showthe\columnwidth +inches_per_pt = 1.0/72.27 # Convert pt to inch +golden_mean = ratio if ratio != 0.0 else (np.sqrt(5)-1.0)/2.0 # Aesthetic ratio +fig_width = fig_width_pt*inches_per_pt # width in inches +fig_height = fig_width*golden_mean # height in inches +fig_size = [fig_width,fig_height] + +params = {'text.usetex' : True, + 'axes.labelsize': 24, + 'font.size': 24, + 'legend.fontsize': 20, + 'xtick.labelsize': 24, + 'ytick.labelsize': 24, + 'font.family' : 'lmodern', + 'text.latex.unicode': True, + 'axes.grid' : True, + 'text.usetex': True, + 'figure.figsize': fig_size} +plt.rcParams.update(params) +''' + +def pdf_combine(pdf_list, outputfile): + merger = PyPDF2.PdfFileMerger() + for pdf in pdf_list: + merger.append(pdf) + merger.write(outputfile) + +def pdf_sidebyside(out, inputfile): + output = PyPDF2.PdfFileWriter() + reader = [PyPDF2.PdfFileReader(file(in1, "rb")) for in1 in inputfile] + m = min([in1.getNumPages() for in1 in reader]) + print("common pages",m) + for i in range(0,m): + print "adding page common",i + p = [in1.getPage(i) for in1 in reader] + nPages = len(p) + p1 = p[0] + offset_x = 0.0 + for i, p2 in enumerate(p[1:]): + offset_y = -(i+1)*p1.cropBox[1] + (i+1)*p1.cropBox[3] + p1.mergeTranslatedPage(p2, offset_x, offset_y, expand=True) + bounding_box = copy.deepcopy(p1.cropBox) + p1.trimBox.lowerLeft = (bounding_box[0], bounding_box[1]) + p1.trimBox.upperRight = (bounding_box[2], bounding_box[1] + nPages*(bounding_box[3] - bounding_box[1])) + p1.cropBox.lowerLeft = (bounding_box[0], bounding_box[1]) + p1.cropBox.upperRight = (bounding_box[2], bounding_box[1] + nPages*(bounding_box[3] - bounding_box[1])) + output.addPage(p1) + outputStream = file(out, "wb") + output.write(outputStream) + outputStream.close() + +def setup_pad(): + pad = ROOT.TPad("pad", "pad", 0.0, 0.0, 1.0, 1.0) + pad.SetTopMargin(0.08) + pad.SetBottomMargin(0.12) + pad.SetLeftMargin(0.11) + pad.SetRightMargin(0.06) + return pad + +def CMS_lumi(isMC=False): + mark = ROOT.TLatex() + mark.SetNDC() + lumistamp = '2018 (13 TeV)' + fontScale = 1.0 + cmsTextSize = 0.042 * fontScale * 1.25 + extraOverCmsTextSize = 0.76 + extraTextSize = extraOverCmsTextSize*cmsTextSize + mark.SetTextAlign(11) + mark.SetTextSize(cmsTextSize) + mark.SetTextFont(61) + mark.DrawLatex(ROOT.gPad.GetLeftMargin(), 1 - (ROOT.gPad.GetTopMargin() - 0.017), "CMS") + mark.SetTextSize(0.042 * fontScale) + mark.SetTextFont(52) + mark.DrawLatex(ROOT.gPad.GetLeftMargin() + 0.09, 1 - (ROOT.gPad.GetTopMargin() - 0.017), "Simulation Preliminary" if isMC else "Preliminary") + mark.SetTextSize(extraTextSize) + mark.SetTextFont(42) + mark.SetTextAlign(31) + mark.DrawLatex(1 - ROOT.gPad.GetRightMargin(), 1 - (ROOT.gPad.GetTopMargin() - 0.017), lumistamp) + + +def draw_hist(histo, histo_name, x_label, y_label, draw_option='E'): + #histo.SetTitle(histo_name) + histo.GetYaxis().SetTitle(y_label) + histo.GetXaxis().SetTitle(x_label) + histo.SetTitleFont(42) + histo.SetTitleSize(0.05) + histo.GetYaxis().SetTitleOffset(0.9) + histo.GetYaxis().SetTitleFont(42) + histo.GetYaxis().SetTitleSize(0.04) + histo.GetYaxis().SetLabelSize(0.04) + histo.GetYaxis().SetLabelFont(42) + histo.GetXaxis().SetTitleOffset(0.9) + histo.GetXaxis().SetTitleFont(42) + histo.GetXaxis().SetTitleSize(0.04) + histo.GetXaxis().SetLabelSize(0.04) + histo.GetXaxis().SetLabelFont(42) + #histo.Draw(draw_option) + if (histo.GetEntries() > 0): + #histo.DrawNormalized(draw_option) + histo.Draw(draw_option) + else: + histo.Draw(draw_option) + + +def plot_hist(selected_branches, name, color, x_label, hist_bins, outputfile, draw_option='E', logScale=False, xlogScale=False, isMC=False, overflow=False, underflow=False, weights=None): + if not (len(selected_branches) == len(name) == len(color)): + print('lengths do not match') + return + + hist = [Hist(hist_bins['nbins'], hist_bins['xmin'], hist_bins['xmax'], name=n, title='', type='F') for n in name] + _ = [fill_hist(h, branch) for h, branch in zip(hist, selected_branches)] if weights is None else [fill_hist(h, branch, weights=w) for h, branch, w in zip(hist, selected_branches, weights)] + + canvas_name = "c_{}".format(outputfile) + ylabel = 'Events' if len(hist) < 2 else 'Fraction' + + c = ROOT.TCanvas(canvas_name, canvas_name, 800, 600) + c.cd() + pad = setup_pad() + pad.Draw() + pad.cd() + + if logScale: pad.SetLogy() + if xlogScale: pad.SetLogx() + + #l1 = ROOT.TLegend(0.6,0.8,0.92,0.9) + #l1 = ROOT.TLegend(0.7,0.7,0.92,0.9) + l1 = ROOT.TLegend(0.6,0.7,0.92,0.9) + #l1 = ROOT.TLegend(0.6,0.2,0.92,0.4) + l1.SetTextFont(42) + l1.SetTextSize(0.03) + + for h in hist: + x_min = 1 + x_max = h.GetNbinsX() + if overflow: + x_max += 1 + if underflow: + x_min = 0 + h.GetXaxis().SetRange(x_min, x_max) + + y_max = hist[0].GetMaximum() + first_hist = True + for h, n, co in zip(hist, name, color): + h.SetMarkerStyle(0) + h.SetFillStyle(0) + h.SetLineColor(co) + if first_hist: + if len(hist) > 1: + h.SetMaximum(1.3*y_max) + #h.SetMaximum(2.0*y_max) + #h.SetMaximum(1) + draw_hist(h, n, x_label, ylabel, draw_option=draw_option) + first_hist = False + else: + draw_hist(h, n, x_label, ylabel, draw_option='{} SAME'.format(draw_option)) + l1.AddEntry(h, n) + + if len(hist) > 1: l1.Draw("same") + + pad.cd() + CMS_lumi(isMC) + c.cd() + c.Update() + c.SaveAs(outputfile) + c.Close() + +def plot_hist_from_hist(hist, name, color, x_label, y_label, outputfile, draw_option='E', logScale=False, xlogScale=False, isMC=False, overflow=False, underflow=False, weights=None): + if not (len(hist) == len(name) == len(color)): + print('lengths do not match') + return + + canvas_name = "c_{}".format(outputfile) + + c = ROOT.TCanvas(canvas_name, canvas_name, 800, 600) + c.cd() + pad = setup_pad() + pad.Draw() + pad.cd() + + if logScale: pad.SetLogy() + if xlogScale: pad.SetLogx() + + #l1 = ROOT.TLegend(0.6,0.8,0.92,0.9) + #l1 = ROOT.TLegend(0.7,0.7,0.92,0.9) + l1 = ROOT.TLegend(0.6,0.7,0.92,0.9) + #l1 = ROOT.TLegend(0.6,0.2,0.92,0.4) + l1.SetTextFont(42) + l1.SetTextSize(0.03) + + for h in hist: + x_min = 1 + x_max = h.GetNbinsX() + if overflow: + x_max += 1 + if underflow: + x_min = 0 + h.GetXaxis().SetRange(x_min, x_max) + + y_max = hist[0].GetMaximum() + first_hist = True + for h, n, co in zip(hist, name, color): + h.SetMarkerStyle(0) + h.SetFillStyle(0) + h.SetLineColor(co) + if first_hist: + if len(hist) > 1: + h.SetMaximum(1.3*y_max) + #h.SetMaximum(2.0*y_max) + #h.SetMaximum(1) + draw_hist(h, n, x_label, y_label, draw_option=draw_option) + first_hist = False + else: + draw_hist(h, n, x_label, y_label, draw_option='{} SAME'.format(draw_option)) + l1.AddEntry(h, n) + + if len(hist) > 1: l1.Draw("same") + + pad.cd() + CMS_lumi(isMC) + c.cd() + c.Update() + c.SaveAs(outputfile) + c.Close() + +def plot_hist2d(xvar_np, yvar_np, x_label, y_label, hist_bins, outputfile, logScale=False, isMC=False): + hist = Hist2D(hist_bins['nbinx'], hist_bins['xmin'], hist_bins['xmax'], hist_bins['nbiny'], hist_bins['ymin'], hist_bins['ymax'], title='', type='F') + fill_hist(hist, np.vstack((xvar_np[np.isfinite(xvar_np)], yvar_np[np.isfinite(yvar_np)])).T) + + ROOT.gStyle.SetPalette(ROOT.kDarkBodyRadiator) + c = ROOT.TCanvas('c1', 'c1', 800, 600) + pad = setup_pad() + pad.SetLeftMargin(0.08) + pad.SetRightMargin(0.11) + pad.Draw() + pad.cd() + + hist.SetContour(100) + hist.GetYaxis().SetTitle(y_label) + hist.GetXaxis().SetTitle(x_label) + hist.SetTitleFont(42) + hist.SetTitleSize(0.05) + hist.GetYaxis().SetTitleOffset(0.9) + hist.GetYaxis().SetTitleFont(42) + hist.GetYaxis().SetTitleSize(0.04) + hist.GetYaxis().SetLabelSize(0.04) + hist.GetYaxis().SetLabelFont(42) + hist.GetXaxis().SetTitleOffset(0.9) + hist.GetXaxis().SetTitleFont(42) + hist.GetXaxis().SetTitleSize(0.04) + hist.GetXaxis().SetLabelSize(0.04) + hist.GetXaxis().SetLabelFont(42) + if logScale: ROOT.gPad.SetLogz(1) + hist.Draw("colz") + + pad.cd() + CMS_lumi(isMC) + c.cd() + c.Update() + c.SaveAs(outputfile) + c.Close() + diff --git a/measurement/roofit_models.py b/measurement/roofit_models.py new file mode 100644 index 0000000..bc179ca --- /dev/null +++ b/measurement/roofit_models.py @@ -0,0 +1,74 @@ +root_function_DoubleSidedCB=""" + +double DoubleSidedCB2(double x, double mu, double width, double a1, double p1, double a2, double p2) +{ + double u = (x-mu)/width; + double A1 = TMath::Power(p1/TMath::Abs(a1),p1)*TMath::Exp(-a1*a1/2); + double A2 = TMath::Power(p2/TMath::Abs(a2),p2)*TMath::Exp(-a2*a2/2); + double B1 = p1/TMath::Abs(a1) - TMath::Abs(a1); + double B2 = p2/TMath::Abs(a2) - TMath::Abs(a2); + + double result(1); + if (u<-a1) result *= A1*TMath::Power(B1-u,-p1); + else if (u 0): + histo.DrawNormalized(draw_options) + #histo.Draw(draw_options) + else: + histo.Draw(draw_options) + +def plot_hist(branches_dict, config, outputfile, weights=None): + _config = { + 'xlabel': 'x', + 'nbins': 50, + 'xmin': 0.0, + 'xmax': 1.0, + 'overflow': False, + 'underflow': False, + 'SetLogy': False, + 'SetLogx': False, + 'draw_options': 'E', + } + + _config.update(config) + + for i, (name, branch_info) in enumerate(branches_dict.items()): + hist = Hist(_config['nbins'], _config['xmin'], _config['xmax'], name=name, title='', type='F') + if weights is None: + fill_hist(hist, branch_info['branches']) + else: + fill_hist(hist, branch_info['branches'], weights=weights[i]) + + branches_dict[name]['hist'] = hist + + canvas = get_canvas() + canvas.cd() + + l1 = rt.TLegend(0.4,0.2,0.92,0.4) + l1.SetTextSize(0.035) + l1.SetFillStyle(0) + l1.SetBorderSize(0) + + hists = [branch_info['hist'] for branch_info in branches_dict.values()] + for hist in hists: + x_min = 1 + x_max = hist.GetNbinsX() + if _config['overflow']: x_max += 1 + if _config['underflow']: x_min = 0 + hist.GetXaxis().SetRange(x_min, x_max) + + ylabel = 'Events' if len(branches_dict) < 2 else 'a.u.' + + first_hist = True + for name, branch_info in branches_dict.items(): + hist, color = branch_info['hist'], branch_info['color'] + hist.SetMarkerStyle(0) + #hist.SetFillStyle(0) + hist.SetLineColor(color) + if first_hist: + y_max = hist.GetMaximum() + if len(branches_dict) > 1: + hist.SetMaximum(1.3*y_max) + draw_hist(hist, _config['xlabel'], ylabel, draw_options=_config['draw_options']) + first_hist = False + else: + draw_hist(hist, _config['xlabel'], ylabel, draw_options='{} SAME'.format(_config['draw_options'])) + + l1.AddEntry(hist, name) + + if len(hist) > 1: l1.Draw("same") + + CMS_lumi.CMS_lumi(canvas, lumiText, iPos) + + if _config['SetLogy']: rt.gPad.SetLogy() + if _config['SetLogx']: rt.gPad.SetLogx() + + canvas.cd() + canvas.Update() + canvas.RedrawAxis() + canvas.SaveAs(outputfile+'.pdf') + canvas.Close() + + diff --git a/plotting/tdrstyle.py b/plotting/tdrstyle.py new file mode 100644 index 0000000..3b5dc11 --- /dev/null +++ b/plotting/tdrstyle.py @@ -0,0 +1,152 @@ +import ROOT as rt + +def tdrGrid( gridOn): + tdrStyle.SetPadGridX(gridOn) + tdrStyle.SetPadGridY(gridOn) + +#fixOverlay: Redraws the axis +def fixOverlay(): gPad.RedrawAxis() + +def setTDRStyle(): + tdrStyle = rt.TStyle("tdrStyle","Style for P-TDR") + + #for the canvas: + tdrStyle.SetCanvasBorderMode(0) + tdrStyle.SetCanvasColor(rt.kWhite) + tdrStyle.SetCanvasDefH(600) #Height of canvas + tdrStyle.SetCanvasDefW(600) #Width of canvas + tdrStyle.SetCanvasDefX(0) #POsition on screen + tdrStyle.SetCanvasDefY(0) + + + tdrStyle.SetPadBorderMode(0) + #tdrStyle.SetPadBorderSize(Width_t size = 1) + tdrStyle.SetPadColor(rt.kWhite) + tdrStyle.SetPadGridX(False) + tdrStyle.SetPadGridY(False) + tdrStyle.SetGridColor(0) + tdrStyle.SetGridStyle(3) + tdrStyle.SetGridWidth(1) + +#For the frame: + tdrStyle.SetFrameBorderMode(0) + tdrStyle.SetFrameBorderSize(1) + tdrStyle.SetFrameFillColor(0) + tdrStyle.SetFrameFillStyle(0) + tdrStyle.SetFrameLineColor(1) + tdrStyle.SetFrameLineStyle(1) + tdrStyle.SetFrameLineWidth(1) + +#For the histo: + #tdrStyle.SetHistFillColor(1) + #tdrStyle.SetHistFillStyle(0) + tdrStyle.SetHistLineColor(1) + tdrStyle.SetHistLineStyle(0) + tdrStyle.SetHistLineWidth(1) + #tdrStyle.SetLegoInnerR(Float_t rad = 0.5) + #tdrStyle.SetNumberContours(Int_t number = 20) + + tdrStyle.SetEndErrorSize(2) + #tdrStyle.SetErrorMarker(20) + #tdrStyle.SetErrorX(0.) + + tdrStyle.SetMarkerStyle(20) + +#For the fit/function: + tdrStyle.SetOptFit(1) + tdrStyle.SetFitFormat("5.4g") + tdrStyle.SetFuncColor(2) + tdrStyle.SetFuncStyle(1) + tdrStyle.SetFuncWidth(1) + +#For the date: + tdrStyle.SetOptDate(0) + # tdrStyle.SetDateX(Float_t x = 0.01) + # tdrStyle.SetDateY(Float_t y = 0.01) + +# For the statistics box: + tdrStyle.SetOptFile(0) + tdrStyle.SetOptStat(0) # To display the mean and RMS: SetOptStat("mr") + tdrStyle.SetStatColor(rt.kWhite) + tdrStyle.SetStatFont(42) + tdrStyle.SetStatFontSize(0.025) + tdrStyle.SetStatTextColor(1) + tdrStyle.SetStatFormat("6.4g") + tdrStyle.SetStatBorderSize(1) + tdrStyle.SetStatH(0.1) + tdrStyle.SetStatW(0.15) + # tdrStyle.SetStatStyle(Style_t style = 1001) + # tdrStyle.SetStatX(Float_t x = 0) + # tdrStyle.SetStatY(Float_t y = 0) + +# Margins: + tdrStyle.SetPadTopMargin(0.05) + tdrStyle.SetPadBottomMargin(0.13) + tdrStyle.SetPadLeftMargin(0.16) + tdrStyle.SetPadRightMargin(0.02) + +# For the Global title: + + tdrStyle.SetOptTitle(0) + tdrStyle.SetTitleFont(42) + tdrStyle.SetTitleColor(1) + tdrStyle.SetTitleTextColor(1) + tdrStyle.SetTitleFillColor(10) + tdrStyle.SetTitleFontSize(0.05) + # tdrStyle.SetTitleH(0) # Set the height of the title box + # tdrStyle.SetTitleW(0) # Set the width of the title box + # tdrStyle.SetTitleX(0) # Set the position of the title box + # tdrStyle.SetTitleY(0.985) # Set the position of the title box + # tdrStyle.SetTitleStyle(Style_t style = 1001) + # tdrStyle.SetTitleBorderSize(2) + +# For the axis titles: + + tdrStyle.SetTitleColor(1, "XYZ") + tdrStyle.SetTitleFont(42, "XYZ") + tdrStyle.SetTitleSize(0.06, "XYZ") + # tdrStyle.SetTitleXSize(Float_t size = 0.02) # Another way to set the size? + # tdrStyle.SetTitleYSize(Float_t size = 0.02) + tdrStyle.SetTitleXOffset(0.9) + tdrStyle.SetTitleYOffset(1.25) + # tdrStyle.SetTitleOffset(1.1, "Y") # Another way to set the Offset + +# For the axis labels: + + tdrStyle.SetLabelColor(1, "XYZ") + tdrStyle.SetLabelFont(42, "XYZ") + tdrStyle.SetLabelOffset(0.007, "XYZ") + tdrStyle.SetLabelSize(0.05, "XYZ") + +# For the axis: + + tdrStyle.SetAxisColor(1, "XYZ") + tdrStyle.SetStripDecimals(True) + tdrStyle.SetTickLength(0.03, "XYZ") + tdrStyle.SetNdivisions(510, "XYZ") + tdrStyle.SetPadTickX(1) # To get tick marks on the opposite side of the frame + tdrStyle.SetPadTickY(1) + +# Change for log plots: + tdrStyle.SetOptLogx(0) + tdrStyle.SetOptLogy(0) + tdrStyle.SetOptLogz(0) + +# Postscript options: + tdrStyle.SetPaperSize(20.,20.) + # tdrStyle.SetLineScalePS(Float_t scale = 3) + # tdrStyle.SetLineStyleString(Int_t i, const char* text) + # tdrStyle.SetHeaderPS(const char* header) + # tdrStyle.SetTitlePS(const char* pstitle) + + # tdrStyle.SetBarOffset(Float_t baroff = 0.5) + # tdrStyle.SetBarWidth(Float_t barwidth = 0.5) + # tdrStyle.SetPaintTextFormat(const char* format = "g") + # tdrStyle.SetPalette(Int_t ncolors = 0, Int_t* colors = 0) + # tdrStyle.SetTimeOffset(Double_t toffset) + # tdrStyle.SetHistMinimumZero(kTRUE) + + tdrStyle.SetHatchesLineWidth(5) + tdrStyle.SetHatchesSpacing(0.05) + + tdrStyle.cd()