Exemple #1
0
def GetYield2(path,
              files,
              ch='eee',
              level='sr',
              inc=None,
              histopref='',
              filepref='',
              var='',
              isdata=False):
    t = TopHistoReader(path, files)
    t.SetLevel(level)
    t.SetChan(ch)
    t.SetHistoNamePrefix(histopref)
    #t.SetLumi(GetLumi(2018)*1000)
    #t.SetLumi(GetLumi(year)*1000)
    #t.SetLumi(1)
    t.SetFileNamePrefix(filepref)
    t.SetIsData(isdata)
    if var != '':
        pref = histopref + '_' if histopref != '' else ''
        if inc == None:
            h = t.GetNamedHisto(pref + var + '_' + ch)
        else:
            h = t.GetNamedHisto(pref + var + '_' + ch + '_' + inc)
        y = h.GetBinContent(9)
    else:
        y = t.GetYield()
    return y
 def loadHistos(self):
     ''' Load the PDF and Scale histos and norm histos '''
     t = TopHistoReader(self.path)
     t.SetHistoNamePrefix(self.histoprefix)
     t.SetIsData(1)
     n = self.GetSampleName()
     t.SetProcess(n)
     t.SetChan(self.GetChan())
     t.SetLevel(self.GetLevel())
     #if self.GetNgenEvents() <= 0 : self.SetNgenEvents(t.GetNGenEvents())
     self.SetYield(t.GetYield() * self.GetLumi())
     self.hpdf = t.GetHisto(n, self.PDFhistoName)
     self.hscale = t.GetHisto(n, self.scaleHistoName)
     #self.hPS       = t.GetHisto(n,self.PShistoName)
     if self.pathToTrees != '' and self.motherfname != '':
         self.LoadTreeSumOfWeights(self.pathToTrees, self.motherfname)
     self.hsumpdf = t.GetNamedHisto(
         self.normPDFhistoName
     ) if self.normPDFhistoName != '' else self.GetSumPDFhistoFromSumWTree(
     )
     self.hsumscale = t.GetNamedHisto(
         self.normScaleHitstoName
     ) if self.normScaleHitstoName != '' else self.GetSumScaleHistoFromSumWTree(
     )
     self.SetNgenEvents(self.count)
     self.nPDFweights = self.hsumpdf.GetNbinsX()
     self.nScaleWeighs = self.hsumscale.GetNbinsX()
     print '>> Count        : ', self.count
     print '>> SumOfWeights : ', self.sow
class DYDD:

    ### Set methods
    def SetPath(self, p):
        if not p.endswith('/'): p += '/'
        self.path = p

    def SetOutPath(self, p):
        self.outpath = p

    def SetMode(self, mode='OF', hname=''):
        self.doOF = True
        if mode in ['SF', 'Elec', 'ElEl', 'Muon', 'MuMu']:
            self.doOF = False
        if self.doOF:
            if hname != '': self.SetHistoNameOF(hname)
            self.SetZhistoName(self.hnameOF)
        else:
            if hname != '': self.SetHistoNameSF(hname)
            self.SetZhistoName(self.hnameSF)

    def SetLumi(self, l):
        self.lumi = l
        self.t.SetLumi(self.lumi)

    def SetHistoNameOF(self, h='DY_InvMass'):
        self.hnameOF = h

    def SetHistoNameSF(self, h='DY_SF_InvMass'):
        self.hnameSF = h

    def SetDYsamples(self, f):
        self.DYfiles = f

    def SetDataSamples(self, f):
        self.datafiles = f

    def SetChannel(self, c):
        self.chan = c

    def SetLevel(self, l):
        self.level = l

    def SetZhistoName(self, h):
        self.zhname = h

    def SetMassRange(self, minM=91 - 15, maxM=91 + 15):
        self.minMZ = minM
        self.maxMZ = maxM

    def SetChanAndLevel(self, chan='', level=''):
        ''' Manages to set chan and leve to the class and the TopHistoReader '''
        if chan != '': self.SetChannel(chan)
        if level != '': self.SetLevel(level)
        self.t.SetChan(self.GetChan())
        self.t.SetLevel(self.GetLevel())
        return self.GetChan(), self.GetLevel()

    ### Get methods
    def GetPath(self):
        return self.path

    def GetOutPath(self):
        return self.outpath

    def GetZhistoName(self):
        return self.zhname

    def GetDYfiles(self):
        return self.DYfiles

    def GetDataFiles(self):
        return self.datafiles

    def GetLevel(self):
        return self.level

    def GetChan(self):
        return self.chan

    ### Calculate quantities...

    def GetDYhisto(self, chan='', level='', isData=True):
        # ARREGLAR PARA QUE COJA EL ADECUADO DEPENDIENDO DEL CANAL!! O HACER FUNCION PARA INDICAR CANAL EMU
        chan, level = self.SetChanAndLevel(chan, level)
        if isData:
            self.t.SetIsData(True)
            pr = self.GetDataFiles()
        else:
            self.t.SetIsData(False)
            pr = self.GetDYfiles()
        zname = self.GetZhistoName()
        if level == 'dilepton' and zname[-4:] == 'ElMu': zname = zname[:-4]
        h = self.t.GetHisto(pr, zname, chan, level)
        h.SetDirectory(0)
        return h

    def GetHdata(self, chan, level):
        return self.GetDYhisto(chan, level, True)

    def GetHMC(self, chan, level):
        return self.GetDYhisto(chan, level, False)

    def DYyield(self, direc='in', isData=True, chan='', level=''):
        h = self.GetDYhisto(chan, level, isData)
        b0 = h.FindBin(self.minMZ)
        bN = h.FindBin(self.maxMZ)
        nbins = h.GetNbinsX()
        integral = h.Integral()
        y = 0
        err = 0
        if direc == 'in' or direc == 'In' or direc == 'IN':
            y += h.Integral(b0, bN)
        else:
            y += h.Integral(0, b0 - 1)
            y += h.Integral(bN + 1, nbins + 1)
        if isData: err = sqrt(y)
        else:
            entries = h.GetEntries()
            err = sqrt((y * integral) / entries)
        if y < 0:  # Avoid wierd numbers due to negative weights...
            y = 0
            err = 0
        return y, err

    def GetDataIn(self, chan='', level=''):
        return self.DYyield('in', True, chan, level)

    def GetDataOut(self, chan='', level=''):
        return self.DYyield('out', True, chan, level)

    def GetMCin(self, chan='', level=''):
        return self.DYyield('in', False, chan, level)

    def GetMCout(self, chan='', level=''):
        return self.DYyield('out', False, chan, level)

    def GetRoutin(self, chan='', level=''):
        ''' Returns ratio Rout/in from MC '''
        rin, errin = self.GetMCin(chan, level)
        out, errout = self.GetMCout(chan, level)
        r = out / rin if rin != 0 else 0
        err = r * SumSquare(
            [errout / out if out != 0 else 0, errin / rin if rin != 0 else 0])
        return r, err

    def GetKfactor(self, chan='', level=''):
        ''' Calculate the k factor k_ee, k_mumu '''
        chan, level = self.SetChanAndLevel(chan, level)
        rinElec, errElec = self.GetDataIn(elname, level)
        rinMuon, errMuon = self.GetDataIn(muname, level)
        k = (rinElec / rinMuon if rinMuon != 0 else 0) if chan == elname else (
            rinMuon / rinElec if rinElec != 0 else 0)
        k = sqrt(k)
        kerr = k * SumSquare([
            errElec / (2 * rinElec) if rinElec != 0 else 0, errMuon /
            (2 * rinMuon) if rinMuon != 0 else 0
        ])
        return k, kerr

    def GetDYDD(self, chan='', level='', mode=''):
        ''' Returns the DY estimate from data '''
        chan, level = self.SetChanAndLevel(chan, level)
        if chan == 'ElMu': self.SetMode('ElMu')
        if mode != '': self.SetMode(mode)
        routin, routin_err = self.GetRoutin(chan, level)
        NemuIn, NemuIn_err = self.GetDataIn('ElMu', level)
        kee, keerr = self.GetKfactor(elname, level)
        NeeIn, NeeInerr = self.GetDataIn(elname, level)
        kmm, kmmrr = self.GetKfactor(muname, level)
        NmmIn, NmmInerr = self.GetDataIn(muname, level)
        est = lambda r, Nin, Nemu, k: r * (Nin - Nemu * k / 2)
        esterr = lambda r, Nin, Nemu, k, er, eNin, eNemu, ek: SumSquare([
            est(r, Nin, Nemu, k) *
            (er / r
             if r != 0 else 0), r * eNin, r * k / 2 * eNemu, r * Nemu / 2 * ek
        ])
        N = 0
        Nerr = 0
        if chan == elname:
            N = est(routin, NeeIn, NemuIn, kee)
            Nerr = esterr(routin, NeeIn, NemuIn, kee, routin_err, NeeInerr,
                          NemuIn_err, keerr)
        elif chan == muname:
            N = est(routin, NmmIn, NemuIn, kmm)
            Nerr = esterr(routin, NmmIn, NemuIn, kmm, routin_err, NmmInerr,
                          NemuIn_err, kmmrr)
        else:  # ElMu
            self.t.SetIsData(False)
            yDY = self.t.GetYield(self.GetDYfiles(), 'ElMu')
            yDYe = self.t.GetYieldStatUnc(self.GetDYfiles(), 'ElMu')
            SF, err = self.GetScaleFactor('ElMu')
            N = yDY * SF
            Nerr = N * SumSquare([
                err / SF if SF != 0 else err, yDYe / yDY if yDY != 0 else yDYe
            ])
        if N < 0:
            N = 0
            Nerr = 0
        if not Nerr == Nerr: Nerr = 0
        return N, Nerr

    def GetScaleFactor(self, chan='', level='', mode=''):
        ''' Returns the data/MC ratio for the DY estimate '''
        chan, level = self.SetChanAndLevel(chan, level)
        if chan == 'ElMu': self.SetMode('ElMu')
        if mode != '': self.SetMode(mode)
        SF = 1
        err = 0
        if chan == muname or chan == elname:
            dd, dde = self.GetDYDD(chan)
            mo, moe = self.GetMCout(chan)
            SF = dd / mo if mo != 0 else 0
            err = SF * SumSquare(
                [dde / dd if dd != 0 else 0, moe / mo if mo != 0 else 0])
        elif chan == 'ElMu':
            e, er = self.GetScaleFactor(elname)
            m, mr = self.GetScaleFactor(muname)
            SF = sqrt(e * m)
            err = SF * SumSquare(
                [er / e if e != 0 else 0, mr / m if m != 0 else 0])
        return SF, err

    def DrawHisto(self,
                  doSF=False,
                  name='',
                  chan='',
                  level='',
                  rebin=1,
                  log=True):
        self.SetChanAndLevel('', level)
        self.SetMode('SF' if doSF else 'OF')
        if name == '':
            name = 'DYDD_%s_%s' % ('SF' if doSF else 'OF', self.GetLevel())
        hData = self.GetDYhisto(chan, level, True)
        hMC = self.GetDYhisto(chan, level, False)
        hemu = self.GetDYhisto('ElMu', level, True)
        hData.SetMarkerStyle(20)
        hData.SetMarkerColor(1)
        hData.SetLineColor(1)
        hData.SetMarkerSize(1.3)
        hMC.SetFillStyle(1000)
        hMC.SetLineColor(kAzure - 8)
        hMC.SetFillColor(kAzure - 8)
        hemu.SetFillStyle(1000)
        hemu.SetLineColor(kGray)
        hemu.SetFillColor(kGray)
        hData.Rebin(rebin)
        hemu.Rebin(rebin)
        hMC.Rebin(rebin)
        ke, kee = self.GetKfactor(elname)
        km, kme = self.GetKfactor(muname)
        hemu.Scale(0.5 * (ke if chan == 'ElE' else km))
        hs = THStack()
        hs.Add(hemu)
        hs.Add(hMC)
        lab = 'e^{#pm}e^{#mp}' if chan == 'ElEl' else '#mu^{#pm}#mu^{#mp}'
        rlab = 'ee' if chan == 'ElEl' else '#mu#mu'
        processes = [
            'Z/#gamma*#rightarrow %s' % (lab),
            '0.5 k_{%s} #times Data(e#mu)' % rlab
        ]
        colors = {processes[0]: kAzure - 9, processes[1]: kGray}
        s = Stack(doRatio=False)
        s.SetXtitle(size=0.06, offset=0.8, nDiv=510, labSize=0.05)
        s.SetTextCMS(cmstex='CMS', x=0.13, y=0.88, s=0.06)
        s.SetTextCMSmode(texcmsMode='Preliminary', x=0.225, y=0.875, s=0.052)
        s.SetLumi(304.32)
        s.SetTextLumi(texlumi='%2.1f pb^{-1} (5.02 TeV)',
                      texlumiX=0.68,
                      texlumiY=0.95,
                      texlumiS=0.045)
        s.SetDataHisto(hData)
        s.SetColors(colors)
        s.SetStack(hs)
        s.SetOutName('DYestimate_%s%s' % (chan, level) +
                     ('_log' if log else ''))
        s.SetOutPath(self.outpath)
        plotMinimum = 0.5 if log else 0
        plotMaxScale = 10 if log else 1.3
        s.SetLogY(log)
        s.SetPlotMaxScale(plotMaxScale)
        s.SetPlotMinimum(plotMinimum)
        maximum = hData.GetMaximum() * (5 if log else 1.2)
        s.AddLine(76, 0.5, 76, maximum)
        s.AddLine(106, 0.5, 106, maximum)
        s.processes = processes
        s.SetLegendPos(x0=0.60, y0=0.55, x1=0.93, y1=0.91, size=0.042, ncol=1)
        s.DrawStack('m_{%s} (GeV)' % rlab)

    def DrawClosureMCeff(self,
                         level='dilepton',
                         outpath='~/www/temp/',
                         ratio=[0.9, 1.1]):
        self.SetMode('OF')
        self.SetChanAndLevel('', level)
        ke, kee = self.GetKfactor(elname)
        km, kme = self.GetKfactor(muname)
        print 'ke = %1.2f +/- %1.2f' % (ke, kee)
        print 'km = %1.2f +/- %1.2f' % (km, kme)

        hdata = TH1F('d1', 'd1', 2, 0, 2)
        hpred = TH1F('h1', 'h1', 2, 0, 2)
        err = lambda l: sqrt(sum([x * x for x in l]))
        '''
   hee1   = self.GetDYhisto(elname, level, False)
   hmm1   = self.GetDYhisto(muname, level, False)
   ee1 = hee1.Integral(); mm1 = hmm1.Integral()

   hdata.SetBinContent(1, ee1); hdata.SetBinError(1, sqrt(ee1));
   hdata.SetBinContent(2, mm1); hdata.SetBinError(2, sqrt(mm1));
   hpred.SetBinContent(1, mm1*ke1); hpred.SetBinError(1, mm1*ke1*( err([sqrt(mm1)/mm1, kee1/ke1]) ))
   hpred.SetBinContent(2, ee1*km1); hpred.SetBinError(2, ee1*km1*( err([sqrt(ee1)/ee1, kme1/km1]) ))
   '''
        sampName = 'TT'
        hname = 'Lep0Eta'
        h_emu = self.t.GetNamedHisto('%s_%s_%s' % (hname, 'ElMu', level),
                                     sampName)
        h_ee = self.t.GetNamedHisto(
            '%s_%s_%s' %
            (hname, 'ElEl', '2jetsnomet' if level == '2jets' else level),
            sampName)
        h_mu = self.t.GetNamedHisto(
            '%s_%s_%s' %
            (hname, 'MuMu', '2jetsnomet' if level == '2jets' else level),
            sampName)
        y_emu = h_emu.Integral() * 304.32
        y_mu = h_mu.Integral() * 304.32
        y_ee = h_ee.Integral() * 304.32
        d_ee = 0.5 * y_emu * ke
        d_ee_err = d_ee * (kee / ke)
        d_mu = 0.5 * y_emu * km
        d_mu_err = d_mu * (kme / km)
        hdata.SetBinContent(1, y_ee)
        hdata.SetBinError(1, y_ee / sqrt(h_ee.GetEntries()))
        hdata.SetBinContent(2, y_mu)
        hdata.SetBinError(2, y_mu / sqrt(h_mu.GetEntries()))
        hpred.SetBinContent(1, d_ee)
        hpred.SetBinError(1, d_ee_err)
        hpred.SetBinContent(2, d_mu)
        hpred.SetBinError(2, d_mu_err)

        p = HistoComp(outpath, doRatio=True, doNorm=False)
        hdata.SetLineWidth(1)
        hdata.SetMarkerSize(1.2)
        hdata.SetMarkerColor(1)
        hdata.SetMarkerStyle(20)
        hdata.SetFillColor(0)
        hdata.SetFillStyle(0)
        hpred.SetFillStyle(3144)
        hpred.SetFillColor(kAzure - 8)
        p.SetPlotMaxScale(1.5)
        p.SetLumi(304.32)
        p.AddHisto(hpred, 'l', 'e2', '0.5 x k_{ll} x t#bar{t} e#mu MC',
                   kAzure + 2, 2)
        p.AddHisto(hdata, 'pe', '', 'Same-flavor t#bar{t} MC', 1)
        p.SetBinLabels(['ee', '#mu#mu'])
        p.SetYratioTitle('Ratio')
        p.SetYtitle('t#bar{t} events')
        rmin, rmax = ratio
        p.SetLegendPos(0.15, 0.6, 0.5, 0.8, ncol=1)
        p.SetRatioMin(rmin)
        p.SetRatioMax(rmax)
        p.SetOutName('DYDDeffClosure_' + level)
        p.autoRatio = True
        p.PlotWithData = True
        p.Draw(0)

    def PrintDYestimate(self, doSF=False, name='', level=''):
        hee = self.GetDYhisto(elname, level, False)
        hmm = self.GetDYhisto(muname, level, False)
        self.SetChanAndLevel('', level)
        self.SetMode('SF' if doSF else 'OF')
        if name == '':
            name = 'DYDD_%s_%s' % ('SF' if doSF else 'OF', self.GetLevel())
        t = OutText(self.GetOutPath(), name, textformat='tex')
        t.SetTexAlign("l c c c")
        t.SetSeparatorLength(20 + (3 + 22) * 3)
        t.SetDefaultFixOption(False)
        t.line('%' + 'Drell-Yan estimate for %s and level \'%s\'' %
               ('SF channels' if doSF else 'all channels (no MET cut) ',
                self.GetLevel()))
        t.bar()
        s = lambda tit, vee, vmm, vem: t.line(
            t.fix(tit, 20) + t.vsep() + t.fix(vee, 22, 'c') + t.vsep() + t.fix(
                vmm, 22, 'c') + t.vsep() + t.fix(vem, 22, 'c'))
        v = lambda val, err: '%1.2f' % val + t.pm() + '%1.2f' % err
        d = lambda val, err: '%1.0f' % val + t.pm() + '%1.2f' % err
        s('', 'ee', '$\mu\mu$', 'e$\mu$')
        t.sep()
        mie, miee = self.GetMCin(elname)
        moe, moee = self.GetMCout(elname)
        mim, mime = self.GetMCin(muname)
        mom, mome = self.GetMCout(muname)
        s(' $N_{in}$        (MC)', v(mie, miee), v(mim, mime), '')
        s(' $N_{out}$       (MC)', v(moe, moee), v(mom, mome), '')

        re, ree = self.GetRoutin(elname)
        rm, rme = self.GetRoutin(muname)
        s(' $R_{out/in}$  (MC)', v(re, ree), v(rm, rme), '')

        ke, kee = self.GetKfactor(elname)
        km, kme = self.GetKfactor(muname)
        s(' $k_{ll}$            ', v(ke, kee), v(km, kme), '')

        ie, ier = self.GetDataIn(elname)
        im, imr = self.GetDataIn(muname)
        iem, iemr = self.GetDataIn('ElMu')
        s(' $N_{in}$      (Data)', d(ie, ier), d(im, imr), d(iem, iemr))
        t.sep()
        dde, ddee = self.GetDYDD(elname)
        ddm, ddme = self.GetDYDD(muname)
        tmc = ' DY estimate out (MC) ' if doSF else ' DY estimate (MC)'
        tdata = ' DY estimate out (DD) ' if doSF else ' DY estimate (DD)'
        if doSF:
            s(' DY estimate (MC)', v(moe, moee), v(mom, mome), '')
            s(' DY estimate (DD)', v(dde, ddee), v(ddm, ddme), '')
        else:
            ddem, ddeme = self.GetDYDD('ElMu')
            yDY = self.t.GetYield(self.GetDYfiles(), 'ElMu')
            yDYe = self.t.GetYieldStatUnc(self.GetDYfiles(), 'ElMu')
            s(' DY estimate (MC)', v(moe, moee), v(mom, mome), v(yDY, yDYe))
            s(' DY estimate (DD)', v(dde, ddee), v(ddm, ddme), v(ddem, ddeme))
        t.sep()
        sfee, sfeee = self.GetScaleFactor(elname)
        sfmm, sfmme = self.GetScaleFactor(muname)
        if doSF:
            s(' DD/MC ratio     ', v(sfee, sfeee), v(sfmm, sfmme), '')
        else:
            sfem, sfeme = self.GetScaleFactor('ElMu')
            s(' DD/MC ratio     ', v(sfee, sfeee), v(sfmm, sfmme),
              v(sfem, sfeme))
        t.bar()
        t.write()

    def PrintDYSFnjets(self):
        t = OutText(self.GetOutPath(), 'DYSF_njets')
        t.SetSeparatorLength(22 + (3 + 16) * 3)
        t.SetDefaultFixOption(False)
        t.line(
            'Drell-Yan data/MC scale factors for different jet multiplicities')
        t.bar()
        s = lambda tit, vee, vmm, vem: t.line(
            t.fix(tit, 22) + t.vsep() + t.fix(vee, 16, 'c') + t.vsep() + t.fix(
                vmm, 16, 'c') + t.vsep() + t.fix(vem, 16, 'c'))
        v = lambda val, err: '%1.2f' % val + t.pm() + '%1.2f' % err
        s('', elname, muname, 'ElMu')
        t.sep()
        #labels = ['Inclusive','== 1 jet', '== 2 jets', '>= 3 jets','>= 2 jets, >= 1 btag', '>= 2 btag']
        #levels = ['dilepton', 'eq1jet', 'eq2jet', 'geq3jet','1btag', '2btag']
        labels = ['Inclusive', '>= 2 jets', ' >= 1 btag']
        levels = ['dilepton', '2jets', '1btag']
        for i in range(len(labels)):
            if i == 4: t.sep()
            lab = labels[i]
            lev = levels[i]
            sfe, sfee = self.GetScaleFactor(elname, lev, 'SF')
            sfm, sfme = self.GetScaleFactor(muname, lev, 'SF')
            sfo, sfoe = self.GetScaleFactor('ElMu', lev, 'OF')
            s(' ' + lab,
              v(sfe, sfee) if sfe > 0 else '-',
              v(sfm, sfme) if sfm > 0 else '-',
              v(sfo, sfoe) if sfo > 0 else '-')
        t.bar()
        t.write()

    def __init__(self,
                 path,
                 outpath='./temp/',
                 chan='ElMu',
                 level='2jets',
                 DYsamples='DYJetsToLL_M_10to50,DYJetsToLL_MLL50',
                 DataSamples='HighEGJet,SingleMuon, DoubleMuon',
                 lumi=304.32,
                 massRange=[91 - 15, 91 + 15],
                 mode='',
                 histonameprefix='H',
                 hname='DY_InvMass'):
        self.SetPath(path)
        self.SetOutPath(outpath)
        self.t = TopHistoReader(path)
        self.t.SetHistoNamePrefix(histonameprefix)
        self.SetLumi(lumi)
        self.SetChanAndLevel(chan, level)
        self.SetDYsamples(DYsamples)
        self.SetDataSamples(DataSamples)
        self.SetMassRange(massRange[0], massRange[1])
        self.SetHistoNameOF()
        self.SetHistoNameSF()
        if chan == 'ElMu':
            if hname != '': self.SetHistoNameOF(hname)
            self.SetMode('OF')
        else:
            if hname != '': self.SetHistoNameSF(hname)
            self.SetMode('SF')
        if mode != '': self.SetMode(mode)
class DYDD:

    ### Set methods
    def SetPath(self, p):
        if not p.endswith('/'): p += '/'
        self.path = p

    def SetOutPath(self, p):
        self.outpath = p

    def SetMode(self, mode='OF', hname=''):
        self.doOF = True
        if mode in ['SF', 'Elec', 'ElEl', 'Muon', 'MuMu']:
            self.doOF = False
        if self.doOF:
            if hname != '': self.SetHistoNameOF(hname)
            self.SetZhistoName(self.hnameOF)
        else:
            if hname != '': self.SetHistoNameSF(hname)
            self.SetZhistoName(self.hnameSF)

    def SetLumi(self, l):
        self.lumi = l
        self.t.SetLumi(self.lumi)

    def SetHistoNameOF(self, h='DY_InvMass'):
        self.hnameOF = h

    def SetHistoNameSF(self, h='DY_SF_InvMass'):
        self.hnameSF = h

    def SetDYsamples(self, f):
        self.DYfiles = f

    def SetDataSamples(self, f):
        self.datafiles = f

    def SetChannel(self, c):
        self.chan = c

    def SetLevel(self, l):
        self.level = l

    def SetZhistoName(self, h):
        self.zhname = h

    def SetMassRange(self, minM=91 - 15, maxM=91 + 15):
        self.minMZ = minM
        self.maxMZ = maxM

    def SetChanAndLevel(self, chan='', level=''):
        ''' Manages to set chan and leve to the class and the TopHistoReader '''
        if chan != '': self.SetChannel(chan)
        if level != '': self.SetLevel(level)
        self.t.SetChan(self.GetChan())
        self.t.SetLevel(self.GetLevel())
        return self.GetChan(), self.GetLevel()

    ### Get methods
    def GetPath(self):
        return self.path

    def GetOutPath(self):
        return self.outpath

    def GetZhistoName(self):
        return self.zhname

    def GetDYfiles(self):
        return self.DYfiles

    def GetDataFiles(self):
        return self.datafiles

    def GetLevel(self):
        return self.level

    def GetChan(self):
        return self.chan

    ### Calculate quantities...

    def GetDYhisto(self, chan='', level='', isData=True):
        # ARREGLAR PARA QUE COJA EL ADECUADO DEPENDIENDO DEL CANAL!! O HACER FUNCION PARA INDICAR CANAL EMU
        chan, level = self.SetChanAndLevel(chan, level)
        if isData:
            self.t.SetIsData(True)
            pr = self.GetDataFiles()
        else:
            self.t.SetIsData(False)
            pr = self.GetDYfiles()
        zname = self.GetZhistoName()
        if level == 'dilepton' and zname[-4:] == 'ElMu': zname = zname[:-4]
        h = self.t.GetHisto(pr, zname, chan, level)
        h.SetDirectory(0)
        return h

    def GetHdata(self, chan, level):
        return self.GetDYhisto(chan, level, True)

    def GetHMC(self, chan, level):
        return self.GetDYhisto(chan, level, False)

    def DYyield(self, direc='in', isData=True, chan='', level=''):
        h = self.GetDYhisto(chan, level, isData)
        b0 = h.FindBin(self.minMZ)
        bN = h.FindBin(self.maxMZ)
        nbins = h.GetNbinsX()
        integral = h.Integral()
        y = 0
        err = 0
        if direc == 'in' or direc == 'In' or direc == 'IN':
            y += h.Integral(b0, bN)
        else:
            y += h.Integral(0, b0 - 1)
            y += h.Integral(bN + 1, nbins + 1)
        if isData: err = sqrt(y)
        else:
            entries = h.GetEntries()
            err = sqrt((y * integral) / entries)
        if y < 0:  # Avoid wierd numbers due to negative weights...
            y = 0
            err = 0
        return y, err

    def GetDataIn(self, chan='', level=''):
        return self.DYyield('in', True, chan, level)

    def GetDataOut(self, chan='', level=''):
        return self.DYyield('out', True, chan, level)

    def GetMCin(self, chan='', level=''):
        return self.DYyield('in', False, chan, level)

    def GetMCout(self, chan='', level=''):
        return self.DYyield('out', False, chan, level)

    def GetRoutin(self, chan='', level=''):
        ''' Returns ratio Rout/in from MC '''
        rin, errin = self.GetMCin(chan, level)
        out, errout = self.GetMCout(chan, level)
        r = out / rin if rin != 0 else 0
        err = r * SumSquare(
            [errout / out if out != 0 else 0, errin / rin if rin != 0 else 0])
        return r, err

    def GetKfactor(self, chan='', level=''):
        ''' Calculate the k factor k_ee, k_mumu '''
        chan, level = self.SetChanAndLevel(chan, level)
        rinElec, errElec = self.GetDataIn(elname, level)
        rinMuon, errMuon = self.GetDataIn(muname, level)
        k = (rinElec / rinMuon if rinMuon != 0 else 0) if chan == elname else (
            rinMuon / rinElec if rinElec != 0 else 0)
        kerr = k * SumSquare([
            errElec / (2 * rinElec) if rinElec != 0 else 0, errMuon /
            (2 * rinMuon) if rinMuon != 0 else 0
        ])
        return k, kerr

    def GetDYDD(self, chan='', level='', mode=''):
        ''' Returns the DY estimate from data '''
        chan, level = self.SetChanAndLevel(chan, level)
        if chan == 'ElMu': self.SetMode('ElMu')
        if mode != '': self.SetMode(mode)
        routin, routin_err = self.GetRoutin(chan, level)
        NemuIn, NemuIn_err = self.GetDataIn('ElMu', level)
        kee, keerr = self.GetKfactor(elname, level)
        NeeIn, NeeInerr = self.GetDataIn(elname, level)
        kmm, kmmrr = self.GetKfactor(muname, level)
        NmmIn, NmmInerr = self.GetDataIn(muname, level)
        est = lambda r, Nin, Nemu, k: r * (Nin - Nemu * k / 2)
        esterr = lambda r, Nin, Nemu, k, er, eNin, eNemu, ek: SumSquare([
            est(r, Nin, Nemu, k) *
            (er / r
             if r != 0 else 0), r * eNin, r * k / 2 * eNemu, r * Nemu / 2 * ek
        ])
        N = 0
        Nerr = 0
        if chan == elname:
            N = est(routin, NeeIn, NemuIn, kee)
            Nerr = esterr(routin, NeeIn, NemuIn, kee, routin_err, NeeInerr,
                          NemuIn_err, keerr)
        elif chan == muname:
            N = est(routin, NmmIn, NemuIn, kmm)
            Nerr = esterr(routin, NmmIn, NemuIn, kmm, routin_err, NmmInerr,
                          NemuIn_err, kmmrr)
        else:  # ElMu
            self.t.SetIsData(False)
            yDY = self.t.GetYield(self.GetDYfiles(), 'ElMu')
            yDYe = self.t.GetYieldStatUnc(self.GetDYfiles(), 'ElMu')
            SF, err = self.GetScaleFactor('ElMu')
            N = yDY * SF
            Nerr = N * SumSquare([
                err / SF if SF != 0 else err, yDYe / yDY if yDY != 0 else yDYe
            ])
        if N < 0:
            N = 0
            Nerr = 0
        if not Nerr == Nerr: Nerr = 0
        return N, Nerr

    def GetScaleFactor(self, chan='', level='', mode=''):
        ''' Returns the data/MC ratio for the DY estimate '''
        chan, level = self.SetChanAndLevel(chan, level)
        if chan == 'ElMu': self.SetMode('ElMu')
        if mode != '': self.SetMode(mode)
        SF = 1
        err = 0
        if chan == muname or chan == elname:
            dd, dde = self.GetDYDD(chan)
            mo, moe = self.GetMCout(chan)
            SF = dd / mo if mo != 0 else 0
            err = SF * SumSquare(
                [dde / dd if dd != 0 else 0, moe / mo if mo != 0 else 0])
        elif chan == 'ElMu':
            e, er = self.GetScaleFactor(elname)
            m, mr = self.GetScaleFactor(muname)
            SF = sqrt(e * m)
            err = SF * SumSquare(
                [er / e if e != 0 else 0, mr / m if m != 0 else 0])
        return SF, err

    def PrintDYestimate(self, doSF=False, name='', level=''):
        self.SetChanAndLevel('', level)
        self.SetMode('SF' if doSF else 'OF')
        if name == '':
            name = 'DYDD_%s_%s' % ('SF' if doSF else 'OF', self.GetLevel())
        t = OutText(self.GetOutPath(), name)
        t.SetSeparatorLength(20 + (3 + 22) * 3)
        t.SetDefaultFixOption(False)
        t.line('Drell-Yan estimate for %s and level \'%s\'' %
               ('SF channels' if doSF else 'all channels (no MET cut) ',
                self.GetLevel()))
        t.bar()
        s = lambda tit, vee, vmm, vem: t.line(
            t.fix(tit, 20) + t.vsep() + t.fix(vee, 22, 'c') + t.vsep() + t.fix(
                vmm, 22, 'c') + t.vsep() + t.fix(vem, 22, 'c'))
        v = lambda val, err: '%1.3f' % val + t.pm() + '%1.3f' % err
        d = lambda val, err: '%1.0f' % val + t.pm() + '%1.2f' % err
        s('', elname, muname, 'ElMu')
        t.sep()
        mie, miee = self.GetMCin(elname)
        moe, moee = self.GetMCout(elname)
        mim, mime = self.GetMCin(muname)
        mom, mome = self.GetMCout(muname)
        s(' N_in        (MC)', v(mie, miee), v(mim, mime), '')
        s(' N_out       (MC)', v(moe, moee), v(mom, mome), '')

        re, ree = self.GetRoutin(elname)
        rm, rme = self.GetRoutin(muname)
        s(' R_(out/in)  (MC)', v(re, ree), v(rm, rme), '')

        ke, kee = self.GetKfactor(elname)
        km, kme = self.GetKfactor(muname)
        s(' k_ll            ', v(ke, kee), v(km, kme), '')

        ie, ier = self.GetDataIn(elname)
        im, imr = self.GetDataIn(muname)
        iem, iemr = self.GetDataIn('ElMu')
        s(' N_in      (Data)', d(ie, ier), d(im, imr), d(iem, iemr))
        t.sep()
        dde, ddee = self.GetDYDD(elname)
        ddm, ddme = self.GetDYDD(muname)
        tmc = ' DY estimate out (MC) ' if doSF else ' DY estimate (MC)'
        tdata = ' DY estimate out (DD) ' if doSF else ' DY estimate (DD)'
        if doSF:
            s(' DY estimate (MC)', v(moe, moee), v(mom, mome), '')
            s(' DY estimate (DD)', v(dde, ddee), v(ddm, ddme), '')
        else:
            ddem, ddeme = self.GetDYDD('ElMu')
            yDY = self.t.GetYield(self.GetDYfiles(), 'ElMu')
            yDYe = self.t.GetYieldStatUnc(self.GetDYfiles(), 'ElMu')
            s(' DY estimate (MC)', v(moe, moee), v(mom, mome), v(yDY, yDYe))
            s(' DY estimate (DD)', v(dde, ddee), v(ddm, ddme), v(ddem, ddeme))
        t.sep()
        sfee, sfeee = self.GetScaleFactor(elname)
        sfmm, sfmme = self.GetScaleFactor(muname)
        if doSF:
            s(' DD/MC ratio     ', v(sfee, sfeee), v(sfmm, sfmme), '')
        else:
            sfem, sfeme = self.GetScaleFactor('ElMu')
            s(' DD/MC ratio     ', v(sfee, sfeee), v(sfmm, sfmme),
              v(sfem, sfeme))
        t.bar()
        t.write()

    def PrintDYSFnjets(self):
        t = OutText(self.GetOutPath(), 'DYSF_njets')
        t.SetSeparatorLength(22 + (3 + 16) * 3)
        t.SetDefaultFixOption(False)
        t.line(
            'Drell-Yan data/MC scale factors for different jet multiplicities')
        t.bar()
        s = lambda tit, vee, vmm, vem: t.line(
            t.fix(tit, 22) + t.vsep() + t.fix(vee, 16, 'c') + t.vsep() + t.fix(
                vmm, 16, 'c') + t.vsep() + t.fix(vem, 16, 'c'))
        v = lambda val, err: '%1.2f' % val + t.pm() + '%1.2f' % err
        s('', elname, muname, 'ElMu')
        t.sep()
        #labels = ['Inclusive','== 1 jet', '== 2 jets', '>= 3 jets','>= 2 jets, >= 1 btag', '>= 2 btag']
        #levels = ['dilepton', 'eq1jet', 'eq2jet', 'geq3jet','1btag', '2btag']
        labels = ['Inclusive', '>= 2 jets', ' >= 1 btag']
        levels = ['dilepton', '2jets', '1btag']
        for i in range(len(labels)):
            if i == 4: t.sep()
            lab = labels[i]
            lev = levels[i]
            sfe, sfee = self.GetScaleFactor(elname, lev, 'SF')
            sfm, sfme = self.GetScaleFactor(muname, lev, 'SF')
            sfo, sfoe = self.GetScaleFactor('ElMu', lev, 'OF')
            s(' ' + lab,
              v(sfe, sfee) if sfe > 0 else '-',
              v(sfm, sfme) if sfm > 0 else '-',
              v(sfo, sfoe) if sfo > 0 else '-')
        t.bar()
        t.write()

    def __init__(self,
                 path,
                 outpath='./temp/',
                 chan='ElMu',
                 level='2jets',
                 DYsamples='DYJetsToLL_M_10to50,DYJetsToLL_MLL50',
                 DataSamples='HighEGJet,SingleMuon, DoubleMuon',
                 lumi=308.54,
                 massRange=[91 - 15, 91 + 15],
                 mode='',
                 histonameprefix='H',
                 hname='DY_InvMass'):
        self.SetPath(path)
        self.SetOutPath(outpath)
        self.t = TopHistoReader(path)
        self.t.SetHistoNamePrefix(histonameprefix)
        self.SetLumi(lumi)
        self.SetChanAndLevel(chan, level)
        self.SetDYsamples(DYsamples)
        self.SetDataSamples(DataSamples)
        self.SetMassRange(massRange[0], massRange[1])
        self.SetHistoNameOF()
        self.SetHistoNameSF()
        if chan == 'ElMu':
            if hname != '': self.SetHistoNameOF(hname)
            self.SetMode('OF')
        else:
            if hname != '': self.SetHistoNameSF(hname)
            self.SetMode('SF')
        if mode != '': self.SetMode(mode)
class CrossSection:

    ### Add background, signal and data numbers
    def AddBkg(self, name, val, normunc=0, systunc=0, statunc=0, samples=''):
        ''' Add a bkg process (must include yield, name, uncertainties...) '''
        self.bkg.append(
            Process(name,
                    Yield=val,
                    NormUnc=normunc,
                    SystUnc=systunc,
                    StatUnc=statunc,
                    samples=samples))

    def SetSignal(self, name, val, statunc=0, samples=''):
        ''' Set the signal process (must include yield, name, uncertainties...) '''
        self.signal = Process(name,
                              Yield=val,
                              StatUnc=statunc,
                              samples=samples)

    def SetData(self, n):
        ''' Number of observed events '''
        self.data = n
        self.dataunc = sqrt(n)

    ### Add uncertainties... experimental and modeling
    def AddExpUnc(self, name, val):
        ''' Add the uncertainty 'name' with value 'val' to the experimental uncertainties '''
        self.effUnc[name] = val

    def AddModUnc(self, name, val=0., do=''):
        ''' Add the uncertainty 'name' with value 'val' to the modeling uncertainties (on acceptance) 
        if sample names are given (up/down) the uncertainty is read from the histos in that samples 
    '''
        if isinstance(val, float):
            self.accUnc[name] = val
        else:
            nom = self.GetSignalYield()
            up = self.t.GetYield(val)
            do = self.t.GetYield(do)
            var = max(abs(up - nom), abs(do - nom)) / nom
            self.AddModUnc(name, var)

    ### Setting methods
    def SetTextFormat(self, textformat):
        ''' Set the format of the output tables (txt, tex) '''
        self.textformat = textformat

    def SetChan(self, ch):
        ''' Set the channel '''
        self.chan = ch

    def SetLevel(self, lev):
        ''' Set level '''
        self.lev = lev

    def SetThXsec(self, t):
        ''' Set the theoretical cross section using to normalize signal events '''
        self.thxsec = t

    def SetDoFiducial(self, val=True):
        ''' Boolean to activate printing the fiducial cross section '''
        self.doFiducial = val

    def SetLumi(self, l):
        ''' Set the luminosity '''
        self.lumi = l

    def SetLumiUnc(self, l):
        ''' Set relative lumi unc '''
        self.lumiunc = l

    def SetFiduEvents(self, f):
        ''' Number of fiducual (unweighted) events '''
        self.nfidu = f

    def SetGenEvents(self, g):
        ''' Number of generated events in the sample '''
        self.ngen = g

    def SetBR(self, b):  # Use relative unc
        ''' The branching ratio to what we consider signal '''
        self.BR = b

    def SetOutPath(self, p):
        ''' Set the output path '''
        self.outpath = p

    ### Get parameters...
    def GetThXsec(self):
        return self.thxsec

    def GetLumi(self):
        return self.lumi

    def GetLumiUnc(self):
        return self.lumiunc

    def GetFiduEvents(self, sys=''):
        return self.nfidu

    def GetGenEvents(self):
        return self.ngen

    def GetBR(self):
        return self.BR

    def GetLevel(self):
        return self.lev

    def GetChan(self):
        return self.chan

    def GetBkg(self, name):
        for b in self.bkg:
            if b.GetName() == name: return b
        print 'WARNING: not found background ' + name

    def GetBkgTotRelUnc(self, name):
        return self.GetBkg(name).GetTotRelUnc()

    def GetBkgTotAbsUnc(self, name):
        return self.GetBkgYield(name) * self.GetBkgTotRelUnc(name)

    def GetBkgYield(self, name, sys=''):
        pr = self.GetBkg(name)
        if sys == '': return pr.GetYield()
        elif IsUpSyst(sys): return pr.GetYield() * (1 + pr.GetTotRelUnc())
        elif IsDownSyst(sys): return pr.GetYield() * (1 - pr.GetTotRelUnc())
        else: return pr.GetYield() * (1 + pr.GetTotRelUnc())

    def GetData(self):
        return self.data

    def GetDataUnc(self):
        return self.dataunc

    def GetSignal(self):
        return self.signal

    def GetSignalYield(self, sys='', d=''):
        y = self.signal.GetYield()
        if sys == '': return y
        u = self.GetUnc(sys)
        if IsDownSyst(d): return y * (1 - u)
        return y * (1 + u)

    def GetExpUnc(self, name=''):
        if name == '': return self.effUnc
        else: return self.effUnc[name]

    def GetModUnc(self, name=''):
        if name == '': return self.accUnc
        else: return self.accUnc[name]

    def GetUnc(self, name):
        if name in self.modUnc.keys(): return self.GetModUnc(name)
        elif name in self.effUnc.keys(): return self.GetEffUnc(name)
        else: print 'WARNING: not found uncertainty \'%d\'' % name
        return 0

    def GetTotBkg(self, sys='', d=''):
        ''' Returns the total expected bkg '''
        if sys != '' and sys in [x.GetName() for x in self.bkg]:
            y = self.GetTotBkg()
            var = self.GetBkgTotAbsUnc(sys)
            y = y - var if IsDownSyst(sys + d) else y + var
        else:
            y = sum([x.GetYield() for x in self.bkg])
        return y

    def GetTotBkgStatUnc(self):
        ''' Returns the total stat unc on bkg '''
        b = 0
        for pr in self.bkg:
            b += pr.GetStatUnc() * pr.GetStatUnc()
        return sqrt(b)

    def GetTotBkgSystUnc(self):
        ''' Returns the total syst unc on bkg '''
        b = 0
        for pr in self.bkg:
            b += pr.GetSystAbsUnc() * pr.GetSystAbsUnc()
        return sqrt(b)

    def GetXsec(self, sys='', d=''):
        ''' Returns the measured cross section '''
        data = self.GetData()
        bkg = self.GetTotBkg(sys, d) if sys in [x.GetName() for x in self.bkg
                                                ] else self.GetTotBkg()
        y = self.GetSignalYield(sys, d)
        thxsec = self.GetThXsec()
        return self.ComputeXsec(data, bkg, y)

    def GetFiduXsec(self):
        ''' Returns the fiducial cross section '''
        # fidu = inclusive*(A)
        return self.ComputeXsec() * self.GetAcc()

    def GetAcc(self, sys=''):
        ''' Returns the measured acceptance '''
        return self.GetFiduEvents(sys) / (self.GetGenEvents() * self.GetBR())

    def GetAccUnc(self):
        ''' Return the syst unc on acceptance '''
        err = 0
        for a in self.accUnc.values():
            err += a * a
        return sqrt(err)

    def GetEff(self, sys=''):
        ''' Returns the measured efficiency '''
        y = self.GetSignalYield(sys)
        A = self.GetAcc()
        BR = self.GetBR()
        lum = self.GetLumi()
        xth = self.GetThXsec()
        return (y) / (A * lum * xth * BR)

    def GetEffUnc(self):
        ''' Return the syst unc on efficiency '''
        err = 0
        for a in self.effUnc.values():
            err += a * a
        return sqrt(err)

    def GetXsecSystUnc(self):
        ''' Returns the xsec syst unc on cross section '''
        effunc = self.GetEffUnc()
        accunc = self.GetAccUnc()
        bkgunc2 = 0
        for b in [x.GetName() for x in self.bkg]:
            bkgunc2 += self.GetXsecBkgRelUnc(b) * self.GetXsecBkgRelUnc(b)
        return sqrt(effunc * effunc + accunc * accunc + bkgunc2)

    def GetXsecLumiUnc(self):
        ''' Returns the xsec lumi uncertainty on cross section '''
        #return self.GetXsec()*(1/self.GetLumi() - 1/(self.GetLumi() * (1+self.GetLumiUnc()) ))
        r = self.GetLumiUnc()
        return (abs(r / (1 - r)) + abs(r / (1 + r))) / 2

    def GetXsecStatUnc(self):
        ''' Returns the stat unc on cross section '''
        xsec = self.ComputeXsec()
        varUp = self.ComputeXsec(self.GetData() + self.GetDataUnc(),
                                 self.GetTotBkg(), self.GetSignalYield())
        varDo = self.ComputeXsec(self.GetData() - self.GetDataUnc(),
                                 self.GetTotBkg(), self.GetSignalYield())
        return max([abs(xsec - varDo) / xsec, abs(xsec - varUp) / xsec])

    def GetXsecBkgRelUnc(self, bkgname):
        ''' Returns the relative unc on the xsec due to the total unc on a bkg estimation '''
        nom = self.ComputeXsec()
        varUp = self.ComputeXsec(self.GetData(), self.GetTotBkg(bkgname, 'Up'),
                                 self.GetSignalYield())
        varDo = self.ComputeXsec(self.GetData(),
                                 self.GetTotBkg(bkgname, 'Down'),
                                 self.GetSignalYield())
        return max([abs(nom - varUp) / nom, abs(nom - varDo) / nom])

    ### Several printing methods!
    def PrintYields(self, name='yields', doStat=True, doSyst=True):
        t = OutText(self.outpath, name, "new", textformat=self.textformat)
        t.SetTexAlign("l c")
        nsem = 16 + 3 + 8 + (5 + 8 if doStat else 0) + (5 + 8 if doSyst else 0)
        t.SetSeparatorLength(nsem)
        t.line('%' + 'Yields for channel \'%s\' and level \'%s\'' %
               (self.GetChan(), self.GetLevel()))
        t.bar()
        for pr in self.bkg:
            name = t.fix(" %s" % pr.GetName(), 16, 'l', 0)
            y = t.fix("%1.2f" % pr.GetYield(), 8, 0)
            stat = t.fix("%1.2f" % pr.GetStatUnc(), 8, 0)
            syst = t.fix("%1.2f" % pr.GetSystAbsUnc(), 8, 0)
            t.line(name + t.vsep() + y + ((t.pm() + stat) if doStat else '') +
                   ((t.pm() + syst) if doSyst else ''))
        t.sep()
        totbkg = t.fix("%1.2f" % self.GetTotBkg(), 8, 0)
        totbkgstat = t.fix("%1.2f" % self.GetTotBkgStatUnc(), 8, 0)
        totbkgsyst = t.fix("%1.2f" % self.GetTotBkgSystUnc(), 8, 0)
        t.line(
            t.fix(" Total bkg", 16, 'l', 0) + t.vsep() + totbkg +
            ((t.pm() + totbkgstat) if doStat else '') +
            ((t.pm() + totbkgsyst) if doSyst else ''))
        t.sep()
        y = self.GetSignalYield()
        signal = t.fix(" %s" % (self.GetSignal().GetName()), 16, 'l', 0)
        ysig = t.fix("%1.2f" % y, 8, 0)
        sigunc = t.fix("%1.2f" % (self.GetXsecSystUnc() * y), 8, 0)
        sigsta = t.fix("%1.2f" % self.GetSignal().GetStatUnc(), 8, 0)
        t.line(signal + t.vsep() + ysig +
               ((t.pm() + sigsta) if doStat else '') +
               ((t.pm() + sigunc) if doSyst else ''))
        t.sep()
        t.line(
            t.fix(" Data", 16, 'l', 0) + t.vsep() +
            t.fix("%i" % self.GetData(), 8, 0))
        t.bar()
        t.write()

    def PrintXsec(self, name='xsec'):
        t = OutText(self.outpath, name, "new", textformat=self.textformat)
        t.SetTexAlign("l c")
        t.SetSeparatorLength(26 + 3 + 20 + 5)
        t.SetDefaultFixOption(False)
        t.line('%' + 'tt cross section for channel \'%s\' and level \'%s\'' %
               (self.GetChan(), self.GetLevel()))
        acc = self.GetAcc()
        eff = self.GetEff()
        t.bar()
        t.line(
            t.fix(' Acceptance', 16, 'r') + t.vsep() +
            t.fix("%1.4f" % acc, 6) + t.pm() +
            t.fix("%1.2f" % (acc * self.GetAccUnc()), 8))
        t.line(
            t.fix(' Efficiency', 16, 'r') + t.vsep() +
            t.fix("%1.4f" % eff, 6) + t.pm() +
            t.fix("%1.2f" % (eff * self.GetEffUnc()), 8))
        t.sep()
        t.line(
            t.fix(' Branching ratio', 16, 'r') + t.vsep() +
            t.fix("%1.4f" % self.GetBR(), 6))
        t.line(
            t.fix(' Gen events', 16, 'r') + t.vsep() +
            t.fix("%d" % self.GetGenEvents(), 9))
        t.line(
            t.fix(' Fiducial events', 16, 'r') + t.vsep() +
            t.fix("%d" % self.GetFiduEvents(), 9))
        if self.doFiducial:
            t.sep()
            xsec = self.GetFiduXsec()
            stat = self.GetXsecStatUnc()
            syst = self.GetEffUnc()
            lumi = self.GetXsecLumiUnc()
            #t.line(t.fix(' Fiducial cross section', 26, 'r') + t.vsep() + t.fix("%1.2f"%xsec,6))
            #t.line(t.fix(' +\- ', 26, 'r')            + '   ' + t.fix('%1.2f (%1.2f'%(stat*xsec,stat*100) + ' %) (stat)',20, 'l'))
            #t.line(t.fix(' +\- ', 26, 'r')            + '   ' + t.fix('%1.2f (%1.2f'%(syst*xsec,syst*100) + ' %) (syst)',20, 'l'))
            #t.line(t.fix(' +\- ', 26, 'r')            + '   ' + t.fix('%1.2f (%1.2f'%(lumi*xsec,lumi*100) + ' %) (lumi)',20, 'l'))
        t.sep()
        xsec = self.GetXsec()
        stat = self.GetXsecStatUnc()
        syst = self.GetXsecSystUnc()
        lumi = self.GetXsecLumiUnc()
        t.line(
            t.fix(' Inclusive cross section', 26, 'r') + t.vsep() +
            t.fix("%1.2f" % xsec, 6))
        t.line(
            t.fix(' $\pm$ ', 26, 'r') + '   ' +
            t.fix('%1.2f (%1.2f' %
                  (stat * xsec, stat * 100) + ' \%) (stat)', 20, 'l') +
            t.vsep())
        t.line(
            t.fix(' $\pm$ ', 26, 'r') + '   ' +
            t.fix('%1.2f (%1.2f' %
                  (syst * xsec, syst * 100) + ' \%) (syst)', 20, 'l') +
            t.vsep())
        t.line(
            t.fix(' $\pm$ ', 26, 'r') + '   ' +
            t.fix('%1.2f (%1.2f' %
                  (lumi * xsec, lumi * 100) + ' \%) (lumi)', 20, 'l') +
            t.vsep())
        t.bar()
        t.write()

    def AddToTxt(self, name='xsec', lab='e#mu'):
        t = OutText(self.outpath, name, "new", textformat=self.textformat)
        text = t.GetTextFromOutFile(form='txt')
        xsec = self.GetXsec()
        stat = self.GetXsecStatUnc() * xsec
        syst = self.GetXsecSystUnc() * xsec
        lum = self.GetXsecLumiUnc() * xsec
        isthere = False
        for l in text.splitlines():
            if l == '' or l.replace(' ', '') == '': continue
            if l.startswith(lab):
                isthere = True
                t.line('%s %1.2f %1.2f %1.2f %1.2f' %
                       (lab, xsec, stat, syst, lum))
            else:
                t.line(l)
        if not isthere:
            t.line('%s %1.2f %1.2f %1.2f %1.2f' % (lab, xsec, stat, syst, lum))
        t.write()

    def PrintSystTable(self, name='uncertainties'):
        t = OutText(self.outpath, name, "new", textformat=self.textformat)
        t.SetTexAlign("l c")
        t.SetSeparatorLength(30)
        t.SetDefaultFixOption(False)
        t.line('%Uncertainties on tt inclusive cross section \n% ' +
               'for channel \'%s\' and level \'%s\'' %
               (self.GetChan(), self.GetLevel()))
        exp = self.GetExpUnc()
        mod = self.GetModUnc()
        stat = self.GetXsecStatUnc()
        lum = self.GetXsecLumiUnc()
        syst = self.GetXsecSystUnc()
        xsec = self.GetXsec()
        t.bar()
        t.line(t.fix(' Source', 18, 'l') + t.vsep() + fix("value (\%)", 6))
        t.sep()
        for b in [x.GetName() for x in self.bkg]:
            t.line(
                fix(' ' + b, 18, 'r') + t.vsep() +
                fix('%1.2f' % (self.GetXsecBkgRelUnc(b) * 100), 6))
        t.sep()
        for e in exp.keys():
            t.line(
                fix(' ' + e, 18, 'l') + t.vsep() +
                fix('%1.2f' % (exp[e] * 100), 6))
        t.sep()
        for e in mod.keys():
            t.line(
                fix(' ' + e, 18, 'l') + t.vsep() +
                fix('%1.2f' % (mod[e] * 100), 6))
        t.sep()
        t.line(
            fix(' Total systematic', 18, 'l') + t.vsep() +
            fix('%1.2f' % (syst * 100), 6))
        t.sep()
        t.line(
            fix(' Statistics', 18, 'l') + t.vsep() +
            fix('%1.2f' % (stat * 100), 6))
        t.sep()
        t.line(
            fix(' Luminosity', 18, 'l') + t.vsep() +
            fix('%1.2f' % (lum * 100), 6))
        t.bar()
        t.write()

    ### Other
    def ComputeXsec(self, data='', bkg='', y=''):
        ''' Computes the xsec from data, bkg and expected yield '''
        if data == '': data = self.data
        if bkg == '': bkg = self.GetTotBkg()
        if y == '': y = self.GetSignalYield()
        return (data - bkg) / y * self.GetThXsec()

    def SetPathToTrees(self, ptt):
        self.pathToTrees = ptt

    def SetMotherName(self, mn):
        self.motherfname = mn

    def GetNGenEvents(self):
        self.treesow = TChain('Runs', 'Runs')
        files = GetFiles(self.pathToTrees, self.motherfname)
        for f in files:
            self.treesow.Add(f)

    def ReadHistos(self,
                   path,
                   chan='ElMu',
                   level='2jets',
                   lumi=Lumi,
                   lumiunc=0.04,
                   bkg=[],
                   signal=[],
                   data='',
                   expUnc=[],
                   modUnc=[],
                   histoPrefix=''):
        ''' Set the xsec from histos '''
        if isinstance(expUnc, str): expUnc = expUnc.replace(' ', '').split(',')
        if isinstance(modUnc, str): modUnc = modUnc.replace(' ', '').split(',')
        self.SetChan(chan)
        self.SetLevel(level)
        self.t = TopHistoReader(path)
        self.t.SetHistoNamePrefix(histoPrefix)
        self.t.SetLumi(lumi)
        self.t.SetChan(chan)
        self.t.SetLevel(level)
        self.ss = SampleSums(self.pathToTrees, self.motherfname, 'Runs')
        signalName = signal[0]
        signalSample = signal[1]

        # GetFiduEvents
        hfiduname = 'FiduEvents'  #_%s'%chan
        fiduEvents = self.t.GetNamedHisto(
            hfiduname, signalSample).GetBinContent(invlevel[level])
        nGenEvents = self.ss.GetCount(
            'Count')  #self.GetNGenEvents(signalSample)
        self.SetLumiUnc(lumiunc)
        self.SetFiduEvents(fiduEvents)
        self.SetGenEvents(nGenEvents)
        for l in bkg:
            if len(l) == 3:
                name, pr, unc = l
                expunc = expUnc
            elif len(l) == 4:
                name, pr, unc, expunc = l
            self.AddBkg(name, self.t.GetYield(pr), unc,
                        self.t.GetUnc(pr, chan, level, expUnc),
                        self.t.GetYieldStatUnc(pr))
        self.SetSignal(signalName, self.t.GetYield(signalSample),
                       self.t.GetYieldStatUnc(signalSample))
        self.t.SetIsData(True)
        self.SetData(self.t.GetYield(data))
        self.t.SetIsData(False)
        for e in expUnc:
            self.AddExpUnc(e, self.t.GetUnc(signal[1], chan, level, e))
        # Modeling uncertainties
        if 'pdf' in modUnc or 'PDF' in modUnc or 'Scale' in modUnc or 'ME' in modUnc or 'scale' in modUnc:
            pathToTrees = self.pathToTrees  #'/pool/ciencias/userstorage/juanr/nanoAODv4/5TeV/5TeV_5sept/'
            motherfname = self.motherfname  #'TT_TuneCP5_PSweights_5p02TeV'
            w = WeightReader(path,
                             '',
                             chan,
                             level,
                             sampleName='TT',
                             pathToTrees=pathToTrees,
                             motherfname=motherfname,
                             PDFname='PDFweights',
                             ScaleName='ScaleWeights',
                             lumi=Lumi,
                             histoprefix=histoPrefix)
            #w.SetSampleName(signalName)
            if 'pdf' in modUnc or 'PDF' in modUnc:
                self.AddModUnc('PDF', w.GetPDFandAlphaSunc())
            if 'scale' in modUnc or 'ME' in modUnc:
                self.AddModUnc('Scale ME', w.GetMaxRelUncScale())
        if 'ISR' in modUnc or 'isr' in modUnc:
            self.AddModUnc('ISR',
                           self.t.GetUnc(signalSample, chan, level, 'ISR'))
        if 'FSR' in modUnc or 'fsr' in modUnc:
            self.AddModUnc('FSR',
                           self.t.GetUnc(signalSample, chan, level, 'FSR'))

    def __init__(self,
                 outpath='./temp/',
                 lev='',
                 chan='',
                 genEvents=1,
                 fiduEvents=1,
                 textformat="txt"):
        self.SetTextFormat(textformat)
        self.SetThXsec(68.9)
        self.SetLumi(Lumi)
        self.SetLumiUnc(0.035)  # Relative
        self.SetChan(chan)
        self.SetLevel(lev)
        self.SetGenEvents(genEvents)
        self.SetFiduEvents(fiduEvents)
        self.SetBR((0.108 * 3) * (0.108 * 3))  # By default, tt dilepton
        self.bkg = []  # List of 'Process'
        self.data = 0  # This is just an integer
        self.signal = ''  # Process
        self.accUnc = {}  # 'Name' : value
        self.effUnc = {}  # 'Name' : value
        self.SetOutPath(outpath)
        self.doFiducial = True
        self.SetMotherName("TT_TuneCP5_5p02TeV")
        self.SetPathToTrees("")
Exemple #6
0
class NonpromptDD:

    ### Set methods
    def SetPath(self, p):
        if not p.endswith('/'): p += '/'
        self.path = p

    def SetOutPath(self, p):
        self.outpath = p

    def SetLumi(self, l):
        self.lumi = l
        self.t.SetLumi(self.lumi)

    def SetChannel(self, c):
        self.chan = c

    def SetLevel(self, l):
        self.level = l

    def SetChanAndLevel(self, chan='', level=''):
        ''' Manages to set chan and leve to the class and the TopHistoReader '''
        if chan != '': self.SetChannel(chan)
        if level != '': self.SetLevel(level)
        self.t.SetChan(self.GetChan())
        self.t.SetLevel(self.GetLevel())
        return self.GetChan(), self.GetLevel()

    ### Get methods
    def GetPath(self):
        return self.path

    def GetOutPath(self):
        return self.outpath

    def GetLevel(self):
        return self.level

    def GetChan(self):
        return self.chan

    ### Calculate quantities...

    def GetYield(self, process, chan='', level='', SS=False):
        if process == 'Data' or process == 'data': self.t.SetIsData(True)
        if process in self.process.keys(): process = self.process[process]
        chan, lev = self.SetChanAndLevel(chan, level)
        y = self.t.GetYield(process, chan, level, SS=SS)
        err = self.t.GetYieldStatUnc(process, chan, level, SS=SS)
        self.t.SetIsData(False)
        if y < 0:  # Negative weights...
            y = 0
            err = 0
        return y, err

    def GetSS(self, process, chan='', level=''):
        return self.GetYield(process, chan, level, True)

    def GetROSSS(self, process, chan='', level=''):
        ''' Returns the OS to SS ratio for process '''
        OS, OSe = self.GetYield(process, chan, level)
        SS, SSe = self.GetSS(process, chan, level)
        R = OS / SS if SS != 0 else 1
        e = R * SumSquare(
            [OSe / OS if OS != 0 else 0, SSe / SS if SS != 0 else 0])
        return R, e

    def GetNonpromptDD(self, chan='', level=''):
        chan, lev = self.SetChanAndLevel(chan, level)
        R, Re = self.GetROSSS(
            [self.process[lab] for lab in self.nonpromptProcess])
        BkgSS, BkgSSe = self.GetSS(
            [self.process[lab] for lab in self.promptProcess])
        DataSS, DataSSe = self.GetSS('data')
        y = R * (DataSS - BkgSS)
        e = y * SumSquare([
            Re / R if R != 0 else 0, (DataSSe + BkgSSe) / (DataSS - BkgSS) if
            (DataSS - BkgSS != 0) else 0
        ])
        return y, e

    ## Print tables
    def PrintSSyields(self, name='', level=''):
        self.SetChanAndLevel('', level)
        if name == '': name = 'SameSign_%s' % (self.GetLevel())
        t = OutText(self.GetOutPath(), name)
        t.SetSeparatorLength(12 + (3 + 16) * 3)
        t.SetDefaultFixOption(False)
        t.line('Same-sign yields for level of selection \'%s\'' %
               (self.GetLevel()))
        t.bar()
        s = lambda tit, vee, vmm, vem: t.line(
            t.fix(tit, 10) + t.vsep() + t.fix(vee, 16, 'c') + t.vsep() + t.fix(
                vmm, 16, 'c') + t.vsep() + t.fix(vem, 16, 'c'))
        v = lambda L: '%1.2f' % L[0] + t.pm() + '%1.2f' % L[1]
        d = lambda L: '%1.0f' % L[0] + t.pm() + '%1.2f' % L[1]
        S = lambda tit, pr: s(tit, v(self.GetSS(pr, elecName)),
                              v(self.GetSS(pr, muName)),
                              v(self.GetSS(pr, 'ElMu')))
        D = lambda tit, pr: s(tit, d(self.GetSS(pr, elecName)),
                              d(self.GetSS(pr, muName)),
                              d(self.GetSS(pr, 'ElMu')))
        s('', elecName, muName, 'ElMu')
        t.sep()
        for pr in self.promptProcess:
            S(pr, pr)
        #S('tt signal', 'tt')
        #S('tW','tW')
        #S('Drell-Yan','DY')
        #S('Dibosons','VV')
        t.sep()
        for pr in self.nonpromptProcess:
            S(pr, pr)
        #S('W+Jets', 'WJets')
        #S('tt semilep', 'ttsemilep')
        t.sep()
        S('Total MC', [
            self.process[lab]
            for lab in self.promptProcess + self.nonpromptProcess
        ])
        t.sep()
        D('Data', 'data')
        t.bar()
        t.write()

    def PrintNonpromptEstimate(self, name='', chan='', level=''):
        chan, lev = self.SetChanAndLevel(chan, level)
        if name == '':
            name = 'NonpromptDD_%s_%s' % (self.GetChan(), self.GetLevel())
        t = OutText(self.GetOutPath(), name)
        t.SetSeparatorLength(55 + 20)
        t.SetDefaultFixOption(False)
        t.line(
            ' Nonpromt estimate from a same-sign control retion\nfor channel \'%s\' and level of selection \'%s\''
            % (chan, lev))
        t.bar()
        s = lambda tit, vee, vmm, vem: t.line(
            t.fix(tit, 10) + t.vsep() + t.fix(vee, 16, 'c') + t.vsep() + t.fix(
                vmm, 16, 'c') + t.vsep() + t.fix(vem, 16, 'c'))
        v = lambda L: '%1.2f' % L[0] + t.pm() + '%1.2f' % L[1]
        d = lambda L: '%1.0f' % L[0] + t.pm() + '%1.2f' % L[1]
        pr = [self.process[p] for p in self.nonpromptProcess]
        sr = [self.process[p] for p in self.promptProcess]
        t.line(
            t.fix(' MC nonprompt estimate (OS W+Jets and semilpetonic tt)', 55)
            + t.vsep() + v(self.GetYield(pr)))
        t.sep()
        t.line(
            t.fix(' MC nonprompt SS (W+Jets and semilpetonic tt)', 55) +
            t.vsep() + v(self.GetSS(pr)))
        t.line(
            t.fix(' R = nonpromt(OS)/nonprompt(SS)', 55) + t.vsep() +
            v(self.GetROSSS(pr)))
        t.line(
            t.fix(' BkgSS = MC prompt SS (other sources)', 55) + t.vsep() +
            v(self.GetSS(sr)))
        t.line(
            t.fix(' DataSS = Obseved data SS', 55) + t.vsep() +
            v(self.GetSS('data')))
        t.sep()
        t.line(
            t.fix(' Nonprompt data-driven estimate = R(DataSS-BkgSS)', 55) +
            t.vsep() + v(self.GetNonpromptDD()))
        t.bar()
        t.write()

    ### Init
    def __init__(self,
                 path,
                 outpath='./temp/',
                 chan='ElMu',
                 level='2jets',
                 process={},
                 prompt=[],
                 nonprompt=[],
                 lumi=304.32,
                 histonameprefix='H',
                 yieldsSSname='SSYields'):
        self.SetPath(path)
        self.t = TopHistoReader(self.GetPath())
        self.t.SetHistoNamePrefix(histonameprefix)
        self.t.SetYieldsSSname(yieldsSSname)
        self.SetLumi(lumi)
        self.SetOutPath(outpath)
        self.SetChanAndLevel(chan, level)
        self.process = process
        self.nonpromptProcess = []
        self.promptProcess = []
        if prompt == [] or nonprompt == []:
            for pr in process.keys():
                if pr in ['data', 'Data', 'DATA']: continue
                elif pr in [
                        'fake', 'nonprompt', 'Nonprompt', 'NonPrompt', 'Fake',
                        'fakes', 'Fakes'
                ]:
                    self.nonpromptProcess.append(pr)
                else:
                    self.promptProcess.append(pr)
        else:
            self.promptProcess = prompt
            self.nonpromptProcess = nonprompt