示例#1
0
 def initPdfPlotCfg(self, p):
     """ [Name, plotOnOpt, argAliasInDB, LegendName] """
     pdfPlotTemplate = ["", plotterCfg_styles['allStyle'], None, None]
     p = p + pdfPlotTemplate[len(p):]
     if isinstance(p[0], str):
         self.logger.logDEBUG("Initialize pdfPlot {0}".format(p[0]))
         p[0] = self.process.sourcemanager.get(p[0])
         if p[0] == None:
             errorMsg = "pdfPlot not found in source manager."
             self.logger.logERROR(errorMsg)
             raise RuntimeError("pdfPlot not found in source manager.")
     args = p[0].getParameters(
         ROOT.RooArgSet(Bmass, CosThetaK, CosThetaL, Mumumass, Phimass))
     if not self.process.cfg['args'].Function_name in ['submit', 'run']:
         FitterCore.ArgLooper(args, lambda p: p.Print())
     if type(
             p[2]
     ) is str:  # In case ArgAlias is to be defined with string at the end for all args
         tag = p[2]
         p[2] = {}
         arglist = []
         FitterCore.ArgLooper(args, lambda p: arglist.append(p.GetName()))
         for var in arglist:
             p[2].update({var: var + tag})
     if self.process.cfg['args'].NoFit:
         self.process.cfg['args'].NoImport = True
     if (not self.process.cfg['args'].NoImport):
         FitDBPlayer.initFromDB(self.process.dbplayer.odbfile, args, p[2])
     if not self.process.cfg['args'].Function_name in ['submit']:
         FitterCore.ArgLooper(args, lambda p: p.Print())
     return p
示例#2
0
    def _bookMinimizer(self):
        """_bookMinimizer from StdFitter"""
        #-----------------------------------------------------------------------------------------
        import ctypes

        def myfunc(iArg):
            lo = ctypes.c_double(0.)
            hi = ctypes.c_double(1.)
            self.data.getRange(iArg, lo, hi)
            iArg.setRange(lo, hi)

        FitterCore.ArgLooper(self.data.get(), myfunc)
        try:
            FitterCore.ArgLooper(self.pdf.getObservables(self.data), myfunc)
        except AttributeError:
            print(
                "Error: PDF '{}' not found. Please make sure you have generated mentioned pdf in RooWorkspaces stored in './input' folder"
                .format(self.cfg['pdf']))
            exit()
        #-----------------------------------------------------------------------------------------

        self.fitter = ROOT.StdFitter()
        for opt in self.cfg.get("createNLLOpt", []):
            self.fitter.addNLLOpt(opt)
        minuit = self.fitter.Init(self.pdf, self.data)
        #minuit.setLogFile(self.name+'_minimizer.log')
        minuit.setStrategy(2)
        self._nll = self.fitter.GetNLL()
示例#3
0
 def FitMinos(self):
     """Minos"""
     if len(self.cfg['FitMinos']) > 1 and self.cfg['FitMinos'][1]:
         par = ROOT.RooArgSet()
         FitterCore.ArgLooper(self.args, lambda var: par.add(var),
                              self.cfg['FitMinos'][1])
     else:
         par = self.args
     minosResult = self.fitter.FitMinos(par)
     self.fitResult = FitterCore.GetFitResult(self.name, "StdFitter",
                                              minosResult)
示例#4
0
    def initFromDB(dbfile, args, aliasDict=None, exclude=None):
        print("""Parameter initialization from db file""")
        if not os.path.exists(dbfile):
            print("dbfile doesnot exist..")
            return
        if aliasDict is None:
            aliasDict = {}

        try:
            db = shelve.open(dbfile, "r")
            def initFromDBImp(iArg):
                argName = iArg.GetName()
                aliasName = aliasDict.get(argName, argName)
                if aliasName in db:
                    for setter, getter in FitDBPlayer.funcPair:
                        if setter in ["setMax", "setMin"]:
                            continue
                        getattr(iArg, setter)(
                            *{
                                'getErrorHi': (db[aliasName]['getErrorLo'], db[aliasName]['getErrorHi']),
                                'getErrorLo': (db[aliasName]['getErrorLo'], db[aliasName]['getErrorHi']),
                            }.get(getter, (db[aliasName][getter],))
                        )
                else:
                    print("WARNING\t: Unable to initialize {0}, record {1} not found in {2}.".format(argName, aliasName, dbfile))
            FitterCore.ArgLooper(args, initFromDBImp, exclude, inverseSel=True)
            print ("Initialized parameters from `{0}`.".format(dbfile))
        finally:
            db.close()
示例#5
0
    def _runSetsLoop_SimFit(self):
        iSet=0 #Total subsamples
        rSet=0 #Converged subsamples
        cwd = self.process.work_dir #Avoid using os.getcwd() which gives problems in condor jobs
        while rSet < max(self.cfg['nSetOfToys'], self.process.cfg['args'].nSetOfToys):
            print(">>>> Running for sub-sample number:", iSet+1)
            self._preRunFitSteps(iSet)
            self.fitter.hookProcess(self.process)
            self.fitter.customize()
            self.BookSimData(iSet, self.fitter._bookPdfData)()
            if self.proceedFlag==False: 
                self.proceedFlag=True
                print(">> Got negative expected entries. Subsample is Flagged Bad")
                continue
            if not self.process.cfg['args'].NoFit:
                self.fitter._bookMinimizer()
                self.fitter._preFitSteps()

                #To keep signal and background yields floating
                self.fitter.ToggleConstVar(self.fitter.minimizer.getParameters(self.fitter.dataWithCategories), False, self.fitter.cfg['argPattern']) 

                self.fitter._runFitSteps(); #self.fitter.minosResult = self.fitter.fitter.FitMinos(self.fitter.data[-1].get())
                self._postRunFitSteps(iSet)

            #Remove a year tag from parameters
            for pdf, data, Year in zip(self.fitter.pdf, self.fitter.data, self.fitter.Years): 
                FitterCore.ArgLooper(pdf.getParameters(data), lambda p: p.SetName(p.GetName().split("_{0}".format(Year))[0]), targetArgs=self.fitter.cfg['argPattern'], inverseSel=True)
            iSet += 1
            if (self.treeContent.status==0 and self.treeContent.hesse==0 and self.treeContent.covQual==3) or (self.process.cfg['args'].NoFit): rSet += 1
            self.fitter.reset()
            print(">>>> Successful sub-samples:", rSet, "Failed sub-samples:", iSet-rSet)
        print("Failed subsamples: ", iSet-rSet)
示例#6
0
 def UpdateToDB(dbfile, args, aliasDict=None):
     """Update fit result to a db file"""
     if aliasDict is None:
         aliasDict = {}
     try:
         db = shelve.open(dbfile, writeback=True)
         if isinstance(args, dict):
             modified_args = {}
             for key, val in args.items():
                 aliasName = aliasDict.get(key, key)
                 modified_args[aliasName] = val
             db.update(modified_args)
         elif args.InheritsFrom("RooArgSet"):
             def updateToDBImp(iArg):
                 argName = iArg.GetName()
                 aliasName = aliasDict.get(argName, argName)
                 if aliasName not in db:
                     db[aliasName] = {}
                 for setter, getter in FitDBPlayer.funcPair:
                     try:
                         db[aliasName][getter] = getattr(iArg, getter)()
                     except AttributeError:
                         # In case of no getError for RooNLLVar and so on.
                         pass
             FitterCore.ArgLooper(args, updateToDBImp)
         else:
             raise ValueError("Input arguement of type {0} is not supported".format(type(args)))
     finally:
         db.close()
         print("Updated to Database `{0}`.".format(dbfile))
示例#7
0
 def _runFitSteps(self):
     """Standard fitting procedure to be overwritten."""
     #FitterCore.ArgLooper(self.minimizer.getParameters(self.dataWithCategories), lambda p: p.Print()) #Print all parameters
     if len(self.cfg['fitToCmds']) == 0:
         self.minimizer.fitTo(self.dataWithCategories)
     else:
         if False:
             for cmd in self.cfg['fitToCmds']:
                 mresult = self.minimizer.fitTo(self.dataWithCategories,
                                                *cmd,
                                                ROOT.RooFit.SumW2Error(0),
                                                ROOT.RooFit.Save(1))
                 self.migradResult = mresult.status()
                 self.hesseResult = mresult.status()
                 self._nll = mresult.minNll()
         else:
             print(">>  Standard Fitter Begin")
             self.fitter = ROOT.StdFitter()
             minuit = self.fitter.Init(self.minimizer,
                                       self.dataWithCategories)
             minuit.setStrategy(3)
             mresult = self.fitter.FitMigrad()
             hresult = self.fitter.FitHesse()
             self._nll = self.fitter.GetNLL().getVal()
             self.fitter.fitResult = FitterCore.GetFitResult(
                 self.name, "StdFitter", hresult)
示例#8
0
    def fluctuateFromDB(dbfile, args, aliasDict=None):
        """ Flucturate certain args from db dbfile"""
        if not os.path.exists(dbfile):
            return
        if aliasDict is None:
            aliasDict = {}

        try:
            db = shelve.open(dbfile)
            gaus = ROOT.TF1("gaus", "exp(-0.5*x**2)", -3, 3)
            def flucturateFromDBImp(iArg):
                argName = iArg.GetName()
                aliasName = aliasDict.get(argName, argName)
                if aliasName in db:
                    significance = gaus.GetRandom()
                    arg = db[aliasName]
                    if significance > 0:
                        iArg.setVal(min(arg['getMax'], arg['getVal'] + significance * (arg['getErrorHi'] if math.fabs(arg['getErrorHi']) > 1e-5 else arg['getError'])))
                    else:
                        iArg.setVal(max(arg['getMin'], arg['getVal'] + significance * (arg['getErrorLo'] if math.fabs(arg['getErrorLo']) > 1e-5 else arg['getError'])))
                else:
                    print("ERROR\t: Unable to fluctuate {0}, record not found in {1}.".format(aliasName, dbfile))
            FitterCore.ArgLooper(args, flucturateFromDBImp)
        finally:
            db.close()
示例#9
0
 def FitMigrad(self):
     """Migrad"""
     migradResult = self.fitter.FitMigrad()
     migradResult = self.fitter.FitMigrad()
     self.fitResult = FitterCore.GetFitResult(self.name, "StdFitter",
                                              migradResult)
     print("Migrad Result: ", self.fitResult)
示例#10
0
 def readAll(iArgs):
     def bookOne(arg):
         argName = arg.GetName()
         if argName in self.process.sourcemanager:
             self.cfg['source'][argName] = self.process.sourcemanager.get(argName)
         else:
             self.cfg['source'][argName+".{0}".format(str(self.process.cfg['args'].Year))] = arg
     FitterCore.ArgLooper(iArgs, bookOne)
 def readAll(iArgs):
     def bookOne(arg):
         argName = arg.GetName()
         if argName in self.process.sourcemanager:
             self.cfg['source'][argName] = self.process.sourcemanager.get(argName)
         else:
             self.cfg['source'][argName] = arg
     FitterCore.ArgLooper(iArgs, bookOne)
示例#12
0
        def wrapped_f(self):
            func(self)

            targetParams = ROOT.RooArgSet()
            def setParamsToFluc(arg):
                if arg.GetName() in parList:
                    targetParams.add(arg)
            FitterCore.ArgLooper(self.params, setParamsToFluc)
            FitDBPlayer.fluctuateFromDB(self.cfg['db'].format(binLabel=q2bins[self.process.cfg['binKey']]['label']), targetParams, self.cfg.get('argAliasInDB', []))
示例#13
0
    def preFitSteps_randEffi(self):
        self.args = self.pdf.getParameters(self.data)
        self._preFitSteps_initFromDB()

        # Fluctuate cross-term correction
        effiArgs = ROOT.RooArgSet()
        FitterCore.ArgLooper(self.args, lambda iArg: effiArgs.add(iArg), targetArgs=[r"x\d{1,2}"])
        FitDBPlayer.fluctuateFromDB(self.process.dbplayer.odbfile, effiArgs, self.cfg['argAliasInDB'])

        self._preFitSteps_vetoSmallFs()
        self._preFitSteps_preFit()
示例#14
0
 def templateConfig(cls):
     cfg = FitterCore.templateConfig()
     cfg.update({
         'name': "EfficiencyFitter",
         'data': "effiHistReader.accXrec",
         'dataX': "effiHistReader.h_accXrec_fine_ProjectionX",
         'dataY': "effiHistReader.h_accXrec_fine_ProjectionY",
         'pdf': "effi_sigA",
         'pdfX': "effi_cosl",
         'pdfY': "effi_cosK",
         'updateArgs': True,
     })
     del cfg['createNLLOpt']
     return cfg
示例#15
0
 def _runFitSteps(self):
     if False:
         RooList = [ROOT.RooFit.Minimizer("Minuit2"), ROOT.RooFit.Save(1)]
         for opt in self.cfg.get("createNLLOpt", []):
             RooList.append(opt)
         FitResult = self.pdf.fitTo(self.data, *RooList)
         self.fitResult = FitterCore.GetFitResult(self.name, "StdFitter",
                                                  FitResult)
     else:
         self.FitMigrad()
         if self.cfg.get('FitHesse', False):
             self.FitHesse()
         if self.cfg.get('FitMinos', [False, ()])[0]:
             self.FitMinos()
示例#16
0
 def FitMinos(self):
     """Minos"""
     if len(self.cfg['FitMinos']) > 1 and self.cfg['FitMinos'][1]:
         par = ROOT.RooArgSet()
         FitterCore.ArgLooper(self.args, lambda var: par.add(var), self.cfg['FitMinos'][1])
     else:
         par = self.args
     minosResult = self.fitter.FitMinos(par)
     self.fitResult.update({
         "{0}.{1}".format(self.name, self.cfg['argAliasInDB'].get('minos', 'minos')): {
             'status': minosResult.status(),
             'nll': minosResult.minNll(),
         }
     })
示例#17
0
 def templateConfig(cls):
     cfg = FitterCore.templateConfig()
     cfg.update({
         'name': "StdFitter",
         'data': "dataReader.Fit",
         'pdf': "f",
         'FitHesse': True,
         'FitMinos': [True, ()],
         'createNLLOpt': [ROOT.RooFit.Extended(1), ],
         'argPattern': [r'^.+$', ],
         'argAliasInDB': {},
         'saveToDB': True,
         'argAliasSaveToDB': True,
     })
     return cfg
示例#18
0
 def _preFitSteps(self):
     """Rename parameter names and import values from database"""
     for pdf, data, Year in zip(self.pdf, self.data, self.Years):
         args = pdf.getParameters(
             ROOT.RooArgSet(CosThetaK, CosThetaL, Bmass))
         odbfile = os.path.join(self.process.cwd, "plots_{0}".format(Year),
                                self.process.dbplayer.odbfile)
         if not self.process.cfg['args'].NoImport:
             FitDBPlayer.initFromDB(odbfile,
                                    args,
                                    aliasDict=self.cfg['argAliasInDB'])
         self.ToggleConstVar(args, True)
         self.ToggleConstVar(args, False, self.cfg['argPattern'])
         # Rename parameter names
         FitterCore.ArgLooper(
             args,
             lambda p: p.SetName(p.GetName() + "_{0}".format(Year)),
             targetArgs=self.cfg['argPattern'],
             inverseSel=True)
示例#19
0
 def FitHesse(self):
     """Hesse"""
     hesseResult = self.fitter.FitHesse()
     self.fitResult = FitterCore.GetFitResult(self.name, "StdFitter",
                                              hesseResult)
示例#20
0
def plotPostfitBLK(self, pltName, dataReader, pdfPlots):
    """Specification of plotSimpleBLK for post-fit plots"""
    for pIdx, plt in enumerate(pdfPlots):
        pdfPlots[pIdx] = self.initPdfPlotCfg(plt)

    # Calculate normalization and then draw
    args = pdfPlots[0][0].getParameters(
        ROOT.RooArgSet(Bmass, CosThetaK, CosThetaL))
    nSigDB = args.find('nSig').getVal()
    nSigErrorDB = args.find('nSig').getError()
    nBkgCombDB = args.find('nBkgComb').getVal()
    nBkgCombErrorDB = args.find('nBkgComb').getError()
    flDB = unboundFlToFl(args.find('unboundFl').getVal())
    afbDB = unboundAfbToAfb(args.find('unboundAfb').getVal(), flDB)
    sigFrac = {}
    bkgCombFrac = {}
    for regionName in ["Fit", "SR", "LSB", "USB", "SB", "innerSB", "outerSB"]:
        dataPlots = [
            [
                "{0}.{1}".format(dataReader, regionName), plotterCfg_dataStyle,
                "Data"
            ],
        ]
        for pIdx, p in enumerate(dataPlots):
            dataPlots[pIdx] = self.initDataPlotCfg(p)

        # Bind the 'Bmass' defined in PDF with 'getObservables' to createIntegral
        obs = pdfPlots[1][0].getObservables(dataPlots[0][0])
        FitterCore.ArgLooper(
            obs, lambda p: p.setRange(regionName, *bMassRegions[regionName][
                'range']), ["Bmass"])
        sigFrac[regionName] = pdfPlots[1][0].createIntegral(
            obs, ROOT.RooFit.NormSet(obs),
            ROOT.RooFit.Range(regionName)).getVal()

        obs = pdfPlots[2][0].getObservables(dataPlots[0][0])
        FitterCore.ArgLooper(
            obs, lambda p: p.setRange(regionName, *bMassRegions[regionName][
                'range']), ["Bmass"])
        bkgCombFrac[regionName] = pdfPlots[2][0].createIntegral(
            obs, ROOT.RooFit.NormSet(obs),
            ROOT.RooFit.Range(regionName)).getVal()

        if regionName in ["SB", "innerSB"]:
            sigFrac[regionName] -= sigFrac['SR']
            bkgCombFrac[regionName] -= bkgCombFrac['SR']
        elif regionName == "outerSB":
            sigFrac[regionName] -= sigFrac['SR']
            sigFrac[regionName] -= sigFrac['innerSB']
            bkgCombFrac[regionName] -= bkgCombFrac['SR']
            bkgCombFrac[regionName] -= bkgCombFrac['innerSB']

        nTotal_local = nSigDB * sigFrac[regionName] + nBkgCombDB * bkgCombFrac[
            regionName]
        #  print(regionName, sigFrac[regionName], bkgCombFrac[regionName], nTotal_local)

        # Correct the shape of f_final
        args.find("nSig").setVal(nSigDB * sigFrac[regionName])
        args.find("nBkgComb").setVal(nBkgCombDB * bkgCombFrac[regionName])

        modified_pdfPlots = [
            [
                pdfPlots[0][0], pdfPlots[0][1] + (ROOT.RooFit.Normalization(
                    nTotal_local, ROOT.RooAbsReal.NumEvent), ), None,
                "Total fit"
            ],
            [
                pdfPlots[0][0], pdfPlots[1][1] +
                (ROOT.RooFit.Normalization(nTotal_local,
                                           ROOT.RooAbsReal.NumEvent),
                 ROOT.RooFit.Components(pdfPlots[1][0].GetName())), None,
                "Sigal"
            ],
            [
                pdfPlots[0][0], pdfPlots[2][1] +
                (ROOT.RooFit.Normalization(nTotal_local,
                                           ROOT.RooAbsReal.NumEvent),
                 ROOT.RooFit.Components(pdfPlots[2][0].GetName())), None,
                "Background"
            ],
        ]

        plotFuncs = {
            'B': {
                'func': Plotter.plotFrameB,
                'tag': ""
            },
            'L': {
                'func': Plotter.plotFrameL,
                'tag': "_cosl"
            },
            'K': {
                'func': Plotter.plotFrameK,
                'tag': "_cosK"
            },
        }

        drawLatexFitResults = False
        for frame in 'BLK':
            plotFuncs[frame]['func'](dataPlots=dataPlots,
                                     pdfPlots=modified_pdfPlots)
            if drawLatexFitResults:
                if frame == 'B':
                    Plotter.latex.DrawLatexNDC(.19, .77, "Y_{Signal}")
                    Plotter.latex.DrawLatexNDC(
                        .35, .77,
                        "= {0:.2f}".format(nSigDB * sigFrac[regionName]))
                    Plotter.latex.DrawLatexNDC(
                        .50, .77, "#pm {0:.2f}".format(nSigErrorDB *
                                                       sigFrac[regionName]))
                    Plotter.latex.DrawLatexNDC(.19, .70, "Y_{Background}")
                    Plotter.latex.DrawLatexNDC(
                        .35, .70, "= {0:.2f}".format(nBkgCombDB *
                                                     bkgCombFrac[regionName]))
                    Plotter.latex.DrawLatexNDC(
                        .50, .70, "#pm {0:.2f}".format(
                            nBkgCombErrorDB * bkgCombFrac[regionName]))
                elif frame == 'L':
                    Plotter.latex.DrawLatexNDC(
                        .19, .77, "A_{{FB}} = {0:.2f}".format(afbDB))
                elif frame == 'K':
                    Plotter.latex.DrawLatexNDC(
                        .19, .77, "F_{{L}} = {0:.2f}".format(flDB))
            Plotter.latexQ2(self.process.cfg['binKey'])
            self.canvasPrint(pltName + '_' + regionName +
                             plotFuncs[frame]['tag'])
    def _preFitSteps(self):
        """Prefit uncorrelated term"""
        args = self.pdf.getParameters(self.data)
        if not self.process.cfg['args'].NoImport:
            FitDBPlayer.initFromDB(self.process.dbplayer.odbfile, args)
        self.ToggleConstVar(args, isConst=True)

        # Disable xTerm correction and fit to 1-D
        args.find('hasXTerm{}'.format(self.cfg['label'])).setVal(0)

        h_accXrec_fine_ProjectionX = self.process.sourcemanager.get(
            self.cfg['dataX'])
        h_accXrec_fine_ProjectionY = self.process.sourcemanager.get(
            self.cfg['dataY'])
        effi_cosl = self.process.sourcemanager.get(self.cfg['pdfX'])
        effi_cosK = self.process.sourcemanager.get(self.cfg['pdfY'])
        for proj, pdf, var, argPats in [
            (h_accXrec_fine_ProjectionX, effi_cosl, CosThetaL, [r"^l\d+\w*"]),
            (h_accXrec_fine_ProjectionY, effi_cosK, CosThetaK, [r"^k\d+\w*"])
        ]:
            hdata = ROOT.RooDataHist("hdata", "", ROOT.RooArgList(var),
                                     ROOT.RooFit.Import(proj))
            self.ToggleConstVar(args, isConst=False, targetArgs=argPats)

            theList = ROOT.RooLinkedList()
            Err = ROOT.RooFit.Minos(True)
            theSave = ROOT.RooFit.Save()  #Python discards temporary objects
            Verbose = ROOT.RooFit.Verbose(0)
            Strategy = ROOT.RooFit.Strategy(2)
            PrintLevel = ROOT.RooFit.PrintLevel(-1)
            theList.Add(theSave)
            theList.Add(Verbose)
            theList.Add(PrintLevel)
            theList.Add(Err)
            theList.Add(Strategy)
            Res = pdf.chi2FitTo(hdata, theList)
            Res = pdf.chi2FitTo(hdata, theList)
            Res.Print("v")
            FitDBPlayer.UpdateToDB(
                self.process.dbplayer.odbfile,
                FitterCore.GetFitResult(self.name, var.GetName(), Res))

            ################## AlTernatively #######################
            #chi2 = pdf.createChi2(hdata, ROOT.RooFit.Save(1))
            #m=ROOT.RooMinuit(chi2)
            #m.setPrintLevel(3)
            #m.migrad()
            #m.hesse()
            #m.minos()
            #RooRes=m.save()

            self.ToggleConstVar(args, isConst=True, targetArgs=argPats)

        effi_norm = 'effi_norm{}'.format(self.cfg['label'])
        args.find('hasXTerm{}'.format(self.cfg['label'])).setVal(1)
        args.find(effi_norm).setConstant(False)
        Res2D = self.pdf.chi2FitTo(self.data, ROOT.RooFit.Minos(True),
                                   ROOT.RooFit.Save(), ROOT.RooFit.Strategy(2),
                                   ROOT.RooFit.PrintLevel(-1))
        Res2D.Print()
        #args.find(effi_norm).setVal(args.find(effi_norm).getVal() / 4.)
        args.find(effi_norm).setConstant(True)

        # Fix uncorrelated term and for later update with xTerms in main fit step
        self.ToggleConstVar(args, isConst=False, targetArgs=[r"^x\d+\w*"])
    def _runFitSteps(self):
        h2_accXrec = self.process.sourcemanager.get(self.cfg['datahist'])
        args = self.pdf.getParameters(self.data)
        nPar = 0
        floaters = {}  #Saving indices for cross terms

        def GetTFunction():
            nonlocal nPar
            args_it = args.createIterator()
            arg = args_it.Next()
            effi_sigA_formula = self.pdf.formula().formulaString()
            paramDict = {}
            for p in range(self.pdf.formula().actualDependents().getSize()):
                paramDict[self.pdf.formula().getParameter(p).GetName()] = p
            effi_sigA_formula = effi_sigA_formula.replace(
                "x[{0}]".format(paramDict['CosThetaL']), "x")
            effi_sigA_formula = effi_sigA_formula.replace(
                "x[{0}]".format(paramDict['CosThetaK']), "y")
            while arg:
                if any(
                        re.match(pat, arg.GetName()) for pat in
                    ["effi_norm", "hasXTerm", r"^l\d+\w*", r"^k\d+\w*"]):
                    effi_sigA_formula = effi_sigA_formula.replace(
                        'x[{0}]'.format(paramDict[arg.GetName()]),
                        "({0})".format(arg.getVal()))
                elif re.match(r"^x\d+\w*$", arg.GetName()):
                    effi_sigA_formula = effi_sigA_formula.replace(
                        'x[{0}]'.format(paramDict[arg.GetName()]),
                        "[{0}]".format(nPar))
                    floaters[nPar] = arg.GetName()
                    nPar = nPar + 1
                arg = args_it.Next()
            f2_effi_sigA = ROOT.TF2("f2_effi_sigA", effi_sigA_formula, -1, 1,
                                    -1, 1)
            return f2_effi_sigA

        if True:  #Using RooMinuit
            if False:  #Using {} optimization
                fitter = ROOT.StdFitter()
                minuit = fitter.Init(self.pdf, self.data)
                minuit.setStrategy(2)
                minuit.optimizeConst(1)
                minuit.setPrintLevel(0)
                self._nll = fitter.GetNLL()
                self.fitter = fitter.FitMigrad()
                self.fitter = fitter.FitHesse()
                self.fitter = fitter.FitMinos(
                    self.pdf.getParameters(self.data).selectByAttrib(
                        "Constant", 0))
            else:  #Using chi2 optimization
                self.fitter = self.pdf.chi2FitTo(self.data,
                                                 ROOT.RooFit.Minos(1),
                                                 ROOT.RooFit.Strategy(2),
                                                 ROOT.RooFit.Save(1),
                                                 ROOT.RooFit.PrintLevel(-1))
                self.fitter = self.pdf.chi2FitTo(self.data,
                                                 ROOT.RooFit.Minos(1),
                                                 ROOT.RooFit.Strategy(2),
                                                 ROOT.RooFit.Save(1),
                                                 ROOT.RooFit.PrintLevel(-1))
            self.fitter.Print("v")
            FitDBPlayer.UpdateToDB(
                self.process.dbplayer.odbfile,
                FitterCore.GetFitResult(self.name, "XTerm", self.fitter))

            setStyle()
            canvas = ROOT.TCanvas()
            latex = ROOT.TLatex()
            h2_effi_2D_comp = h2_accXrec.Clone("h2_effi_2D_comp")
            h2_effi_2D_comp.Reset("ICESM")
            pdfhist = h2_accXrec.Clone("pdfhist")
            pdfhist.Reset("ICESM")
            self.pdf.fillHistogram(pdfhist,
                                   ROOT.RooArgList(CosThetaL, CosThetaK))

            #Text plot comparison
            canvas2 = ROOT.TCanvas()
            for lBin, KBin in itertools.product(
                    list(range(1,
                               h2_effi_2D_comp.GetNbinsX() + 1)),
                    list(range(1,
                               h2_effi_2D_comp.GetNbinsY() + 1))):
                if h2_accXrec.GetBinContent(lBin, KBin) == 0:
                    h2_effi_2D_comp.SetBinContent(lBin, KBin, 0)
                    print(">> ** Warning ** Empty bins: (l, k)", lBin, KBin)
                else:
                    h2_effi_2D_comp.SetBinContent(
                        lBin, KBin,
                        pdfhist.GetBinContent(lBin, KBin) /
                        h2_accXrec.GetBinContent(lBin, KBin))

            ROOT.gStyle.SetPalette(
                ROOT.kLightTemperature)  #kColorPrintableOnGrey)
            h2_effi_2D_text = h2_effi_2D_comp.Clone(
                "h2_effi_2D_text")  #; h2_effi_2D_text.Reset("ICESM")
            h2_effi_2D_text.Draw("COLZ")
            h2_effi_2D_text.GetYaxis().SetTitleOffset(1)
            ROOT.gStyle.SetPaintTextFormat("6.4g")
            pdfhist.SetBarOffset(0.25)
            pdfhist.Draw("TEXT SAME")
            canvas2.SetRightMargin(0.115)
            canvas2.SetLeftMargin(0.1)
            h2_accXrec.SetBarOffset(0.)
            h2_accXrec.Draw("TEXT SAME")
            h2_effi_2D_comp.SetBarOffset(-0.25)
            h2_effi_2D_comp.Draw("TEXT SAME")
            ROOT.TLatex().DrawLatexNDC(
                0.12, 0.96,
                r"#scale[0.8]{{{latexLabel}}}".format(latexLabel=q2bins[
                    self.process.cfg['binKey']]['latexLabel']))

            canvas.cd()
            h2_effi_2D_comp.SetMinimum(0)
            h2_effi_2D_comp.SetMaximum(1.5)
            h2_effi_2D_comp.SetTitleOffset(1.6, "X")
            h2_effi_2D_comp.SetTitleOffset(1.8, "Y")
            h2_effi_2D_comp.SetTitleOffset(1.5, "Z")
            h2_effi_2D_comp.SetZTitle(
                "#varepsilon_{fit}/#varepsilon_{measured}")
            h2_effi_2D_comp.Draw("LEGO2")
            latex.DrawLatexNDC(
                .08, .93, "#font[61]{CMS} #font[52]{#scale[0.8]{Simulation}}")
            chi2ndf = self.fitter.minNll() / (
                h2_effi_2D_comp.GetNbinsX() * h2_effi_2D_comp.GetNbinsY() -
                self.pdf.getParameters(self.data).selectByAttrib(
                    "Constant", 0).getSize())
            latex.DrawLatexNDC(.08, .89,
                               "#chi^{{2}}/ndf={0:.2f}".format(chi2ndf))
            print("2D Efficiency Chi^2/ndf: ", chi2ndf)

        else:  #Using TMinuit (This section can be used only if pdf is defined in terms of expression (e.g. RooFormulaVar). Does not work for RooProdPdf or RooProduct)
            f2_effi_sigA = GetTFunction()
            fitter = ROOT.EfficiencyFitter()
            self.minimizer = fitter.Init(nPar, h2_accXrec, f2_effi_sigA)
            self.minimizer.SetPrintLevel(0)  #Pritam
            self.minimizer.mnexcm("SET STR", ctypes.c_double(2.), 1,
                                  ctypes.c_int(0))
            for xIdx in range(nPar):
                self.minimizer.DefineParameter(xIdx, floaters[xIdx], 0., 1E-4,
                                               -1E+2, 1E+2)
            MigStatus = self.minimizer.Migrad()
            MigStatus = self.minimizer.Migrad()
            MinosStatus = self.minimizer.Command("MINOS")

            # Check if efficiency is positive definite
            f2_max_x, f2_max_y = ctypes.c_double(0.), ctypes.c_double(.0)
            f2_min_x, f2_min_y = ctypes.c_double(0.), ctypes.c_double(.0)
            f2_effi_sigA.GetMaximumXY(f2_max_x, f2_max_y)
            f2_effi_sigA.GetMinimumXY(f2_min_x, f2_min_y)
            print("Sanitary check: Efficiency ranges from {0:.2e} to {1:.2e}".
                  format(f2_effi_sigA.Eval(f2_min_x, f2_min_y),
                         f2_effi_sigA.Eval(f2_max_x, f2_max_y)))
            EfficiencyFitter.isPosiDef(f2_effi_sigA)

            #Update parameter values
            parVal, parErr = ctypes.c_double(.0), ctypes.c_double(.0)
            eplus, eminus, eparab, gcc = ctypes.c_double(0.), ctypes.c_double(
                0.), ctypes.c_double(.0), ctypes.c_double(0.)
            for xIdx in range(nPar):
                self.minimizer.GetParameter(xIdx, parVal, parErr)
                self.minimizer.mnerrs(xIdx, eplus, eminus, eparab, gcc)
                arg = args.find(floaters[xIdx])
                arg.setVal(parVal.value)
                arg.setError(parErr.value)
                arg.setAsymError(eplus.value, eminus.value)

            # Plot comparison between fitting result to data
            setStyle()
            canvas = ROOT.TCanvas()
            latex = ROOT.TLatex()
            h2_effi_2D_comp = h2_accXrec.Clone("h2_effi_2D_comp")
            h2_effi_2D_comp.Reset("ICESM")
            pdfhist = h2_accXrec.Clone("pdfhist")
            pdfhist.Reset("ICESM")
            self.pdf.fillHistogram(pdfhist,
                                   ROOT.RooArgList(CosThetaL, CosThetaK))
            print(
                "2D Efficiency Chi^2/ndf: ",
                fitter.GetChi2() /
                (h2_effi_2D_comp.GetNbinsX() * h2_effi_2D_comp.GetNbinsY() -
                 nPar))
            print("TMinuit Status: ", self.minimizer.GetStatus(), MigStatus,
                  MinosStatus)

            #Text plot comparison
            canvas2 = ROOT.TCanvas()
            for lBin, KBin in itertools.product(
                    list(range(1,
                               h2_effi_2D_comp.GetNbinsX() + 1)),
                    list(range(1,
                               h2_effi_2D_comp.GetNbinsY() + 1))):
                if h2_accXrec.GetBinContent(lBin, KBin) == 0:
                    h2_effi_2D_comp.SetBinContent(lBin, KBin, 0)
                    print(">> ** Warning ** Empty bins: (l, k)", lBin, KBin)
                else:
                    h2_effi_2D_comp.SetBinContent(
                        lBin, KBin,
                        f2_effi_sigA.Eval(
                            h2_accXrec.GetXaxis().GetBinCenter(lBin),
                            h2_accXrec.GetYaxis().GetBinCenter(KBin)) /
                        h2_accXrec.GetBinContent(lBin, KBin))

            ROOT.gStyle.SetPalette(
                ROOT.kLightTemperature)  #kColorPrintableOnGrey)
            h2_effi_2D_text = h2_effi_2D_comp.Clone(
                "h2_effi_2D_text")  #; h2_effi_2D_text.Reset("ICESM")
            h2_effi_2D_text.Draw("COLZ")
            h2_effi_2D_text.GetYaxis().SetTitleOffset(1)
            ROOT.gStyle.SetPaintTextFormat("6.4g")
            pdfhist.SetBarOffset(0.25)
            pdfhist.Draw("TEXT SAME")
            canvas2.SetRightMargin(0.115)
            canvas2.SetLeftMargin(0.1)
            h2_accXrec.SetBarOffset(0.)
            h2_accXrec.Draw("TEXT SAME")
            h2_effi_2D_comp.SetBarOffset(-0.25)
            h2_effi_2D_comp.Draw("TEXT SAME")
            ROOT.TLatex().DrawLatexNDC(
                0.12, 0.96,
                r"#scale[0.8]{{{latexLabel}}}".format(latexLabel=q2bins[
                    self.process.cfg['binKey']]['latexLabel']))

            canvas.cd()
            h2_effi_2D_comp.SetMinimum(0)
            h2_effi_2D_comp.SetMaximum(1.5)
            h2_effi_2D_comp.SetTitleOffset(1.6, "X")
            h2_effi_2D_comp.SetTitleOffset(1.8, "Y")
            h2_effi_2D_comp.SetTitleOffset(1.5, "Z")
            h2_effi_2D_comp.SetZTitle(
                "#varepsilon_{fit}/#varepsilon_{measured}")
            h2_effi_2D_comp.Draw("LEGO2")
            latex.DrawLatexNDC(
                .08, .93, "#font[61]{CMS} #font[52]{#scale[0.8]{Simulation}}")
            latex.DrawLatexNDC(
                .08, .89, "#chi^{{2}}/ndf={0:.2f}".format(
                    fitter.GetChi2() / (h2_effi_2D_comp.GetNbinsX() *
                                        h2_effi_2D_comp.GetNbinsY() - nPar)))
            FitterCore.ArgLooper(args, lambda p: p.Print())

        ####################################
        path = os.path.join(modulePath, self.process.work_dir, "Efficiency")
        if not os.path.exists(path):
            os.mkdir(path)
        os.chdir(path)
        ####################################
        canvas.Print("effi_2D_comp{}_{}.pdf".format(
            self.cfg['label'], q2bins[self.process.cfg['binKey']]['label']))
        canvas2.cd()
        canvas2.Print("effi_2D_TEXT{}_{}.pdf".format(
            self.cfg['label'], q2bins[self.process.cfg['binKey']]['label']))
        os.chdir(os.path.join(modulePath, self.process.work_dir))