Example #1
0
def alpha(channel):

    nElec = channel.count('e')
    nMuon = channel.count('m')
    nLept = nElec + nMuon
    nBtag = channel.count('b')
    
    # Channel-dependent settings
    # Background function. Semi-working options are: EXP, EXP2, EXPN, EXPTAIL
    if nLept == 0:
        treeName = 'SR'
        signName = 'XZh'
        colorVjet = sample['DYJetsToNuNu']['linecolor']
        triName = "HLT_PFMET"
        leptCut = "0==0"
        topVeto = selection["TopVetocut"]
        massVar = "X_cmass"
        binFact = 1
        #fitFunc = "EXP"
        #fitFunc = "EXP2"
        #fitFunc = "EXPN"
        #fitFunc = "EXPTAIL"
        fitFunc = "EXPN" if nBtag < 2 else "EXP"
        fitAltFunc = "EXPTAIL" if nBtag < 2 else "EXPTAIL"
        fitFuncVjet = "ERFEXP" if nBtag < 2 else "ERFEXP"
        fitFuncVV   = "EXPGAUS"
        fitFuncTop  = "GAUS2"
    elif nLept == 1:
        treeName = 'WCR'
        signName = 'XWh'
        colorVjet = sample['WJetsToLNu']['linecolor']
        triName = "HLT_Ele" if nElec > 0 else "HLT_Mu"
        leptCut = "isWtoEN" if nElec > 0 else "isWtoMN"
        topVeto = selection["TopVetocut"]
        massVar = "X_mass"
        binFact = 2
        if nElec > 0:
            fitFunc = "EXP" if nBtag < 2 else "EXP"
            fitAltFunc  = "EXPTAIL" if nBtag < 2 else "EXPTAIL"
        else:
            fitFunc = "EXPTAIL" if nBtag < 2 else "EXP"
            fitAltFunc  = "EXPN" if nBtag < 2 else "EXPTAIL"
        fitFuncVjet = "ERFEXP" if nBtag < 2 else "ERFEXP"
        fitFuncVV   = "EXPGAUS"
        fitFuncTop  = "GAUS3" if nBtag < 2 else "GAUS2"
    else:
        treeName = 'XZh'
        signName = 'XZh'
        colorVjet = sample['DYJetsToLL']['linecolor']
        triName = "HLT_Ele" if nElec > 0 else "HLT_Mu"
        leptCut = "isZtoEE" if nElec > 0 else "isZtoMM"
        topVeto = "0==0"
        massVar = "X_mass"
        binFact = 5
        if nElec > 0:
            fitFunc = "EXP" if nBtag < 2 else "EXP"
            fitAltFunc = "POW" if nBtag < 2 else "POW"
        else:
            fitFunc = "EXP" if nBtag < 2 else "EXP"
            fitAltFunc = "POW" if nBtag < 2 else "POW"
        fitFuncVjet = "ERFEXP" if nBtag < 2 else "EXP"
        fitFuncVV   = "EXPGAUS2"
        fitFuncTop  = "GAUS"
    
    btagCut = selection["2Btag"] if nBtag == 2 else selection["1Btag"]
    
    print "--- Channel", channel, "---"
    print "  number of electrons:", nElec, " muons:", nMuon, " b-tags:", nBtag
    print "  read tree:", treeName, "and trigger:", triName
    if ALTERNATIVE: print "  using ALTERNATIVE fit functions"
    print "-"*11*2
    
    # Silent RooFit
    RooMsgService.instance().setGlobalKillBelow(RooFit.FATAL)
    
    #*******************************************************#
    #                                                       #
    #              Variables and selections                 #
    #                                                       #
    #*******************************************************#
    
    # Define all the variables from the trees that will be used in the cuts and fits
    # this steps actually perform a "projection" of the entire tree on the variables in thei ranges, so be careful once setting the limits
    X_mass = RooRealVar(  massVar, "m_{X}" if nLept > 0 else "m_{T}^{X}", XBINMIN, XBINMAX, "GeV")
    J_mass = RooRealVar( "fatjet1_prunedMassCorr",       "corrected pruned mass", HBINMIN, HBINMAX, "GeV")
    CSV1 = RooRealVar(   "fatjet1_CSVR1",                           "",        -1.e99,   1.e4     )
    CSV2 = RooRealVar(   "fatjet1_CSVR2",                           "",        -1.e99,   1.e4     )
    nBtag = RooRealVar(  "fatjet1_nBtag",                           "",            0.,   4        )
    CSVTop = RooRealVar( "bjet1_CSVR",                              "",        -1.e99,   1.e4     )
    isZtoEE = RooRealVar("isZtoEE",                                 "",            0.,   2        )
    isZtoMM = RooRealVar("isZtoMM",                                 "",            0.,   2        )
    isWtoEN = RooRealVar("isWtoEN",                                 "",            0.,   2        )
    isWtoMN = RooRealVar("isWtoMN",                                 "",            0.,   2        )
    weight = RooRealVar( "eventWeightLumi",                         "",         -1.e9,   1.       )
    
    # Define the RooArgSet which will include all the variables defined before
    # there is a maximum of 9 variables in the declaration, so the others need to be added with 'add'
    variables = RooArgSet(X_mass, J_mass, CSV1, CSV2, nBtag, CSVTop)
    variables.add(RooArgSet(isZtoEE, isZtoMM, isWtoEN, isWtoMN, weight))
    
    # Define the ranges in fatJetMass - these will be used to define SB and SR
    J_mass.setRange("LSBrange", LOWMIN, LOWMAX)
    J_mass.setRange("HSBrange", HIGMIN, HIGMAX)
    J_mass.setRange("VRrange",  LOWMAX, SIGMIN)
    J_mass.setRange("SRrange",  SIGMIN, SIGMAX)
    J_mass.setBins(54)
    
    # Define the selection for the various categories (base + SR / LSBcut / HSBcut )
    baseCut = leptCut + " && " + btagCut + "&&" + topVeto
    massCut = massVar + ">%d" % XBINMIN
    baseCut += " && " + massCut
    
    # Cuts
    SRcut  = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), SIGMIN, J_mass.GetName(), SIGMAX)
    LSBcut = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), LOWMIN, J_mass.GetName(), LOWMAX)
    HSBcut = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), HIGMIN, J_mass.GetName(), HIGMAX)
    SBcut  = baseCut + " && ((%s>%d && %s<%d) || (%s>%d && %s<%d))" % (J_mass.GetName(), LOWMIN, J_mass.GetName(), LOWMAX, J_mass.GetName(), HIGMIN, J_mass.GetName(), HIGMAX)
    VRcut  = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), LOWMAX, J_mass.GetName(), SIGMIN)
    
    # Binning
    binsJmass = RooBinning(HBINMIN, HBINMAX)
    binsJmass.addUniform(HBINS, HBINMIN, HBINMAX)
    binsXmass = RooBinning(XBINMIN, XBINMAX)
    binsXmass.addUniform(binFact*XBINS, XBINMIN, XBINMAX)
    
    #*******************************************************#
    #                                                       #
    #                      Input files                      #
    #                                                       #
    #*******************************************************#
    
    # Import the files using TChains (separately for the bkg "classes" that we want to describe: here DY and VV+ST+TT)
    treeData = TChain(treeName)
    treeMC   = TChain(treeName)
    treeVjet = TChain(treeName)
    treeVV   = TChain(treeName)
    treeTop  = TChain(treeName)
#    treeSign = {}
#    nevtSign = {}
    
    # Read data
    pd = getPrimaryDataset(triName)
    if len(pd)==0: raw_input("Warning: Primary Dataset not recognized, continue?")
    for i, s in enumerate(pd): treeData.Add(NTUPLEDIR + s + ".root")
    
    # Read V+jets backgrounds
    for i, s in enumerate(["WJetsToLNu_HT", "DYJetsToNuNu_HT", "DYJetsToLL_HT"]):
        for j, ss in enumerate(sample[s]['files']): treeVjet.Add(NTUPLEDIR + ss + ".root")
    
    # Read VV backgrounds
    for i, s in enumerate(["VV"]):
        for j, ss in enumerate(sample[s]['files']): treeVV.Add(NTUPLEDIR + ss + ".root")
    
    # Read Top backgrounds
    for i, s in enumerate(["ST", "TTbar"]):
        for j, ss in enumerate(sample[s]['files']): treeTop.Add(NTUPLEDIR + ss + ".root")
        
    # Sum all background MC
    treeMC.Add(treeVjet)
    treeMC.Add(treeVV)
    treeMC.Add(treeTop)
    
    # create a dataset to host data in sideband (using this dataset we are automatically blind in the SR!)
    setDataSB = RooDataSet("setDataSB", "setDataSB", variables, RooFit.Cut(SBcut), RooFit.WeightVar(weight), RooFit.Import(treeData))
    setDataLSB = RooDataSet("setDataLSB", "setDataLSB", variables, RooFit.Import(setDataSB), RooFit.Cut(LSBcut), RooFit.WeightVar(weight))
    setDataHSB = RooDataSet("setDataHSB", "setDataHSB", variables, RooFit.Import(setDataSB), RooFit.Cut(HSBcut), RooFit.WeightVar(weight))
    
    # Observed data (WARNING, BLIND!)
    setDataSR = RooDataSet("setDataSR", "setDataSR", variables, RooFit.Cut(SRcut), RooFit.WeightVar(weight), RooFit.Import(treeData))
    setDataVR = RooDataSet("setDataVR", "setDataVR", variables, RooFit.Cut(VRcut), RooFit.WeightVar(weight), RooFit.Import(treeData)) # Observed in the VV mass, just for plotting purposes
    
    # same for the bkg datasets from MC, where we just apply the base selections (not blind)
    setVjet = RooDataSet("setVjet", "setVjet", variables, RooFit.Cut(baseCut), RooFit.WeightVar(weight), RooFit.Import(treeVjet))
    setVjetSB = RooDataSet("setVjetSB", "setVjetSB", variables, RooFit.Import(setVjet), RooFit.Cut(SBcut), RooFit.WeightVar(weight))
    setVjetSR = RooDataSet("setVjetSR", "setVjetSR", variables, RooFit.Import(setVjet), RooFit.Cut(SRcut), RooFit.WeightVar(weight))
    setVV = RooDataSet("setVV", "setVV", variables, RooFit.Cut(baseCut), RooFit.WeightVar(weight), RooFit.Import(treeVV))
    setVVSB = RooDataSet("setVVSB", "setVVSB", variables, RooFit.Import(setVV), RooFit.Cut(SBcut), RooFit.WeightVar(weight))
    setVVSR = RooDataSet("setVVSR", "setVVSR", variables, RooFit.Import(setVV), RooFit.Cut(SRcut), RooFit.WeightVar(weight))
    setTop = RooDataSet("setTop", "setTop", variables, RooFit.Cut(baseCut), RooFit.WeightVar(weight), RooFit.Import(treeTop))
    setTopSB = RooDataSet("setTopSB", "setTopSB", variables, RooFit.Import(setTop), RooFit.Cut(SBcut), RooFit.WeightVar(weight))
    setTopSR = RooDataSet("setTopSR", "setTopSR", variables, RooFit.Import(setTop), RooFit.Cut(SRcut), RooFit.WeightVar(weight))
    
    print "  Data events SB: %.2f" % setDataSB.sumEntries()
    print "  V+jets entries: %.2f" % setVjet.sumEntries()
    print "  VV, VH entries: %.2f" % setVV.sumEntries()
    print "  Top,ST entries: %.2f" % setTop.sumEntries()
    
    
    # the relative normalization of the varius bkg is taken from MC by counting all the events in the full fatJetMass range
    #coef = RooRealVar("coef", "coef", setVV.sumEntries()/setVjet.sumEntries(),0.,1.)
    coef_VV_Vjet = RooRealVar("coef2_1", "coef2_1", setVV.sumEntries()/setVjet.sumEntries(), 0., 1.)
    coef_Top_VVVjet = RooRealVar("coef3_21", "coef3_21", setTop.sumEntries()/(setVjet.sumEntries()+setVV.sumEntries()),0.,1.);
    coef_VV_Vjet.setConstant(True)
    coef_Top_VVVjet.setConstant(True)
    
    # Define entries
    entryVjet = RooRealVar("entryVjets",  "V+jets normalization", setVjet.sumEntries(), 0., 1.e6)
    entryVV = RooRealVar("entryVV",  "VV normalization", setVV.sumEntries(), 0., 1.e6)
    entryTop = RooRealVar("entryTop",  "Top normalization", setTop.sumEntries(), 0., 1.e6)
    
    entrySB = RooRealVar("entrySB",  "Data SB normalization", setDataSB.sumEntries(SBcut), 0., 1.e6)
    entrySB.setError(math.sqrt(entrySB.getVal()))
    
    entryLSB = RooRealVar("entryLSB",  "Data LSB normalization", setDataSB.sumEntries(LSBcut), 0., 1.e6)
    entryLSB.setError(math.sqrt(entryLSB.getVal()))

    entryHSB = RooRealVar("entryHSB",  "Data HSB normalization", setDataSB.sumEntries(HSBcut), 0., 1.e6)
    entryHSB.setError(math.sqrt(entryHSB.getVal()))
    
    #*******************************************************#
    #                                                       #
    #                    NORMALIZATION                      #
    #                                                       #
    #*******************************************************#
    
    # set reasonable ranges for J_mass and X_mass
    # these are used in the fit in order to avoid ROOFIT to look in regions very far away from where we are fitting 
    J_mass.setRange("h_reasonable_range", LOWMIN, HIGMAX)
    X_mass.setRange("X_reasonable_range", XBINMIN, XBINMAX)
    
    # Set RooArgSets once for all, see https://root.cern.ch/phpBB3/viewtopic.php?t=11758
    jetMassArg = RooArgSet(J_mass)
    
    #*******************************************************#
    #                                                       #
    #                 V+jets normalization                  #
    #                                                       #
    #*******************************************************#
    
    # Variables for V+jets
    constVjet   = RooRealVar("constVjet",   "slope of the exp",      -0.020, -1.,   0.)
    offsetVjet  = RooRealVar("offsetVjet",  "offset of the erf",     30.,   -50., 200.)
    widthVjet   = RooRealVar("widthVjet",   "width of the erf",     100.,     1., 200.)
    offsetVjet.setConstant(True)
    a0Vjet = RooRealVar("a0Vjet", "width of the erf", -0.1, -5, 0)
    a1Vjet = RooRealVar("a1Vjet", "width of the erf", 0.6,  0, 5)
    a2Vjet = RooRealVar("a2Vjet", "width of the erf", -0.1, -1, 1)
    
    # Define V+jets model
    if fitFuncVjet == "ERFEXP": modelVjet = RooErfExpPdf("modelVjet", "error function for V+jets mass", J_mass, constVjet, offsetVjet, widthVjet)
    elif fitFuncVjet == "EXP": modelVjet = RooExponential("modelVjet", "exp for V+jets mass", J_mass, constVjet)
    elif fitFuncVjet == "POL": modelVjet = RooChebychev("modelVjet", "polynomial for V+jets mass", J_mass, RooArgList(a0Vjet, a1Vjet, a2Vjet))
    elif fitFuncVjet == "POW": modelVjet = RooGenericPdf("modelVjet", "powerlaw for X mass", "@0^@1", RooArgList(J_mass, a0Vjet))
    else:
        print "  ERROR! Pdf", fitFuncVjet, "is not implemented for Vjets"
        exit()
    
    # fit to main bkg in MC (whole range)
    frVjet = modelVjet.fitTo(setVjet, RooFit.SumW2Error(True), RooFit.Range("h_reasonable_range"), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.Save(1), RooFit.PrintLevel(1 if VERBOSE else -1))
    
    # integrals and number of events
    iSBVjet = modelVjet.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("LSBrange,HSBrange"))
    iLSBVjet = modelVjet.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("LSBrange"))
    iHSBVjet = modelVjet.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("HSBrange"))
    iSRVjet = modelVjet.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("SRrange"))
    iVRVjet = modelVjet.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("VRrange"))
    # Do not remove the following lines, integrals are computed here
    iALVjet = modelVjet.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg))
    nSBVjet = iSBVjet.getVal()/iALVjet.getVal()*setVjet.sumEntries(SBcut)
    nLSBVjet = iLSBVjet.getVal()/iALVjet.getVal()*setVjet.sumEntries(LSBcut)
    nHSBVjet = iHSBVjet.getVal()/iALVjet.getVal()*setVjet.sumEntries(HSBcut)
    nSRVjet = iSRVjet.getVal()/iALVjet.getVal()*setVjet.sumEntries(SRcut)
    
    drawPlot("JetMass_Vjet", channel, J_mass, modelVjet, setVjet, binsJmass, frVjet)

    if VERBOSE: print "********** Fit result [JET MASS Vjets] *"+"*"*40, "\n", frVjet.Print(), "\n", "*"*80
    
    #*******************************************************#
    #                                                       #
    #                 VV, VH normalization                  #
    #                                                       #
    #*******************************************************#
    
    # Variables for VV
    # Error function and exponential to model the bulk
    constVV  = RooRealVar("constVV",  "slope of the exp",  -0.030, -0.1,   0.)
    offsetVV = RooRealVar("offsetVV", "offset of the erf", 90.,     1., 300.)
    widthVV  = RooRealVar("widthVV",  "width of the erf",  50.,     1., 100.)
    erfrVV   = RooErfExpPdf("baseVV", "error function for VV jet mass", J_mass, constVV, offsetVV, widthVV)
    expoVV   = RooExponential("baseVV", "error function for VV jet mass", J_mass, constVV)
    # gaussian for the V mass peak
    meanVV   = RooRealVar("meanVV",   "mean of the gaussian",           90.,    60., 100.)
    sigmaVV  = RooRealVar("sigmaVV",  "sigma of the gaussian",          10.,     6.,  30.)
    fracVV   = RooRealVar("fracVV",   "fraction of gaussian wrt erfexp", 3.2e-1, 0.,   1.)
    gausVV   = RooGaussian("gausVV",  "gaus for VV jet mass", J_mass, meanVV, sigmaVV)
    # gaussian for the H mass peak
    meanVH   = RooRealVar("meanVH",   "mean of the gaussian",           125.,   100., 150.)
    sigmaVH  = RooRealVar("sigmaVH",  "sigma of the gaussian",           30.,     5.,  40.)
    fracVH   = RooRealVar("fracVH",   "fraction of gaussian wrt erfexp",  1.5e-2, 0.,   1.)
    gausVH   = RooGaussian("gausVH",  "gaus for VH jet mass", J_mass, meanVH, sigmaVH)
    
    # Define VV model
    if fitFuncVV == "ERFEXPGAUS": modelVV  = RooAddPdf("modelVV",   "error function + gaus for VV jet mass", RooArgList(gausVV, erfrVV), RooArgList(fracVV))
    elif fitFuncVV == "ERFEXPGAUS2": modelVV  = RooAddPdf("modelVV",   "error function + gaus + gaus for VV jet mass", RooArgList(gausVH, gausVV, erfrVV), RooArgList(fracVH, fracVV))
    elif fitFuncVV == "EXPGAUS": modelVV  = RooAddPdf("modelVV",   "error function + gaus for VV jet mass", RooArgList(gausVV, expoVV), RooArgList(fracVV))
    elif fitFuncVV == "EXPGAUS2": modelVV  = RooAddPdf("modelVV",   "error function + gaus + gaus for VV jet mass", RooArgList(gausVH, gausVV, expoVV), RooArgList(fracVH, fracVV))
    else:
        print "  ERROR! Pdf", fitFuncVV, "is not implemented for VV"
        exit()
    
    # fit to secondary bkg in MC (whole range)
    frVV = modelVV.fitTo(setVV, RooFit.SumW2Error(True), RooFit.Range("h_reasonable_range"), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.Save(1), RooFit.PrintLevel(1 if VERBOSE else -1))
    
    # integrals and number of events
    iSBVV = modelVV.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("LSBrange,HSBrange"))
    iLSBVV = modelVV.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("LSBrange"))
    iHSBVV = modelVV.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("HSBrange"))
    iSRVV = modelVV.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("SRrange"))
    iVRVV = modelVV.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("VRrange"))
    # Do not remove the following lines, integrals are computed here
    iALVV = modelVV.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg))
    nSBVV = iSBVV.getVal()/iALVV.getVal()*setVV.sumEntries(SBcut)
    nLSBVV = iLSBVV.getVal()/iALVV.getVal()*setVV.sumEntries(LSBcut)
    nHSBVV = iHSBVV.getVal()/iALVV.getVal()*setVV.sumEntries(HSBcut)
    nSRVV = iSRVV.getVal()/iALVV.getVal()*setVV.sumEntries(SRcut)
    rSBSRVV = nSRVV/nSBVV
    
    drawPlot("JetMass_VV", channel, J_mass, modelVV, setVV, binsJmass, frVV)
    
    if VERBOSE: print "********** Fit result [JET MASS VV] ****"+"*"*40, "\n", frVV.Print(), "\n", "*"*80
    
    #*******************************************************#
    #                                                       #
    #                 Top, ST normalization                 #
    #                                                       #
    #*******************************************************#
    
    # Variables for Top
    # Error Function * Exponential to model the bulk
    constTop  = RooRealVar("constTop",  "slope of the exp", -0.030,   -1.,   0.)
    offsetTop = RooRealVar("offsetTop", "offset of the erf", 175.0,   50., 250.)
    widthTop  = RooRealVar("widthTop",  "width of the erf",  100.0,    1., 300.)
    gausTop   = RooGaussian("baseTop",  "gaus for Top jet mass", J_mass, offsetTop, widthTop)
    erfrTop   = RooErfExpPdf("baseTop", "error function for Top jet mass", J_mass, constTop, offsetTop, widthTop)
    # gaussian for the W mass peak
    meanW     = RooRealVar("meanW",     "mean of the gaussian",           80., 70., 90.)
    sigmaW    = RooRealVar("sigmaW",    "sigma of the gaussian",          10.,  2., 20.)
    fracW     = RooRealVar("fracW",     "fraction of gaussian wrt erfexp", 0.1, 0.,  1.)
    gausW     = RooGaussian("gausW",    "gaus for W jet mass", J_mass, meanW, sigmaW)
    # gaussian for the Top mass peak
    meanT     = RooRealVar("meanT",     "mean of the gaussian",           175., 150., 200.)
    sigmaT    = RooRealVar("sigmaT",    "sigma of the gaussian",           12.,   5.,  50.)
    fracT     = RooRealVar("fracT",     "fraction of gaussian wrt erfexp",  0.1,  0.,   1.)
    gausT     = RooGaussian("gausT",    "gaus for T jet mass", J_mass, meanT, sigmaT)
    
    # Define Top model
    if fitFuncTop == "ERFEXPGAUS2": modelTop = RooAddPdf("modelTop",   "error function + gaus + gaus for Top jet mass", RooArgList(gausW, gausT, erfrTop), RooArgList(fracW, fracT))
    elif fitFuncTop == "ERFEXPGAUS": modelTop = RooAddPdf("modelTop",   "error function + gaus for Top jet mass", RooArgList(gausT, erfrTop), RooArgList(fracT))
    elif fitFuncTop == "GAUS3": modelTop  = RooAddPdf("modelTop",   "gaus + gaus + gaus for Top jet mass", RooArgList(gausW, gausT, gausTop), RooArgList(fracW, fracT))
    elif fitFuncTop == "GAUS2": modelTop  = RooAddPdf("modelTop",   "gaus + gaus for Top jet mass", RooArgList(gausT, gausTop), RooArgList(fracT))
    elif fitFuncTop == "GAUS": modelTop  = RooGaussian("modelTop", "gaus for Top jet mass", J_mass, offsetTop, widthTop)
    else:
        print "  ERROR! Pdf", fitFuncTop, "is not implemented for Top"
        exit()
    
    # fit to secondary bkg in MC (whole range)
    frTop = modelTop.fitTo(setTop, RooFit.SumW2Error(True), RooFit.Range("h_reasonable_range"), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.Save(1), RooFit.PrintLevel(1 if VERBOSE else -1))
    
    # integrals and number of events
    iSBTop = modelTop.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("LSBrange,HSBrange"))
    iLSBTop = modelTop.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("LSBrange"))
    iHSBTop = modelTop.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("HSBrange"))
    iSRTop = modelTop.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("SRrange"))
    iVRTop = modelTop.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("VRrange"))
    # Do not remove the following lines, integrals are computed here
    iALTop = modelTop.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg))
    nSBTop = iSBTop.getVal()/iALTop.getVal()*setTop.sumEntries(SBcut)
    nLSBTop = iLSBTop.getVal()/iALTop.getVal()*setTop.sumEntries(LSBcut)
    nHSBTop = iHSBTop.getVal()/iALTop.getVal()*setTop.sumEntries(HSBcut)
    nSRTop = iSRTop.getVal()/iALTop.getVal()*setTop.sumEntries(SRcut)
    
    drawPlot("JetMass_Top", channel, J_mass, modelTop, setTop, binsJmass, frTop)
    
    if VERBOSE: print "********** Fit result [JET MASS TOP] ***"+"*"*40, "\n", frTop.Print(), "\n", "*"*80
    
    #*******************************************************#
    #                                                       #
    #                 All bkg normalization                 #
    #                                                       #
    #*******************************************************#
    
    constVjet.setConstant(True)
    offsetVjet.setConstant(True)
    widthVjet.setConstant(True)
    a0Vjet.setConstant(True)
    a1Vjet.setConstant(True)
    a2Vjet.setConstant(True)
    
    constVV.setConstant(True)
    offsetVV.setConstant(True)
    widthVV.setConstant(True)
    meanVV.setConstant(True)
    sigmaVV.setConstant(True)
    fracVV.setConstant(True)
    meanVH.setConstant(True)
    sigmaVH.setConstant(True)
    fracVH.setConstant(True)
    
    constTop.setConstant(True)
    offsetTop.setConstant(True)
    widthTop.setConstant(True)
    meanW.setConstant(True)
    sigmaW.setConstant(True)
    fracW.setConstant(True)
    meanT.setConstant(True)
    sigmaT.setConstant(True)
    fracT.setConstant(True)
    
    
    # Final background model by adding the main+secondary pdfs (using 'coef': ratio of the secondary/main, from MC)
    model = RooAddPdf("model", "model", RooArgList(modelTop, modelVV, modelVjet), RooArgList(coef_Top_VVVjet, coef_VV_Vjet))#FIXME
    model.fixAddCoefRange("h_reasonable_range")
    
    # Extended fit model to data in SB
    # all the 3 sidebands (Low / High / the 2 combined) could be used
    # currently using the LOW+HIGH (the others are commented out)
    yieldLSB = RooRealVar("yieldLSB", "Lower SB normalization",  10, 0., 1.e6)
    yieldHSB = RooRealVar("yieldHSB", "Higher SB normalization", 10, 0., 1.e6)
    yieldSB  = RooRealVar("yieldSB",  "All SB normalization",    10, 0., 1.e6)
    #model_ext = RooExtendPdf("model_ext", "extended p.d.f",   model,  yieldLSB)
    #model_ext = RooExtendPdf("model_ext", "extended p.d.f",   model,  yieldHSB)
    model_ext = RooExtendPdf("model_ext", "extended p.d.f",   model,  yieldSB)
    #frMass = model_ext.fitTo(setDataSB, RooFit.ConditionalObservables(RooArgSet(J_mass)),RooFit.SumW2Error(True),RooFit.Extended(True),RooFit.Range("LSBrange"),RooFit.PrintLevel(-1))
    #frMass = model_ext.fitTo(setDataSB, RooFit.ConditionalObservables(RooArgSet(J_mass)),RooFit.SumW2Error(True),RooFit.Extended(True),RooFit.Range("HSBrange"),RooFit.PrintLevel(-1))
    #frMass = model_ext.fitTo(setDataSB, RooFit.ConditionalObservables(RooArgSet(J_mass)), RooFit.SumW2Error(True), RooFit.Extended(True), RooFit.Range("LSBrange,HSBrange"), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.PrintLevel(1 if VERBOSE else -1))
    
    #print "********** Fit result [JET MASS DATA] **"+"*"*40
    #print frMass.Print()
    #print "*"*80
    
    # Calculate integral of the model obtained from the fit to data (fraction of PDF that is within a given region)
    #nSB = model_ext.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("LSBrange,HSBrange"))
    #nSB = model_ext.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("LSBrange"))
    #nSB = model_ext.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("HSBrange"))
    #nSR = model_ext.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("SRrange"))
    #nVR = model_ext.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("VRrange"))
    
    # scale the yieldSB from SB to SR using the ratio of the PDFs defined by the two integrals
    SRyield = RooFormulaVar("SRyield", "extrapolation to SR","(@0-@1*@3-@2*@4) * @5/@6 +@1*@7+@2*@8", RooArgList(entrySB, entryVV, entryTop, iSBVV, iSBTop, iSRVjet, iSBVjet, iSRVV, iSRTop))
    VRyield = RooFormulaVar("VRyield", "extrapolation to VR","(@0-@1*@3-@2*@4) * @5/@6 +@1*@7+@2*@8", RooArgList(entrySB, entryVV, entryTop, iSBVV, iSBTop, iVRVjet, iSBVjet, iVRVV, iVRTop))
    HSByield = RooFormulaVar("SRyield", "extrapolation to SR","(@0-@1*@3-@2*@4) * @5/@6 +@1*@7+@2*@8", RooArgList(entryLSB, entryVV, entryTop, iLSBVV, iLSBTop, iHSBVjet, iLSBVjet, iHSBVV, iHSBTop))
    #   RooFormulaVar SRyield("SRyield","extrapolation to SR","(@0/@1)*@2",RooArgList(*nSR,*nSB,yieldLowerSB))
    #   RooFormulaVar SRyield("SRyield","extrapolation to SR","(@0/@1)*@2",RooArgList(*nSR,*nSB,yieldHigherSB))
    #SRyield = RooFormulaVar("SRyield", "extrapolation to SR","(@0/@1)*@2", RooArgList(nSR, nSB, entrySB))
    
    bkgYield            = SRyield.getVal()
    bkgYield_error      = math.sqrt(SRyield.getPropagatedError(frVjet)**2 + SRyield.getPropagatedError(frVV)**2 + SRyield.getPropagatedError(frTop)**2 + (entrySB.getError()*rSBSRVV)**2)
    bkgNorm             = entrySB.getVal() + SRyield.getVal() + VRyield.getVal()
    bkgYield_eig_norm   = RooRealVar("predSR_eig_norm", "expected yield in SR", bkgYield, 0., 1.e6)
    bkgYieldExt         = HSByield.getVal()
    
    drawPlot("JetMass", channel, J_mass, model, setDataSB, binsJmass, None, None, "", bkgNorm, True)

    
    print channel, "normalization = %.3f +/- %.3f, observed = %.0f" % (bkgYield, bkgYield_error, setDataSR.sumEntries() if not BLIND else -1)
    if VERBOSE: raw_input("Press Enter to continue...")
Example #2
0
def alpha(channel):

    nElec = channel.count("e")
    nMuon = channel.count("m")
    nLept = nElec + nMuon
    nBtag = channel.count("b")

    # Channel-dependent settings
    # Background function. Semi-working options are: EXP, EXP2, EXPN, EXPTAIL
    if nLept == 0:
        treeName = "SR"
        signName = "XZh"
        colorVjet = sample["DYJetsToNuNu"]["linecolor"]
        triName = "HLT_PFMET"
        leptCut = "0==0"
        topVeto = selection["TopVetocut"]
        massVar = "X_cmass"
        binFact = 1
        fitFunc = "EXPN" if nBtag < 2 else "EXPN"
        fitAltFunc = "EXPTAIL" if nBtag < 2 else "EXPTAIL"
        fitFuncVjet = "ERFEXP" if nBtag < 2 else "EXP"
        fitAltFuncVjet = "POL" if nBtag < 2 else "POL"
        fitFuncVV = "EXPGAUS" if nBtag < 2 else "EXPGAUS"
        fitFuncTop = "GAUS2"
    elif nLept == 1:
        treeName = "WCR"
        signName = "XWh"
        colorVjet = sample["WJetsToLNu"]["linecolor"]
        triName = "HLT_Ele" if nElec > 0 else "HLT_Mu"
        leptCut = "isWtoEN" if nElec > 0 else "isWtoMN"
        topVeto = selection["TopVetocut"]
        massVar = "X_mass"
        binFact = 2
        if nElec > 0:
            fitFunc = "EXPTAIL" if nBtag < 2 else "EXPN"
            fitAltFunc = "EXPN" if nBtag < 2 else "POW"
        else:
            fitFunc = "EXPN" if nBtag < 2 else "EXPN"
            fitAltFunc = "EXPTAIL" if nBtag < 2 else "POW"
        fitFuncVjet = "ERFEXP" if nBtag < 2 else "EXP"
        fitAltFuncVjet = "POL" if nBtag < 2 else "POL"
        fitFuncVV = "EXPGAUS" if nBtag < 2 else "EXPGAUS"
        fitFuncTop = "GAUS3" if nBtag < 2 else "GAUS2"
    else:
        treeName = "XZh"
        signName = "XZh"
        colorVjet = sample["DYJetsToLL"]["linecolor"]
        triName = "HLT_Ele" if nElec > 0 else "HLT_Mu"
        leptCut = "isZtoEE" if nElec > 0 else "isZtoMM"
        topVeto = "X_dPhi>2.5"
        massVar = "X_mass"
        binFact = 2
        if nElec > 0:
            fitFunc = "EXPTAIL" if nBtag < 2 else "EXPTAIL"
            fitAltFunc = "POW" if nBtag < 2 else "POW"
        else:
            fitFunc = "EXPTAIL" if nBtag < 2 else "EXPTAIL"
            fitAltFunc = "POW" if nBtag < 2 else "POW"
        fitFuncVjet = "ERFEXP" if nBtag < 2 and nElec < 1 else "EXP"
        fitAltFuncVjet = "POL" if nBtag < 2 else "POL"
        fitFuncVV = "EXPGAUS2" if nBtag < 2 else "EXPGAUS2"
        fitFuncTop = "GAUS"

    btagCut = selection["2Btag"] if nBtag == 2 else selection["1Btag"]

    print "--- Channel", channel, "---"
    print "  number of electrons:", nElec, " muons:", nMuon, " b-tags:", nBtag
    print "  read tree:", treeName, "and trigger:", triName
    if ALTERNATIVE:
        print "  using ALTERNATIVE fit functions"
    print "-" * 11 * 2

    # Silent RooFit
    RooMsgService.instance().setGlobalKillBelow(RooFit.FATAL)

    # *******************************************************#
    #                                                       #
    #              Variables and selections                 #
    #                                                       #
    # *******************************************************#

    # Define all the variables from the trees that will be used in the cuts and fits
    # this steps actually perform a "projection" of the entire tree on the variables in thei ranges, so be careful once setting the limits
    X_mass = RooRealVar(massVar, "m_{X}" if nLept > 0 else "m_{T}^{X}", XBINMIN, XBINMAX, "GeV")
    J_mass = RooRealVar("fatjet1_prunedMassCorr", "jet corrected pruned mass", HBINMIN, HBINMAX, "GeV")
    CSV1 = RooRealVar("fatjet1_CSVR1", "", -1.0e99, 1.0e4)
    CSV2 = RooRealVar("fatjet1_CSVR2", "", -1.0e99, 1.0e4)
    nB = RooRealVar("fatjet1_nBtag", "", 0.0, 4)
    CSVTop = RooRealVar("bjet1_CSVR", "", -1.0e99, 1.0e4)
    X_dPhi = RooRealVar("X_dPhi", "", 0.0, 3.15)
    isZtoEE = RooRealVar("isZtoEE", "", 0.0, 2)
    isZtoMM = RooRealVar("isZtoMM", "", 0.0, 2)
    isWtoEN = RooRealVar("isWtoEN", "", 0.0, 2)
    isWtoMN = RooRealVar("isWtoMN", "", 0.0, 2)
    weight = RooRealVar("eventWeightLumi", "", -1.0e9, 1.0)

    # Define the RooArgSet which will include all the variables defined before
    # there is a maximum of 9 variables in the declaration, so the others need to be added with 'add'
    variables = RooArgSet(X_mass, J_mass, CSV1, CSV2, nB, CSVTop, X_dPhi)
    variables.add(RooArgSet(isZtoEE, isZtoMM, isWtoEN, isWtoMN, weight))

    # set reasonable ranges for J_mass and X_mass
    # these are used in the fit in order to avoid ROOFIT to look in regions very far away from where we are fitting
    # (honestly, it is not clear to me why it is necessary, but without them the fit often explodes)
    J_mass.setRange("h_reasonable_range", LOWMIN, HIGMAX)
    X_mass.setRange("X_reasonable_range", XBINMIN, XBINMAX)

    # Set RooArgSets once for all, see https://root.cern.ch/phpBB3/viewtopic.php?t=11758
    jetMassArg = RooArgSet(J_mass)
    # Define the ranges in fatJetMass - these will be used to define SB and SR
    J_mass.setRange("LSBrange", LOWMIN, LOWMAX)
    J_mass.setRange("HSBrange", HIGMIN, HIGMAX)
    J_mass.setRange("VRrange", LOWMAX, SIGMIN)
    J_mass.setRange("SRrange", SIGMIN, SIGMAX)

    # Set binning for plots
    J_mass.setBins(HBINS)
    X_mass.setBins(binFact * XBINS)

    # Define the selection for the various categories (base + SR / LSBcut / HSBcut )
    baseCut = leptCut + " && " + btagCut + "&&" + topVeto
    massCut = massVar + ">%d" % XBINMIN
    baseCut += " && " + massCut

    # Cuts
    SRcut = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), SIGMIN, J_mass.GetName(), SIGMAX)
    LSBcut = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), LOWMIN, J_mass.GetName(), LOWMAX)
    HSBcut = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), HIGMIN, J_mass.GetName(), HIGMAX)
    SBcut = baseCut + " && ((%s>%d && %s<%d) || (%s>%d && %s<%d))" % (
        J_mass.GetName(),
        LOWMIN,
        J_mass.GetName(),
        LOWMAX,
        J_mass.GetName(),
        HIGMIN,
        J_mass.GetName(),
        HIGMAX,
    )
    VRcut = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), LOWMAX, J_mass.GetName(), SIGMIN)

    # Binning
    binsJmass = RooBinning(HBINS, HBINMIN, HBINMAX)
    # binsJmass.addUniform(HBINS, HBINMIN, HBINMAX)
    binsXmass = RooBinning(binFact * XBINS, XBINMIN, XBINMAX)
    # binsXmass.addUniform(binFact*XBINS, XBINMIN, XBINMAX)

    # *******************************************************#
    #                                                       #
    #                      Input files                      #
    #                                                       #
    # *******************************************************#

    # Import the files using TChains (separately for the bkg "classes" that we want to describe: here DY and VV+ST+TT)
    treeData = TChain(treeName)
    treeMC = TChain(treeName)
    treeVjet = TChain(treeName)
    treeVV = TChain(treeName)
    treeTop = TChain(treeName)
    treeSign = {}
    nevtSign = {}
    for i, m in enumerate(massPoints):
        treeSign[m] = TChain(treeName)

    # Read data
    pd = getPrimaryDataset(triName)
    if len(pd) == 0:
        raw_input("Warning: Primary Dataset not recognized, continue?")
    for i, s in enumerate(pd):
        treeData.Add(NTUPLEDIR + s + ".root")

    # Read V+jets backgrounds
    for i, s in enumerate(["WJetsToLNu_HT", "DYJetsToNuNu_HT", "DYJetsToLL_HT"]):
        for j, ss in enumerate(sample[s]["files"]):
            treeVjet.Add(NTUPLEDIR + ss + ".root")

    # Read VV backgrounds
    for i, s in enumerate(["VV"]):
        for j, ss in enumerate(sample[s]["files"]):
            treeVV.Add(NTUPLEDIR + ss + ".root")

    # Read Top backgrounds
    for i, s in enumerate(["ST", "TTbar"]):
        for j, ss in enumerate(sample[s]["files"]):
            treeTop.Add(NTUPLEDIR + ss + ".root")

    # Read signals
    for i, m in enumerate(massPoints):
        for j, ss in enumerate(sample["%s_M%d" % (signName, m)]["files"]):
            treeSign[m].Add(NTUPLEDIR + ss + ".root")
            sfile = TFile(NTUPLEDIR + ss + ".root", "READ")
            shist = sfile.Get("Counters/Counter")
            nevtSign[m] = shist.GetBinContent(1)
            sfile.Close()

    # Sum all background MC
    treeMC.Add(treeVjet)
    treeMC.Add(treeVV)
    treeMC.Add(treeTop)

    # create a dataset to host data in sideband (using this dataset we are automatically blind in the SR!)
    setDataSB = RooDataSet(
        "setDataSB", "setDataSB", variables, RooFit.Cut(SBcut), RooFit.WeightVar(weight), RooFit.Import(treeData)
    )
    setDataLSB = RooDataSet(
        "setDataLSB", "setDataLSB", variables, RooFit.Import(setDataSB), RooFit.Cut(LSBcut), RooFit.WeightVar(weight)
    )
    setDataHSB = RooDataSet(
        "setDataHSB", "setDataHSB", variables, RooFit.Import(setDataSB), RooFit.Cut(HSBcut), RooFit.WeightVar(weight)
    )

    # Observed data (WARNING, BLIND!)
    setDataSR = RooDataSet(
        "setDataSR", "setDataSR", variables, RooFit.Cut(SRcut), RooFit.WeightVar(weight), RooFit.Import(treeData)
    )
    setDataVR = RooDataSet(
        "setDataVR", "setDataVR", variables, RooFit.Cut(VRcut), RooFit.WeightVar(weight), RooFit.Import(treeData)
    )  # Observed in the VV mass, just for plotting purposes

    setDataSRSB = RooDataSet(
        "setDataSRSB",
        "setDataSRSB",
        variables,
        RooFit.Cut("(" + SRcut + ") || (" + SBcut + ")"),
        RooFit.WeightVar(weight),
        RooFit.Import(treeData),
    )

    # same for the bkg datasets from MC, where we just apply the base selections (not blind)
    setVjet = RooDataSet(
        "setVjet", "setVjet", variables, RooFit.Cut(baseCut), RooFit.WeightVar(weight), RooFit.Import(treeVjet)
    )
    setVjetSB = RooDataSet(
        "setVjetSB", "setVjetSB", variables, RooFit.Import(setVjet), RooFit.Cut(SBcut), RooFit.WeightVar(weight)
    )
    setVjetSR = RooDataSet(
        "setVjetSR", "setVjetSR", variables, RooFit.Import(setVjet), RooFit.Cut(SRcut), RooFit.WeightVar(weight)
    )
    setVV = RooDataSet(
        "setVV", "setVV", variables, RooFit.Cut(baseCut), RooFit.WeightVar(weight), RooFit.Import(treeVV)
    )
    setVVSB = RooDataSet(
        "setVVSB", "setVVSB", variables, RooFit.Import(setVV), RooFit.Cut(SBcut), RooFit.WeightVar(weight)
    )
    setVVSR = RooDataSet(
        "setVVSR", "setVVSR", variables, RooFit.Import(setVV), RooFit.Cut(SRcut), RooFit.WeightVar(weight)
    )
    setTop = RooDataSet(
        "setTop", "setTop", variables, RooFit.Cut(baseCut), RooFit.WeightVar(weight), RooFit.Import(treeTop)
    )
    setTopSB = RooDataSet(
        "setTopSB", "setTopSB", variables, RooFit.Import(setTop), RooFit.Cut(SBcut), RooFit.WeightVar(weight)
    )
    setTopSR = RooDataSet(
        "setTopSR", "setTopSR", variables, RooFit.Import(setTop), RooFit.Cut(SRcut), RooFit.WeightVar(weight)
    )

    print "  Data events SB: %.2f" % setDataSB.sumEntries()
    print "  V+jets entries: %.2f" % setVjet.sumEntries()
    print "  VV, VH entries: %.2f" % setVV.sumEntries()
    print "  Top,ST entries: %.2f" % setTop.sumEntries()

    nVV = RooRealVar("nVV", "VV normalization", setVV.sumEntries(SBcut), 0.0, 2 * setVV.sumEntries(SBcut))
    nTop = RooRealVar("nTop", "Top normalization", setTop.sumEntries(SBcut), 0.0, 2 * setTop.sumEntries(SBcut))
    nVjet = RooRealVar("nVjet", "Vjet normalization", setDataSB.sumEntries(), 0.0, 2 * setDataSB.sumEntries(SBcut))
    nVjet2 = RooRealVar("nVjet2", "Vjet2 normalization", setDataSB.sumEntries(), 0.0, 2 * setDataSB.sumEntries(SBcut))

    # Apply Top SF
    nTop.setVal(nTop.getVal() * topSF[nLept][nBtag])
    nTop.setError(nTop.getVal() * topSFErr[nLept][nBtag])

    # Define entries
    entryVjet = RooRealVar("entryVjets", "V+jets normalization", setVjet.sumEntries(), 0.0, 1.0e6)
    entryVV = RooRealVar("entryVV", "VV normalization", setVV.sumEntries(), 0.0, 1.0e6)
    entryTop = RooRealVar("entryTop", "Top normalization", setTop.sumEntries(), 0.0, 1.0e6)

    entrySB = RooRealVar("entrySB", "Data SB normalization", setDataSB.sumEntries(SBcut), 0.0, 1.0e6)
    entrySB.setError(math.sqrt(entrySB.getVal()))

    entryLSB = RooRealVar("entryLSB", "Data LSB normalization", setDataSB.sumEntries(LSBcut), 0.0, 1.0e6)
    entryLSB.setError(math.sqrt(entryLSB.getVal()))

    entryHSB = RooRealVar("entryHSB", "Data HSB normalization", setDataSB.sumEntries(HSBcut), 0.0, 1.0e6)
    entryHSB.setError(math.sqrt(entryHSB.getVal()))

    ###################################################################################
    #        _   _                                                                    #
    #       | \ | |                          | (_)         | | (_)                    #
    #       |  \| | ___  _ __ _ __ ___   __ _| |_ ___  __ _| |_ _  ___  _ __          #
    #       | . ` |/ _ \| '__| '_ ` _ \ / _` | | / __|/ _` | __| |/ _ \| '_ \         #
    #       | |\  | (_) | |  | | | | | | (_| | | \__ \ (_| | |_| | (_) | | | |        #
    #       |_| \_|\___/|_|  |_| |_| |_|\__,_|_|_|___/\__,_|\__|_|\___/|_| |_|        #
    #                                                                                 #
    ###################################################################################
    # fancy ASCII art thanks to, I guess, Jose

    # start by creating the fit models to get the normalization:
    # * MAIN and SECONDARY bkg are taken from MC by fitting the whole J_mass range
    # * The two PDFs are added together using the relative normalizations of the two bkg from MC
    # * DATA is then fit in the sidebands only using the combined bkg PDF
    # * The results of the fit are then estrapolated in the SR and the integral is evaluated.
    # * This defines the bkg normalization in the SR

    # *******************************************************#
    #                                                       #
    #                 V+jets normalization                  #
    #                                                       #
    # *******************************************************#

    # Variables for V+jets
    constVjet = RooRealVar("constVjet", "slope of the exp", -0.020, -1.0, 0.0)
    offsetVjet = RooRealVar("offsetVjet", "offset of the erf", 30.0, -50.0, 400.0)
    widthVjet = RooRealVar("widthVjet", "width of the erf", 100.0, 1.0, 200.0)  # 0, 400
    a0Vjet = RooRealVar("a0Vjet", "width of the erf", -0.1, -5, 0)
    a1Vjet = RooRealVar("a1Vjet", "width of the erf", 0.6, 0, 5)
    a2Vjet = RooRealVar("a2Vjet", "width of the erf", -0.1, -1, 1)

    if channel == "XZhnnb":
        offsetVjet = RooRealVar("offsetVjet", "offset of the erf", 500.0, 200.0, 1000.0)
    if channel == "XZhnnbb":
        offsetVjet = RooRealVar("offsetVjet", "offset of the erf", 350.0, 200.0, 500.0)
    #    if channel == "XWhenb" or channel == "XZheeb":
    #        offsetVjet.setVal(120.)
    #        offsetVjet.setConstant(True)
    if channel == "XWhenb":
        offsetVjet = RooRealVar("offsetVjet", "offset of the erf", 120.0, 80.0, 155.0)
    if channel == "XWhenbb" or channel == "XZhmmb":
        offsetVjet = RooRealVar("offsetVjet", "offset of the erf", 67.0, 50.0, 100.0)
    if channel == "XWhmnb":
        offsetVjet = RooRealVar("offsetVjet", "offset of the erf", 30.0, -50.0, 600.0)
    if channel == "XZheeb":
        offsetVjet.setMin(-400)
        offsetVjet.setVal(0.0)
        offsetVjet.setMax(1000)
        widthVjet.setVal(1.0)

    # Define V+jets model
    if fitFuncVjet == "ERFEXP":
        VjetMass = RooErfExpPdf("VjetMass", fitFuncVjet, J_mass, constVjet, offsetVjet, widthVjet)
    elif fitFuncVjet == "EXP":
        VjetMass = RooExponential("VjetMass", fitFuncVjet, J_mass, constVjet)
    elif fitFuncVjet == "GAUS":
        VjetMass = RooGaussian("VjetMass", fitFuncVjet, J_mass, offsetVjet, widthVjet)
    elif fitFuncVjet == "POL":
        VjetMass = RooChebychev("VjetMass", fitFuncVjet, J_mass, RooArgList(a0Vjet, a1Vjet, a2Vjet))
    elif fitFuncVjet == "POW":
        VjetMass = RooGenericPdf("VjetMass", fitFuncVjet, "@0^@1", RooArgList(J_mass, a0Vjet))
    else:
        print "  ERROR! Pdf", fitFuncVjet, "is not implemented for Vjets"
        exit()

    if fitAltFuncVjet == "POL":
        VjetMass2 = RooChebychev("VjetMass2", "polynomial for V+jets mass", J_mass, RooArgList(a0Vjet, a1Vjet, a2Vjet))
    else:
        print "  ERROR! Pdf", fitAltFuncVjet, "is not implemented for Vjets"
        exit()

    # fit to main bkg in MC (whole range)
    frVjet = VjetMass.fitTo(
        setVjet,
        RooFit.SumW2Error(True),
        RooFit.Range("h_reasonable_range"),
        RooFit.Strategy(2),
        RooFit.Minimizer("Minuit2"),
        RooFit.Save(1),
        RooFit.PrintLevel(1 if VERBOSE else -1),
    )
    frVjet2 = VjetMass2.fitTo(
        setVjet,
        RooFit.SumW2Error(True),
        RooFit.Range("h_reasonable_range"),
        RooFit.Strategy(2),
        RooFit.Minimizer("Minuit2"),
        RooFit.Save(1),
        RooFit.PrintLevel(1 if VERBOSE else -1),
    )

    if VERBOSE:
        print "********** Fit result [JET MASS Vjets] *" + "*" * 40, "\n", frVjet.Print(), "\n", "*" * 80

    # likelihoodScan(VjetMass, setVjet, [constVjet, offsetVjet, widthVjet])

    # *******************************************************#
    #                                                       #
    #                 VV, VH normalization                  #
    #                                                       #
    # *******************************************************#

    # Variables for VV
    # Error function and exponential to model the bulk
    constVV = RooRealVar("constVV", "slope of the exp", -0.030, -0.1, 0.0)
    offsetVV = RooRealVar("offsetVV", "offset of the erf", 90.0, 1.0, 300.0)
    widthVV = RooRealVar("widthVV", "width of the erf", 50.0, 1.0, 100.0)
    erfrVV = RooErfExpPdf("baseVV", "error function for VV jet mass", J_mass, constVV, offsetVV, widthVV)
    expoVV = RooExponential("baseVV", "error function for VV jet mass", J_mass, constVV)
    # gaussian for the V mass peak
    meanVV = RooRealVar("meanVV", "mean of the gaussian", 90.0, 60.0, 100.0)
    sigmaVV = RooRealVar("sigmaVV", "sigma of the gaussian", 10.0, 6.0, 30.0)
    fracVV = RooRealVar("fracVV", "fraction of gaussian wrt erfexp", 3.2e-1, 0.0, 1.0)
    gausVV = RooGaussian("gausVV", "gaus for VV jet mass", J_mass, meanVV, sigmaVV)
    # gaussian for the H mass peak
    meanVH = RooRealVar("meanVH", "mean of the gaussian", 125.0, 100.0, 150.0)
    sigmaVH = RooRealVar("sigmaVH", "sigma of the gaussian", 10.0, 5.0, 50.0)
    fracVH = RooRealVar("fracVH", "fraction of gaussian wrt erfexp", 1.5e-2, 0.0, 1.0)
    gausVH = RooGaussian("gausVH", "gaus for VH jet mass", J_mass, meanVH, sigmaVH)

    # Define VV model
    if fitFuncVV == "ERFEXPGAUS":
        VVMass = RooAddPdf("VVMass", fitFuncVV, RooArgList(gausVV, erfrVV), RooArgList(fracVV))
    elif fitFuncVV == "ERFEXPGAUS2":
        VVMass = RooAddPdf("VVMass", fitFuncVV, RooArgList(gausVH, gausVV, erfrVV), RooArgList(fracVH, fracVV))
    elif fitFuncVV == "EXPGAUS":
        VVMass = RooAddPdf("VVMass", fitFuncVV, RooArgList(gausVV, expoVV), RooArgList(fracVV))
    elif fitFuncVV == "EXPGAUS2":
        VVMass = RooAddPdf("VVMass", fitFuncVV, RooArgList(gausVH, gausVV, expoVV), RooArgList(fracVH, fracVV))
    else:
        print "  ERROR! Pdf", fitFuncVV, "is not implemented for VV"
        exit()

    # fit to secondary bkg in MC (whole range)
    frVV = VVMass.fitTo(
        setVV,
        RooFit.SumW2Error(True),
        RooFit.Range("h_reasonable_range"),
        RooFit.Strategy(2),
        RooFit.Minimizer("Minuit2"),
        RooFit.Save(1),
        RooFit.PrintLevel(1 if VERBOSE else -1),
    )

    if VERBOSE:
        print "********** Fit result [JET MASS VV] ****" + "*" * 40, "\n", frVV.Print(), "\n", "*" * 80

    # *******************************************************#
    #                                                       #
    #                 Top, ST normalization                 #
    #                                                       #
    # *******************************************************#

    # Variables for Top
    # Error Function * Exponential to model the bulk
    constTop = RooRealVar("constTop", "slope of the exp", -0.030, -1.0, 0.0)
    offsetTop = RooRealVar("offsetTop", "offset of the erf", 175.0, 50.0, 250.0)
    widthTop = RooRealVar("widthTop", "width of the erf", 100.0, 1.0, 300.0)
    gausTop = RooGaussian("baseTop", "gaus for Top jet mass", J_mass, offsetTop, widthTop)
    erfrTop = RooErfExpPdf("baseTop", "error function for Top jet mass", J_mass, constTop, offsetTop, widthTop)
    # gaussian for the W mass peak
    meanW = RooRealVar("meanW", "mean of the gaussian", 80.0, 70.0, 90.0)
    sigmaW = RooRealVar("sigmaW", "sigma of the gaussian", 10.0, 2.0, 20.0)
    fracW = RooRealVar("fracW", "fraction of gaussian wrt erfexp", 0.1, 0.0, 1.0)
    gausW = RooGaussian("gausW", "gaus for W jet mass", J_mass, meanW, sigmaW)
    # gaussian for the Top mass peak
    meanT = RooRealVar("meanT", "mean of the gaussian", 175.0, 150.0, 200.0)
    sigmaT = RooRealVar("sigmaT", "sigma of the gaussian", 12.0, 5.0, 30.0)
    fracT = RooRealVar("fracT", "fraction of gaussian wrt erfexp", 0.1, 0.0, 1.0)
    gausT = RooGaussian("gausT", "gaus for T jet mass", J_mass, meanT, sigmaT)

    if channel == "XZheeb" or channel == "XZheebb" or channel == "XZhmmb" or channel == "XZhmmbb":
        offsetTop = RooRealVar("offsetTop", "offset of the erf", 200.0, -50.0, 450.0)
        widthTop = RooRealVar("widthTop", "width of the erf", 100.0, 1.0, 1000.0)

    # Define Top model
    if fitFuncTop == "ERFEXPGAUS2":
        TopMass = RooAddPdf("TopMass", fitFuncTop, RooArgList(gausW, gausT, erfrTop), RooArgList(fracW, fracT))
    elif fitFuncTop == "ERFEXPGAUS":
        TopMass = RooAddPdf("TopMass", fitFuncTop, RooArgList(gausT, erfrTop), RooArgList(fracT))
    elif fitFuncTop == "GAUS3":
        TopMass = RooAddPdf("TopMass", fitFuncTop, RooArgList(gausW, gausT, gausTop), RooArgList(fracW, fracT))
    elif fitFuncTop == "GAUS2":
        TopMass = RooAddPdf("TopMass", fitFuncTop, RooArgList(gausT, gausTop), RooArgList(fracT))
    elif fitFuncTop == "GAUS":
        TopMass = RooGaussian("TopMass", fitFuncTop, J_mass, offsetTop, widthTop)
    else:
        print "  ERROR! Pdf", fitFuncTop, "is not implemented for Top"
        exit()

    # fit to secondary bkg in MC (whole range)
    frTop = TopMass.fitTo(
        setTop,
        RooFit.SumW2Error(True),
        RooFit.Range("h_reasonable_range"),
        RooFit.Strategy(2),
        RooFit.Minimizer("Minuit2"),
        RooFit.Save(1),
        RooFit.PrintLevel(1 if VERBOSE else -1),
    )

    if VERBOSE:
        print "********** Fit result [JET MASS TOP] ***" + "*" * 40, "\n", frTop.Print(), "\n", "*" * 80

    # likelihoodScan(TopMass, setTop, [offsetTop, widthTop])

    # *******************************************************#
    #                                                       #
    #                 All bkg normalization                 #
    #                                                       #
    # *******************************************************#

    #    nVjet.setConstant(False)
    #    nVjet2.setConstant(False)
    #
    #    constVjet.setConstant(False)
    #    offsetVjet.setConstant(False)
    #    widthVjet.setConstant(False)
    #    a0Vjet.setConstant(False)
    #    a1Vjet.setConstant(False)
    #    a2Vjet.setConstant(False)

    constVV.setConstant(True)
    offsetVV.setConstant(True)
    widthVV.setConstant(True)
    meanVV.setConstant(True)
    sigmaVV.setConstant(True)
    fracVV.setConstant(True)
    meanVH.setConstant(True)
    sigmaVH.setConstant(True)
    fracVH.setConstant(True)

    constTop.setConstant(True)
    offsetTop.setConstant(True)
    widthTop.setConstant(True)
    meanW.setConstant(True)
    sigmaW.setConstant(True)
    fracW.setConstant(True)
    meanT.setConstant(True)
    sigmaT.setConstant(True)
    fracT.setConstant(True)

    nVV.setConstant(True)
    nTop.setConstant(True)
    nVjet.setConstant(False)
    nVjet2.setConstant(False)

    # Final background model by adding the main+secondary pdfs (using 'coef': ratio of the secondary/main, from MC)
    TopMass_ext = RooExtendPdf("TopMass_ext", "extended p.d.f", TopMass, nTop)
    VVMass_ext = RooExtendPdf("VVMass_ext", "extended p.d.f", VVMass, nVV)
    VjetMass_ext = RooExtendPdf("VjetMass_ext", "extended p.d.f", VjetMass, nVjet)
    VjetMass2_ext = RooExtendPdf("VjetMass_ext", "extended p.d.f", VjetMass, nVjet2)
    BkgMass = RooAddPdf(
        "BkgMass", "BkgMass", RooArgList(TopMass_ext, VVMass_ext, VjetMass_ext), RooArgList(nTop, nVV, nVjet)
    )
    BkgMass2 = RooAddPdf(
        "BkgMass2", "BkgMass2", RooArgList(TopMass_ext, VVMass_ext, VjetMass2_ext), RooArgList(nTop, nVV, nVjet2)
    )
    BkgMass.fixAddCoefRange("h_reasonable_range")
    BkgMass2.fixAddCoefRange("h_reasonable_range")

    # Extended fit model to data in SB
    frMass = BkgMass.fitTo(
        setDataSB,
        RooFit.SumW2Error(True),
        RooFit.Extended(True),
        RooFit.Range("LSBrange,HSBrange"),
        RooFit.Strategy(2),
        RooFit.Minimizer("Minuit"),
        RooFit.Save(1),
        RooFit.PrintLevel(1 if VERBOSE else -1),
    )  # , RooFit.NumCPU(10)
    if VERBOSE:
        print "********** Fit result [JET MASS DATA] **" + "*" * 40, "\n", frMass.Print(), "\n", "*" * 80
    frMass2 = BkgMass2.fitTo(
        setDataSB,
        RooFit.SumW2Error(True),
        RooFit.Extended(True),
        RooFit.Range("LSBrange,HSBrange"),
        RooFit.Strategy(2),
        RooFit.Minimizer("Minuit"),
        RooFit.Save(1),
        RooFit.PrintLevel(1 if VERBOSE else -1),
    )
    if VERBOSE:
        print "********** Fit result [JET MASS DATA] **" + "*" * 40, "\n", frMass2.Print(), "\n", "*" * 80

    # if SCAN:
    #    likelihoodScan(VjetMass, setVjet, [constVjet, offsetVjet, widthVjet])

    # Fix normalization and parameters of V+jets after the fit to data
    nVjet.setConstant(True)
    nVjet2.setConstant(True)

    constVjet.setConstant(True)
    offsetVjet.setConstant(True)
    widthVjet.setConstant(True)
    a0Vjet.setConstant(True)
    a1Vjet.setConstant(True)
    a2Vjet.setConstant(True)

    # integrals for global normalization
    # do not integrate the composte model: results have no sense

    # integral for normalization in the SB
    iSBVjet = VjetMass.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("LSBrange,HSBrange"))
    iSBVV = VVMass.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("LSBrange,HSBrange"))
    iSBTop = TopMass.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("LSBrange,HSBrange"))

    # integral for normalization in the SR
    iSRVjet = VjetMass.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("SRrange"))
    iSRVV = VVMass.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("SRrange"))
    iSRTop = TopMass.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("SRrange"))

    # integral for normalization in the VR
    iVRVjet = VjetMass.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("VRrange"))
    iVRVV = VVMass.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("VRrange"))
    iVRTop = TopMass.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("VRrange"))

    # formual vars
    SByield = RooFormulaVar(
        "SByield", "extrapolation to SR", "@0*@1 + @2*@3 + @4*@5", RooArgList(iSBVjet, nVjet, iSBVV, nVV, iSBTop, nTop)
    )
    VRyield = RooFormulaVar(
        "VRyield", "extrapolation to VR", "@0*@1 + @2*@3 + @4*@5", RooArgList(iVRVjet, nVjet, iVRVV, nVV, iVRTop, nTop)
    )
    SRyield = RooFormulaVar(
        "SRyield", "extrapolation to SR", "@0*@1 + @2*@3 + @4*@5", RooArgList(iSRVjet, nVjet, iSRVV, nVV, iSRTop, nTop)
    )

    # fractions
    fSBVjet = RooRealVar(
        "fVjet", "Fraction of Vjet events in SB", iSBVjet.getVal() * nVjet.getVal() / SByield.getVal(), 0.0, 1.0
    )
    fSBVV = RooRealVar(
        "fSBVV", "Fraction of VV events in SB", iSBVV.getVal() * nVV.getVal() / SByield.getVal(), 0.0, 1.0
    )
    fSBTop = RooRealVar(
        "fSBTop", "Fraction of Top events in SB", iSBTop.getVal() * nTop.getVal() / SByield.getVal(), 0.0, 1.0
    )

    fSRVjet = RooRealVar(
        "fSRVjet", "Fraction of Vjet events in SR", iSRVjet.getVal() * nVjet.getVal() / SRyield.getVal(), 0.0, 1.0
    )
    fSRVV = RooRealVar(
        "fSRVV", "Fraction of VV events in SR", iSRVV.getVal() * nVV.getVal() / SRyield.getVal(), 0.0, 1.0
    )
    fSRTop = RooRealVar(
        "fSRTop", "Fraction of Top events in SR", iSRTop.getVal() * nTop.getVal() / SRyield.getVal(), 0.0, 1.0
    )

    # final normalization values
    bkgYield = SRyield.getVal()
    bkgYield2 = (
        (VjetMass2.createIntegral(jetMassArg, RooFit.NormSet(jetMassArg), RooFit.Range("SRrange"))).getVal()
        * nVjet2.getVal()
        + iSRVV.getVal() * nVV.getVal()
        + iSRTop.getVal() * nTop.getVal()
    )
    bkgYield_syst = math.sqrt(SRyield.getPropagatedError(frVV) ** 2 + SRyield.getPropagatedError(frTop) ** 2)
    bkgYield_stat = math.sqrt(SRyield.getPropagatedError(frMass) ** 2)
    bkgYield_alte = abs(bkgYield - bkgYield2)  # /bkgYield
    bkgYield_eig_norm = RooRealVar("predSR_eig_norm", "expected yield in SR", bkgYield, 0.0, 1.0e6)

    print "Events in channel", channel, ": V+jets %.3f (%.1f%%),   VV %.3f (%.1f%%),   Top %.3f (%.1f%%)" % (
        iSRVjet.getVal() * nVjet.getVal(),
        fSRVjet.getVal() * 100,
        iSRVV.getVal() * nVV.getVal(),
        fSRVV.getVal() * 100,
        iSRTop.getVal() * nTop.getVal(),
        fSRTop.getVal() * 100,
    )
    print "Events in channel", channel, ": Integral = $%.3f$ & $\pm %.3f$ & $\pm %.3f$ & $\pm %.3f$, observed = %.0f" % (
        bkgYield,
        bkgYield_stat,
        bkgYield_syst,
        bkgYield_alte,
        setDataSR.sumEntries() if not False else -1,
    )
Example #3
0
def alpha(channel):

    nElec = channel.count('e')
    nMuon = channel.count('m')
    nLept = nElec + nMuon
    nBtag = channel.count('b')
    
    # Channel-dependent settings
    # Background function. Semi-working options are: EXP, EXP2, EXPN, EXPTAIL
    if nLept == 0:
        treeName = 'SR'
        signName = 'XZh'
        colorVjet = sample['DYJetsToNuNu']['linecolor']
        triName = "HLT_PFMET"
        leptCut = "0==0"
        topVeto = selection["TopVetocut"]
        massVar = "X_cmass"
        binFact = 1
        #fitFunc = "EXP"
        #fitFunc = "EXP2"
        #fitFunc = "EXPN"
        #fitFunc = "EXPTAIL"
        fitFunc = "EXPN" if nBtag < 2 else "EXP"
        fitAltFunc = "EXPTAIL" if nBtag < 2 else "EXPTAIL"
        fitFuncVjet = "ERFEXP" if nBtag < 2 else "ERFEXP"
        fitFuncVV   = "EXPGAUS"
        fitFuncTop  = "GAUS2"
    elif nLept == 1:
        treeName = 'WCR'
        signName = 'XWh'
        colorVjet = sample['WJetsToLNu']['linecolor']
        triName = "HLT_Ele" if nElec > 0 else "HLT_Mu"
        leptCut = "isWtoEN" if nElec > 0 else "isWtoMN"
        topVeto = selection["TopVetocut"]
        massVar = "X_mass"
        binFact = 2
        if nElec > 0:
            fitFunc = "EXP" if nBtag < 2 else "EXP"
            fitAltFunc  = "EXPTAIL" if nBtag < 2 else "EXPTAIL"
        else:
            fitFunc = "EXPTAIL" if nBtag < 2 else "EXP"
            fitAltFunc  = "EXPN" if nBtag < 2 else "EXPTAIL"
        fitFuncVjet = "ERFEXP" if nBtag < 2 else "ERFEXP"
        fitFuncVV   = "EXPGAUS"
        fitFuncTop  = "GAUS3" if nBtag < 2 else "GAUS2"
    else:
        treeName = 'XZh'
        signName = 'XZh'
        colorVjet = sample['DYJetsToLL']['linecolor']
        triName = "HLT_Ele" if nElec > 0 else "HLT_Mu"
        leptCut = "isZtoEE" if nElec > 0 else "isZtoMM"
        topVeto = "0==0"
        massVar = "X_mass"
        binFact = 5
        if nElec > 0:
            fitFunc = "EXP" if nBtag < 2 else "EXP"
            fitAltFunc = "POW" if nBtag < 2 else "POW"
        else:
            fitFunc = "EXP" if nBtag < 2 else "EXP"
            fitAltFunc = "POW" if nBtag < 2 else "POW"
        fitFuncVjet = "ERFEXP" if nBtag < 2 else "EXP"
        fitFuncVV   = "EXPGAUS2"
        fitFuncTop  = "GAUS"
    
    btagCut = selection["2Btag"] if nBtag == 2 else selection["1Btag"]
    
    print "--- Channel", channel, "---"
    print "  number of electrons:", nElec, " muons:", nMuon, " b-tags:", nBtag
    print "  read tree:", treeName, "and trigger:", triName
    if ALTERNATIVE: print "  using ALTERNATIVE fit functions"
    print "-"*11*2
    
    # Silent RooFit
    RooMsgService.instance().setGlobalKillBelow(RooFit.FATAL)
    
    #*******************************************************#
    #                                                       #
    #              Variables and selections                 #
    #                                                       #
    #*******************************************************#
    
    # Define all the variables from the trees that will be used in the cuts and fits
    # this steps actually perform a "projection" of the entire tree on the variables in thei ranges, so be careful once setting the limits
    X_mass = RooRealVar(  massVar, "m_{X}" if nLept > 0 else "m_{T}^{X}", XBINMIN, XBINMAX, "GeV")
    J_mass = RooRealVar( "fatjet1_prunedMassCorr",       "corrected pruned mass", HBINMIN, HBINMAX, "GeV")
    CSV1 = RooRealVar(   "fatjet1_CSVR1",                           "",        -1.e99,   1.e4     )
    CSV2 = RooRealVar(   "fatjet1_CSVR2",                           "",        -1.e99,   1.e4     )
    nBtag = RooRealVar(  "fatjet1_nBtag",                           "",            0.,   4        )
    CSVTop = RooRealVar( "bjet1_CSVR",                              "",        -1.e99,   1.e4     )
    isZtoEE = RooRealVar("isZtoEE",                                 "",            0.,   2        )
    isZtoMM = RooRealVar("isZtoMM",                                 "",            0.,   2        )
    isWtoEN = RooRealVar("isWtoEN",                                 "",            0.,   2        )
    isWtoMN = RooRealVar("isWtoMN",                                 "",            0.,   2        )
    weight = RooRealVar( "eventWeightLumi",                         "",         -1.e9,   1.       )
    
    # Define the RooArgSet which will include all the variables defined before
    # there is a maximum of 9 variables in the declaration, so the others need to be added with 'add'
    variables = RooArgSet(X_mass, J_mass, CSV1, CSV2, nBtag, CSVTop)
    variables.add(RooArgSet(isZtoEE, isZtoMM, isWtoEN, isWtoMN, weight))
    
    # Define the ranges in fatJetMass - these will be used to define SB and SR
    J_mass.setRange("LSBrange", LOWMIN, LOWMAX)
    J_mass.setRange("HSBrange", HIGMIN, HIGMAX)
    J_mass.setRange("VRrange",  LOWMAX, SIGMIN)
    J_mass.setRange("SRrange",  SIGMIN, SIGMAX)
    J_mass.setBins(54)
    
    # Define the selection for the various categories (base + SR / LSBcut / HSBcut )
    baseCut = leptCut + " && " + btagCut + "&&" + topVeto
    massCut = massVar + ">%d" % XBINMIN
    baseCut += " && " + massCut
    
    # Cuts
    SRcut  = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), SIGMIN, J_mass.GetName(), SIGMAX)
    LSBcut = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), LOWMIN, J_mass.GetName(), LOWMAX)
    HSBcut = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), HIGMIN, J_mass.GetName(), HIGMAX)
    SBcut  = baseCut + " && ((%s>%d && %s<%d) || (%s>%d && %s<%d))" % (J_mass.GetName(), LOWMIN, J_mass.GetName(), LOWMAX, J_mass.GetName(), HIGMIN, J_mass.GetName(), HIGMAX)
    VRcut  = baseCut + " && %s>%d && %s<%d" % (J_mass.GetName(), LOWMAX, J_mass.GetName(), SIGMIN)
    
    # Binning
    binsJmass = RooBinning(HBINMIN, HBINMAX)
    binsJmass.addUniform(HBINS, HBINMIN, HBINMAX)
    binsXmass = RooBinning(XBINMIN, XBINMAX)
    binsXmass.addUniform(binFact*XBINS, XBINMIN, XBINMAX)
    
    #*******************************************************#
    #                                                       #
    #                      Input files                      #
    #                                                       #
    #*******************************************************#
    
    # Import the files using TChains (separately for the bkg "classes" that we want to describe: here DY and VV+ST+TT)
    treeData = TChain(treeName)
    treeMC   = TChain(treeName)
    treeVjet = TChain(treeName)
    treeVV   = TChain(treeName)
    treeTop  = TChain(treeName)
#    treeSign = {}
#    nevtSign = {}

    
    # Read data
    print "read data start"
    pd = getPrimaryDataset(triName)
    if len(pd)==0: raw_input("Warning: Primary Dataset not recognized, continue?")
    for i, s in enumerate(pd): treeData.Add(NTUPLEDIR + s + ".root")

    
    # Read V+jets backgrounds
    print "read V+jet start"
    for i, s in enumerate(["WJetsToLNu_HT", "DYJetsToNuNu_HT", "DYJetsToLL_HT"]):
        for j, ss in enumerate(sample[s]['files']): treeVjet.Add(NTUPLEDIR + ss + ".root")
    
    # Read VV backgrounds
    print "read VV start"
    for i, s in enumerate(["VV"]):
        for j, ss in enumerate(sample[s]['files']): treeVV.Add(NTUPLEDIR + ss + ".root")
    
    # Read Top backgrounds
    print "read Top start"
    for i, s in enumerate(["ST", "TTbar"]):
        for j, ss in enumerate(sample[s]['files']): treeTop.Add(NTUPLEDIR + ss + ".root")
        
    # Sum all background MC
    treeMC.Add(treeVjet)
    treeMC.Add(treeVV)
    treeMC.Add(treeTop)


#    print "prepare SB dataset"
    
    # create a dataset to host data in sideband (using this dataset we are automatically blind in the SR!)
#    setDataSB = RooDataSet("setDataSB", "setDataSB", variables, RooFit.Cut(SBcut), RooFit.WeightVar(weight), RooFit.Import(treeData))
#    setDataLSB = RooDataSet("setDataLSB", "setDataLSB", variables, RooFit.Import(setDataSB), RooFit.Cut(LSBcut), RooFit.WeightVar(weight))
#    setDataHSB = RooDataSet("setDataHSB", "setDataHSB", variables, RooFit.Import(setDataSB), RooFit.Cut(HSBcut), RooFit.WeightVar(weight))

#    print "prepare SR dataset"
    
    # Observed data (WARNING, BLIND!)
#    setDataSR = RooDataSet("setDataSR", "setDataSR", variables, RooFit.Cut(SRcut), RooFit.WeightVar(weight), RooFit.Import(treeData))
#    setDataVR = RooDataSet("setDataVR", "setDataVR", variables, RooFit.Cut(VRcut), RooFit.WeightVar(weight), RooFit.Import(treeData)) # Observed in the VV mass, just for plotting purposes
    

    print "prepare MC dataset"

    # same for the bkg datasets from MC, where we just apply the base selections (not blind)
    setVjet = RooDataSet("setVjet", "setVjet", variables, RooFit.Cut(baseCut), RooFit.WeightVar(weight), RooFit.Import(treeVjet))
    setVjetSB = RooDataSet("setVjetSB", "setVjetSB", variables, RooFit.Import(setVjet), RooFit.Cut(SBcut), RooFit.WeightVar(weight))
    setVjetSR = RooDataSet("setVjetSR", "setVjetSR", variables, RooFit.Import(setVjet), RooFit.Cut(SRcut), RooFit.WeightVar(weight))

    print "finish Vjet dataset"


#    setVV = RooDataSet("setVV", "setVV", variables, RooFit.Cut(baseCut), RooFit.WeightVar(weight), RooFit.Import(treeVV))
#    setVVSB = RooDataSet("setVVSB", "setVVSB", variables, RooFit.Import(setVV), RooFit.Cut(SBcut), RooFit.WeightVar(weight))
#    setVVSR = RooDataSet("setVVSR", "setVVSR", variables, RooFit.Import(setVV), RooFit.Cut(SRcut), RooFit.WeightVar(weight))

#    print "finish VV dataset"

#    setTop = RooDataSet("setTop", "setTop", variables, RooFit.Cut(baseCut), RooFit.WeightVar(weight), RooFit.Import(treeTop))
#    setTopSB = RooDataSet("setTopSB", "setTopSB", variables, RooFit.Import(setTop), RooFit.Cut(SBcut), RooFit.WeightVar(weight))
#    setTopSR = RooDataSet("setTopSR", "setTopSR", variables, RooFit.Import(setTop), RooFit.Cut(SRcut), RooFit.WeightVar(weight))

#    print "finish Top dataset"

    
#    print "  Data events SB: %.2f" % setDataSB.sumEntries()
    print "  V+jets entries: %.2f" % setVjet.sumEntries()
#    print "  VV, VH entries: %.2f" % setVV.sumEntries()
#    print "  Top,ST entries: %.2f" % setTop.sumEntries()
    
    
    # the relative normalization of the varius bkg is taken from MC by counting all the events in the full fatJetMass range
    #coef = RooRealVar("coef", "coef", setVV.sumEntries()/setVjet.sumEntries(),0.,1.)
#    coef_VV_Vjet = RooRealVar("coef2_1", "coef2_1", setVV.sumEntries()/setVjet.sumEntries(), 0., 1.)
#    coef_Top_VVVjet = RooRealVar("coef3_21", "coef3_21", setTop.sumEntries()/(setVjet.sumEntries()+setVV.sumEntries()),0.,1.);
#    coef_VV_Vjet.setConstant(True)
#    coef_Top_VVVjet.setConstant(True)
    
    # Define entries
    entryVjet = RooRealVar("entryVjets",  "V+jets normalization", setVjet.sumEntries(), 0., 1.e6)
#    entryVV = RooRealVar("entryVV",  "VV normalization", setVV.sumEntries(), 0., 1.e6)
#    entryTop = RooRealVar("entryTop",  "Top normalization", setTop.sumEntries(), 0., 1.e6)
    
#    entrySB = RooRealVar("entrySB",  "Data SB normalization", setDataSB.sumEntries(SBcut), 0., 1.e6)
#    entrySB.setError(math.sqrt(entrySB.getVal()))
    
#    entryLSB = RooRealVar("entryLSB",  "Data LSB normalization", setDataSB.sumEntries(LSBcut), 0., 1.e6)
#    entryLSB.setError(math.sqrt(entryLSB.getVal()))

#    entryHSB = RooRealVar("entryHSB",  "Data HSB normalization", setDataSB.sumEntries(HSBcut), 0., 1.e6)
#    entryHSB.setError(math.sqrt(entryHSB.getVal()))
    
    #*******************************************************#
    #                                                       #
    #                    NORMALIZATION                      #
    #                                                       #
    #*******************************************************#
    
    # set reasonable ranges for J_mass and X_mass
    # these are used in the fit in order to avoid ROOFIT to look in regions very far away from where we are fitting 
    J_mass.setRange("h_reasonable_range", LOWMIN, HIGMAX)
    X_mass.setRange("X_reasonable_range", XBINMIN, XBINMAX)
    
    # Set RooArgSets once for all, see https://root.cern.ch/phpBB3/viewtopic.php?t=11758
    jetMassArg = RooArgSet(J_mass)

    ##############################
    #                            #
    #    Yu-hsiang test region   #
    #                            #
    ##############################

    # test it in the channel "XZhnnb"
    print "the channel is", channel 
    if channel == "XZhnnb":

	# -------------------------------------------------------------------    
    	# draw the setVjet
    	Jmass_frame = J_mass.frame(RooFit.Title("test frame"))
    	setVjet.plotOn(Jmass_frame)    

        # ------------------------------------------------------------------- 
    	# use a PDF to fit the dataset
    	print "fitFuncVjet is", fitFuncVjet 

        constVjet_value_initial = -0.020
	offsetVjet_value_initial = 30.
	widthVjet_value_initial = 100.

    	constVjet_test   = RooRealVar("constVjet_test",   "slope of the exp", constVjet_value_initial , -1.,   0.)
    	offsetVjet_test  = RooRealVar("offsetVjet_test",  "offset of the erf", offsetVjet_value_initial,   -50., 200.)
    	widthVjet_test   = RooRealVar("widthVjet_test",   "width of the erf",  widthVjet_value_initial,     1., 200.)

        modelVjet_test = RooErfExpPdf("modelVjet_test", "error function for V+jets mass", J_mass, constVjet_test, offsetVjet_test, widthVjet_test)

#	constVjet_test.Print()
#	offsetVjet_test.Print()
#	widthVjet_test.Print()

#    	constVjet_test.setConstant(True)
#    	offsetVjet_test.setConstant(True)
#    	widthVjet_test.setConstant(True)

        frVjet_test = modelVjet_test.fitTo(setVjet, RooFit.SumW2Error(True), RooFit.Range("h_reasonable_range"), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.Save(1), RooFit.PrintLevel(1 if VERBOSE else -1))

#        constVjet_test.Print()
#        offsetVjet_test.Print()
#        widthVjet_test.Print()

	constVjet_value_fit_MC = constVjet_test.getVal()
	offsetVjet_value_fit_MC = offsetVjet_test.getVal()
	widthVjet_value_fit_MC = widthVjet_test.getVal()

	print "constVjet_value_fit_MC:", constVjet_value_fit_MC, "offsetVjet_value_fit_MC:",offsetVjet_value_fit_MC,"widthVjet_value_fit_MC:",widthVjet_value_fit_MC


        modelVjet_test.plotOn(Jmass_frame,RooFit.LineColor(4))

        # ------------------------------------------------------------------- 
	# use the shape of fit to generate the psudo-data

	Entries_pseudo_data = setVjet.sumEntries()
#        Entries_pseudo_data = 502
#        Entries_pseudo_data = 5021


        pseudo_data = modelVjet_test.generate(RooArgSet(J_mass),Entries_pseudo_data )
#	pseudo_data = modelVjet_test.generate(RooArgSet(J_mass),setVjet.sumEntries()) 
#        pseudo_data = modelVjet_test.generate(RooArgSet(J_mass),502 )
#        pseudo_data = modelVjet_test.generate(RooArgSet(J_mass),5021 )
#	pseudo_data.Print("v")

	Jmass_frame2 = J_mass.frame(RooFit.Title("test frame2"))
	pseudo_data.plotOn(Jmass_frame2)
        modelVjet_test.plotOn(Jmass_frame2,RooFit.LineColor(4))

        # -------------------------------------------------------------------
	# make another dataset that remove the signal region 
        pseudo_data_SB = RooDataSet("pseudo_data_SB", "pseudo_data_SB", RooArgSet(J_mass), RooFit.Import(pseudo_data), RooFit.Cut("fatjet1_prunedMassCorr<65 || fatjet1_prunedMassCorr>135") )
	pseudo_data_SB.plotOn(Jmass_frame2,RooFit.LineColor(2))

        # -------------------------------------------------------------------
        # use another PDF to fit the pseudo-data in SB only

        constVjet_test2   = RooRealVar("constVjet_test2",   "slope of the exp", constVjet_value_fit_MC , -1.,   0.)
        offsetVjet_test2  = RooRealVar("offsetVjet_test2",  "offset of the erf", offsetVjet_value_fit_MC ,   -50., 200.)
        widthVjet_test2   = RooRealVar("widthVjet_test2",   "width of the erf", widthVjet_value_fit_MC ,     1., 200.)

        modelVjet_test2 = RooErfExpPdf("modelVjet_test2", "error function for V+jets mass", J_mass, constVjet_test2, offsetVjet_test2, widthVjet_test2)

        frVjet_test2 = modelVjet_test2.fitTo(pseudo_data_SB, RooFit.SumW2Error(True), RooFit.Range("LSBrange,HSBrange"), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.Save(1), RooFit.PrintLevel(1 if VERBOSE else -1))	
#        frVjet_test2 = modelVjet_test2.fitTo(pseudo_data_SB, RooFit.SumW2Error(True), RooFit.Range("h_reasonable_range"), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.Save(1), RooFit.PrintLevel(1 if VERBOSE else -1))

        constVjet_value_fit_pseudo_data_SB = constVjet_test2.getVal()
        offsetVjet_value_fit_pseudo_data_SB = offsetVjet_test2.getVal()
        widthVjet_value_fit_pseudo_data_SB = widthVjet_test2.getVal()

        print "constVjet_value_fit_pseudo_data_SB:", constVjet_value_fit_pseudo_data_SB, "offsetVjet_value_fit_pseudo_data_SB:",offsetVjet_value_fit_pseudo_data_SB,"widthVjet_value_fit_pseudo_data_SB:",widthVjet_value_fit_pseudo_data_SB

        Jmass_frame3 = J_mass.frame(RooFit.Title("test frame3, fit the pseudo-data in SB only"))
        pseudo_data_SB.plotOn(Jmass_frame3)
        modelVjet_test2.plotOn(Jmass_frame3,RooFit.LineColor(4),RooFit.Range("h_reasonable_range"))

        # ------------------------------------------------------------------- 
        # calculate the Gen_value, the Fit_value and the Bias= ( Fit_value - Gen_value)/Gen_value 

        iGen_value = modelVjet_test.createIntegral(RooArgSet(J_mass), RooFit.Range("VRrange,SRrange"))
        print "iGen_value:", iGen_value.getVal()

        iFit_value = modelVjet_test2.createIntegral(RooArgSet(J_mass), RooFit.Range("VRrange,SRrange"))
        print "iFit_value:", iFit_value.getVal()

        Bias_value = ( iFit_value.getVal() - iGen_value.getVal() ) / iGen_value.getVal()
        print "Bias_value of VR+SR:", Bias_value

        # --------------

        iGen_value = modelVjet_test.createIntegral(RooArgSet(J_mass), RooFit.Range("SRrange"))
        print "iGen_value:", iGen_value.getVal()
        
        iFit_value = modelVjet_test2.createIntegral(RooArgSet(J_mass), RooFit.Range("SRrange"))
        print "iFit_value:", iFit_value.getVal()


	Bias_value = ( iFit_value.getVal() - iGen_value.getVal() ) / iGen_value.getVal()
        print "Bias_value of SR:", Bias_value

#        iGen_value = modelVjet_test.createIntegral(RooArgSet(J_mass),RooFit.NormSet(RooArgSet(J_mass)), RooFit.Range("VRrange,SRrange"))
#	print "iGen_value:", iGen_value.getVal()

#        iGen_value = modelVjet_test.createIntegral(RooArgSet(J_mass),RooFit.NormSet(RooArgSet(J_mass)), RooFit.Range("VRrange,SRrange"))
#        print "iGen_value:", iGen_value.getVal()

#        iGen_value = modelVjet_test.createIntegral(RooArgSet(J_mass), RooFit.Range("h_reasonable_range"))
#        print "iGen_value:", iGen_value.getVal()

#        iGen_value = modelVjet_test.createIntegral(RooArgSet(J_mass))
#        print "iGen_value:", iGen_value.getVal()


        # ------------------------------------------------------------------- 
        # repeat thousand times to see bias distribution

        h_Bias = TH1D("h_Bias","h_Bias",80,-1,1);

        Jmass_frame4 = J_mass.frame(RooFit.Title("test frame4"))

	times_max = 50000

        constVjet_test.setConstant(True)
        offsetVjet_test.setConstant(True)
        widthVjet_test.setConstant(True)

        constVjet_test3   = RooRealVar("constVjet_test3",   "slope of the exp", constVjet_value_fit_MC , -1.,   0.)
        offsetVjet_test3  = RooRealVar("offsetVjet_test3",  "offset of the erf", offsetVjet_value_fit_MC ,   -50., 200.)
        widthVjet_test3   = RooRealVar("widthVjet_test3",   "width of the erf", widthVjet_value_fit_MC ,     1., 200.)


	for times in range(0,times_max):  

    		# inside loop
#		print "times:", times
		if times % 10 == 0 :
			print "Processing times:", times+1 ,"of", times_max 


		# generate pseudo-data
#		n_1_prime = gRandom->Poisson(n_1);
		Entries_pseudo_data_fluc = gRandom.Poisson( Entries_pseudo_data )
#		print "Entries_pseudo_data:", Entries_pseudo_data
#		print "Entries_pseudo_data_fluc:", Entries_pseudo_data_fluc

#		pseudo_data2 = modelVjet_test.generate(RooArgSet(J_mass),Entries_pseudo_data )
                pseudo_data2 = modelVjet_test.generate(RooArgSet(J_mass),Entries_pseudo_data_fluc )

#        	pseudo_data2.plotOn(Jmass_frame3,RooFit.LineColor(4),RooFit.Range("h_reasonable_range"))

                # take out VR+SR		
	        pseudo_data_SB2 = RooDataSet("pseudo_data_SB2", "pseudo_data_SB2", RooArgSet(J_mass), RooFit.Import(pseudo_data2), RooFit.Cut("fatjet1_prunedMassCorr<65 || fatjet1_prunedMassCorr>135") )

		# use other PDF to fit
#		print "constVjet_value_fit_MC:",constVjet_value_fit_MC

		constVjet_test3.setVal(constVjet_value_fit_MC)
		offsetVjet_test3.setVal(offsetVjet_value_fit_MC)
		widthVjet_test3.setVal(widthVjet_value_fit_MC)

		modelVjet_test3 = RooErfExpPdf("modelVjet_test3", "error function for V+jets mass", J_mass, constVjet_test3, offsetVjet_test3, widthVjet_test3)


        	frVjet_test3 = modelVjet_test3.fitTo(pseudo_data_SB2, RooFit.SumW2Error(True), RooFit.Range("LSBrange,HSBrange"), RooFit.Strategy(2), RooFit.Minimizer("Minuit2"), RooFit.Save(1), RooFit.PrintLevel(1 if VERBOSE else -1))

		# calculate the bias
        	iGen_value2 = modelVjet_test.createIntegral(jetMassArg,RooFit.NormSet(jetMassArg), RooFit.Range("SRrange"))
#        	print "iGen_value2:", iGen_value2.getVal()

        	iFit_value2 = modelVjet_test3.createIntegral(jetMassArg,RooFit.NormSet(jetMassArg), RooFit.Range("SRrange"))
#        	print "iFit_value2:", iFit_value2.getVal()

        	Bias_value2 = ( iFit_value2.getVal() - iGen_value2.getVal() ) / iGen_value2.getVal()
#        	print "Bias_value2 of VR+SR:", Bias_value2
		
		h_Bias.Fill(Bias_value2)



        # ------------------------------------------------------------------- 
	# plot and save
        Save_Dir = "/afs/cern.ch/user/y/yuchang/www/jacopo_plotsAlpha/yu_hsiang_bias_study"

        c_test = TCanvas("test","test draw",800,600)
        c_test.cd()
        Jmass_frame.Draw()
        c_test.SaveAs(Save_Dir+"/"+"VJet_MC_fit_get_shape.pdf")

        c_test2 = TCanvas("test2","test draw 2",800,600)
        c_test2.cd()
        Jmass_frame2.Draw()
        c_test2.SaveAs(Save_Dir+"/"+"use_shape_to_generate_pseudo_data.pdf")
#        c_test2.SaveAs(Save_Dir+"/"+"use_shape_to_generate_pseudo_data_test.pdf")

        c_test3 = TCanvas("test3","test draw 3",800,600)
        c_test3.cd()
        Jmass_frame3.Draw()
        c_test3.SaveAs(Save_Dir+"/"+"fit_pseudo_data_in_SB_only.pdf")

        c_test4 = TCanvas("test4","test draw 4",800,600)
        c_test4.cd()
	h_Bias.Draw()
        c_test4.SaveAs(Save_Dir+"/"+"h_Bias.pdf")
Example #4
0
#diJetMass_5 = RooGenericPdf('diJetMass_5', "@1+@2*pow(@0,1)+@3*pow(@0,2)+@4*pow(@0,3)+@5*pow(@0,4)+@6*pow(@0,5)",RooArgList(J_Mass,p1mod,p2mod,p3mod,p4mod,p5mod,p6mod))
#diJetMass_5 = RooGenericPdf('diJetMass_5', "@1*pow(@0,1)+@2*pow(@0,2)+@3*pow(@0,3)+@4*pow(@0,4)+@5*pow(@0,5)",RooArgList(J_Mass,p2mod,p3mod,p4mod,p5mod,p6mod))
#x= RooRealVar("x","x", 500,1500)
#x.setRange(520,1500)
#diJetMass_5 = RooBernstein ("diJetMass_5","diJetMass_5",x,RooArgList(p1mod,p2mod,p3mod,p4mod,p5mod,p6mod))
#diJetMass_2 = RooGenericPdf('diJetMass_2', "1.0/pow(@0,@2)", RooArgList(x,p3mod))
#diJetMass_3 = RooGenericPdf('diJetMass_3', "pow(1-@0,@2)/pow(@0,@3)",RooArgList(x,p1mod,p2mod,p3mod))
#diJetMass_4 = RooGenericPdf('diJetMass_4', "pow(1-@0,@2)/pow(@0, @3+@4*log(@0))", RooArgList(x, p1mod, p2mod,p3mod,p4mod))
#diJetMass_5 = RooGenericPdf('diJetMass_5', "pow(1-@0,@2)/pow(@0, @3+@4*log(@0)+@5*pow(log(@0),2))", RooArgList(x, p1mod, p2mod,p3mod,p4mod,p5mod))
#diJetMass_4 = RooGenericPdf('diJetMass_4', "pow(1-@0, @2)/pow(@0, @1+@3*log(@0))", RooArgList(x, p1mod, p2mod,p3mod))

## Erf x Exp
constQCD = RooRealVar('constQCD', 'constQCD', -0.02, -1., 0.)
offsetQCD = RooRealVar('offsetQCD', 'offsetQCD', 70., -0., 200.)
widthQCD = RooRealVar('widthQCD', 'widthQCD', 30., 0.1, 100.)
ErfExpQCD = RooErfExpPdf("ErfExpQCD", "error function for Z+jets mass", J_Mass,
                         constQCD, offsetQCD, widthQCD)

##########################################
#
#   #####  #####    #######    ####
#   #      #    #   #     #   #
#   #      #    #   #     #  #
#   #####  ####     #######  #
#   #      #  #     #     #  #
#   #      #   #    #     #   #
#   #      #    #   #     #    ####
##########################################

## fraction parameters
## for signal
signalfrac = RooRealVar('signalfrac', 'signalfrac', 0.01, 0, 0.1)