def init(self):
        self.hist = {}
        self.hist["numGenTracks"] = ROOT.TH1F("numGenTracks", "numGenTracks",
                                              100, -0.5, 99.5)

        # EX3
        self.hist["numVtx"] = ROOT.TH1F("numVtx", "numVtx", 5, -0.5, 4.5)
        self.hist["jetPT"] = ROOT.TH1F("jetPT", "jetPT", 100, 0, 100)

        # EX9
        self.hist["jetBelowEta3PT"] = ROOT.TH1F("jetBelowEta3PT",
                                                "jetBelowEta3PT", 100, 0, 100)
        self.hist["jetBelowEta3Eta"] = ROOT.TH1F("jetBelowEta3Eta",
                                                 "jetBelowEta3Eta", 100, -5, 5)
        for h in self.hist:
            self.hist[h].Sumw2()
            self.GetOutputList().Add(self.hist[h])

        # EX 8.0
        self.jetGetter = BetterJetGetter("PFAK5")
    def init( self):
        self.hist = {}
        self.hist["numGenTracks"] =  ROOT.TH1F("numGenTracks",   "numGenTracks",  100, -0.5, 99.5)

        # EX3
        self.hist["numVtx"] =  ROOT.TH1F("numVtx",   "numVtx",  5, -0.5, 4.5)
        self.hist["jetPT"] =  ROOT.TH1F("jetPT",   "jetPT",  100, 0, 100)

        # EX9 
        self.hist["jetBelowEta3PT"] =  ROOT.TH1F("jetBelowEta3PT", "jetBelowEta3PT",  100, 0, 100)
        self.hist["jetBelowEta3Eta"] =  ROOT.TH1F("jetBelowEta3Eta",   "jetBelowEta3Eta" ,  100, -5, 5)
        for h in self.hist:
            self.hist[h].Sumw2()
            self.GetOutputList().Add(self.hist[h])

        # EX 8.0
        self.jetGetter = BetterJetGetter("PFAK5") 
class SingleJet(CommonFSQFramework.Core.ExampleProofReader.ExampleProofReader):
    def init( self):
        self.hist = {}
        self.hist["numGenTracks"] =  ROOT.TH1F("numGenTracks",   "numGenTracks",  100, -0.5, 99.5)

        # EX3
        self.hist["numVtx"] =  ROOT.TH1F("numVtx",   "numVtx",  5, -0.5, 4.5)
        self.hist["jetPT"] =  ROOT.TH1F("jetPT",   "jetPT",  100, 0, 100)

        # EX9 
        self.hist["jetBelowEta3PT"] =  ROOT.TH1F("jetBelowEta3PT", "jetBelowEta3PT",  100, 0, 100)
        self.hist["jetBelowEta3Eta"] =  ROOT.TH1F("jetBelowEta3Eta",   "jetBelowEta3Eta" ,  100, -5, 5)
        for h in self.hist:
            self.hist[h].Sumw2()
            self.GetOutputList().Add(self.hist[h])

        # EX 8.0
        self.jetGetter = BetterJetGetter("PFAK5") 

    def analyze(self):
        # ex 4.5
        if self.isData and self.fChain.jet15 < 0.5:
            return 

        weight = 1.
        # EX 6.
        if not self.isData:
            weight *= self.fChain.genWeight

        num = 0

        # genTracks
        #num = self.fChain.genTracks.size()
        #print num
        #print self.maxEta # see slaveParams below
        self.hist["numGenTracks"].Fill(num, weight)

        # EX2.0
        #print "vtx", self.fChain.ngoodVTX

        # EX3.0
        self.hist["numVtx"].Fill(self.fChain.ngoodVTX, weight)

        # EX5.0
        for i in xrange(self.fChain.PFAK5pt.size()):
            pt = self.fChain.PFAK5pt.at(i)
            if pt < 35: continue
            self.hist["jetPT"].Fill(pt, weight)

        # EX 8.0
        self.jetGetter.newEvent(self.fChain)
        #print "New event!"
        for j in self.jetGetter.get("_central"):
             if j.pt()<35.: continue
             #print "A jet: ", j.pt(), j.eta()


        # EX 9.0
        for j in self.jetGetter.get("_central"):
             if j.pt()<35.: continue
             if abs(j.eta())>3.: continue
             self.hist["jetBelowEta3Eta"].Fill(j.eta(), weight)
             self.hist["jetBelowEta3PT"].Fill(j.pt(), weight)


        return 1

    def finalize(self):
        print "Finalize:"
        normFactor = self.getNormalizationFactor()
        # exercise A.2
        #  this is the lumi for jet15 trigger in JetMETtau
        if self.isData:
            print "Expected norm factor is 1. Got", normFactor
            print "Changeing norm factor to have properly normalized data histo"
            normFactor = 1/0.013781

        print "  applying norm", normFactor
        for h in self.hist:
            self.hist[h].Scale(normFactor)
    def __init__(self, triggerName, period=None, weight=False):

        if period == None:
            runMin = 0
            runMax = 9999999
        elif period == "A":
            runMin = 0
            runMax = 146219
        elif period == "B":
            runMin = 146240
            runMax = 9999999
        elif isinstance(period, (int, long)):
            runMin = period
            runMax = period
        else:
            print "HLTMCWeighter: Period not known:", period
            sys.exit()

        self.label = triggerName

        shortName = triggerName.replace("HLT_", "")
        shortName1 = shortName
        shortName2 = shortName
        if "_raw" in shortName:
            shortName2 = shortName2.replace("_raw", "")
            self.getter = BetterJetGetter("CaloRaw")
        else:
            self.getter = BetterJetGetter("Calo")

        self.l1seeding = False
        if "_L1Seeding" in shortName:
            self.l1seeding = True
            shortName2 = shortName2.replace("_L1Seeding", "")

        self.etaRangeLowForMax = 3.0  # dj fb
        self.etaRangeHighForMax = 5.1
        self.fb = True

        if shortName2 == "Jet15U":
            self.fb = False
            self.etaRangeLowForMax = -1.0
            self.etaRangeHighForMax = 5.1

        # hltEffHistos.root  prescales_Jet15U.p
        # CommonFSQFramework.Core/test/MNxsectionAna/trgEfficiency
        fPrescales = edm.FileInPath(
            "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/prescales_"
            + shortName2 + ".p").fullPath()
        prescales = pickle.load(open(fPrescales, "rb"))

        fLumi = edm.FileInPath(
            "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/runLumi_"
            + shortName2 + ".p").fullPath()
        runLumi = pickle.load(open(fLumi, "rb"))

        # hltEffHistos_DoubleJet15U_ForwardBackward.root  hltEffHistos_Jet15U.root

        fName = "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/hltEffHistos_" + shortName1 + ".root"
        print self.label, "- using", fName
        filePath = edm.FileInPath(fName).fullPath()
        curPath = ROOT.gDirectory.GetPath()
        rootFileTF = ROOT.TFile(filePath, "READ")
        lst = rootFileTF.GetListOfKeys()
        # nom_142304
        h = {}
        h["nom"] = None
        h["denom"] = None
        denom = None
        self.runs = set()
        binx = 38
        biny = 4
        sumNom = 0

        for l in lst:
            current = l.ReadObj()
            name = current.GetName()
            if not "nom_" in name: continue
            spl = name.split("_")
            hType = spl[0]
            run = int(spl[1])
            if run < runMin or run > runMax: continue
            self.runs.add(run)

            if weight:
                if run not in prescales:
                    print "HLTMCWeighter: run not found", run
                    continue
                if len(prescales[run]) == 0:
                    print "HLTMCWeighter: run found but empty", run
                    continue
                prescale = iter(prescales[run]).next()
                if run not in runLumi:
                    print "Lumi missing:", run
                    lumi = 0
                else:
                    lumi = runLumi[run][0]

                factor = lumi / prescale
            else:
                factor = 1
            if hType == "nom":
                a = 1
                sumNom += current.GetBinContent(binx, biny)

            if h[hType] == None:
                #print "Clone"
                h[hType] = current.Clone("clone_" + str(hType) + str(run))
                h[hType].Scale(factor)
            else:
                h[hType].Add(current, factor)

            #print "TTT", hType, h[hType].GetName(), h[hType].Integral()

        binx = h["nom"].GetXaxis().FindBin(50)
        biny = h["nom"].GetYaxis().FindBin(1)
        #print binx, biny
        nnom = h["nom"].GetBinContent(binx, biny)
        ndenom = h["denom"].GetBinContent(binx, biny)
        r = -1
        if ndenom != 0:
            r = float(nnom) / ndenom
        if ndenom < nnom: print "asdfa", period
        #print r, period,"|", nnom, ndenom

        #print sumNom

        nom = h["nom"].Clone()
        #nom.Scale(1000)
        denom = h["denom"].Clone()

        h["nom"].Divide(h["denom"])

        #  the histogram is associated with a currently open rootfile (which soon will be closed). A clone is needed in root main dir
        ROOT.gDirectory.cd(curPath)
        self.efficiencyHisto = h["nom"].Clone()
        self.nom = nom.Clone("nomAA")
        self.denom = denom.Clone("denomAA")
class HLTMCWeighter:

    # https://wiki.physik.uzh.ch/lhcb/root:colorscheme
    def set_palette(name="palette", ncontours=999):

        if name == "gray" or name == "grayscale":
            stops = [0.00, 0.34, 0.61, 0.84, 1.001]
            #stops = [0.00, 340, 611, 840, 1000]
            red = [1.00, 0.84, 0.61, 0.34, 0.00]
            green = [1.00, 0.84, 0.61, 0.34, 0.00]
            blue = [1.00, 0.84, 0.61, 0.34, 0.00]
        # elif name == "whatever":
        # (define more palettes)
        else:
            # default palette, looks cool
            stops = [0.00, 0.34, 0.61, 0.84, 1.00]
            red = [0.00, 0.00, 0.87, 1.00, 0.51]
            green = [0.00, 0.81, 1.00, 0.20, 0.00]
            blue = [0.51, 1.00, 0.12, 0.00, 0.00]

        s = array('d', stops)
        r = array('d', red)
        g = array('d', green)
        b = array('d', blue)

        npoints = len(s)
        TColor.CreateGradientColorTable(npoints, s, r, g, b, ncontours)
        gStyle.SetNumberContours(ncontours)

    def __init__(self, triggerName, period=None, weight=False):

        if period == None:
            runMin = 0
            runMax = 9999999
        elif period == "A":
            runMin = 0
            runMax = 146219
        elif period == "B":
            runMin = 146240
            runMax = 9999999
        elif isinstance(period, (int, long)):
            runMin = period
            runMax = period
        else:
            print "HLTMCWeighter: Period not known:", period
            sys.exit()

        self.label = triggerName

        shortName = triggerName.replace("HLT_", "")
        shortName1 = shortName
        shortName2 = shortName
        if "_raw" in shortName:
            shortName2 = shortName2.replace("_raw", "")
            self.getter = BetterJetGetter("CaloRaw")
        else:
            self.getter = BetterJetGetter("Calo")

        self.l1seeding = False
        if "_L1Seeding" in shortName:
            self.l1seeding = True
            shortName2 = shortName2.replace("_L1Seeding", "")

        self.etaRangeLowForMax = 3.0  # dj fb
        self.etaRangeHighForMax = 5.1
        self.fb = True

        if shortName2 == "Jet15U":
            self.fb = False
            self.etaRangeLowForMax = -1.0
            self.etaRangeHighForMax = 5.1

        # hltEffHistos.root  prescales_Jet15U.p
        # CommonFSQFramework.Core/test/MNxsectionAna/trgEfficiency
        fPrescales = edm.FileInPath(
            "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/prescales_"
            + shortName2 + ".p").fullPath()
        prescales = pickle.load(open(fPrescales, "rb"))

        fLumi = edm.FileInPath(
            "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/runLumi_"
            + shortName2 + ".p").fullPath()
        runLumi = pickle.load(open(fLumi, "rb"))

        # hltEffHistos_DoubleJet15U_ForwardBackward.root  hltEffHistos_Jet15U.root

        fName = "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/hltEffHistos_" + shortName1 + ".root"
        print self.label, "- using", fName
        filePath = edm.FileInPath(fName).fullPath()
        curPath = ROOT.gDirectory.GetPath()
        rootFileTF = ROOT.TFile(filePath, "READ")
        lst = rootFileTF.GetListOfKeys()
        # nom_142304
        h = {}
        h["nom"] = None
        h["denom"] = None
        denom = None
        self.runs = set()
        binx = 38
        biny = 4
        sumNom = 0

        for l in lst:
            current = l.ReadObj()
            name = current.GetName()
            if not "nom_" in name: continue
            spl = name.split("_")
            hType = spl[0]
            run = int(spl[1])
            if run < runMin or run > runMax: continue
            self.runs.add(run)

            if weight:
                if run not in prescales:
                    print "HLTMCWeighter: run not found", run
                    continue
                if len(prescales[run]) == 0:
                    print "HLTMCWeighter: run found but empty", run
                    continue
                prescale = iter(prescales[run]).next()
                if run not in runLumi:
                    print "Lumi missing:", run
                    lumi = 0
                else:
                    lumi = runLumi[run][0]

                factor = lumi / prescale
            else:
                factor = 1
            if hType == "nom":
                a = 1
                sumNom += current.GetBinContent(binx, biny)

            if h[hType] == None:
                #print "Clone"
                h[hType] = current.Clone("clone_" + str(hType) + str(run))
                h[hType].Scale(factor)
            else:
                h[hType].Add(current, factor)

            #print "TTT", hType, h[hType].GetName(), h[hType].Integral()

        binx = h["nom"].GetXaxis().FindBin(50)
        biny = h["nom"].GetYaxis().FindBin(1)
        #print binx, biny
        nnom = h["nom"].GetBinContent(binx, biny)
        ndenom = h["denom"].GetBinContent(binx, biny)
        r = -1
        if ndenom != 0:
            r = float(nnom) / ndenom
        if ndenom < nnom: print "asdfa", period
        #print r, period,"|", nnom, ndenom

        #print sumNom

        nom = h["nom"].Clone()
        #nom.Scale(1000)
        denom = h["denom"].Clone()

        h["nom"].Divide(h["denom"])

        #  the histogram is associated with a currently open rootfile (which soon will be closed). A clone is needed in root main dir
        ROOT.gDirectory.cd(curPath)
        self.efficiencyHisto = h["nom"].Clone()
        self.nom = nom.Clone("nomAA")
        self.denom = denom.Clone("denomAA")

    # TODO: check limits
    def getEfficiency(self, eta, pt):
        #if self.fb: # temporary, till workaround for HLT_FB logic is implemented
        #    eta = abs(eta)

        binx = self.efficiencyHisto.GetXaxis().FindBin(pt)
        biny = self.efficiencyHisto.GetYaxis().FindBin(eta)
        return self.efficiencyHisto.GetBinContent(binx, biny)

    def setGetter(self, getter):
        self.getter = getter
        self.cached = None
        self.jets = None

    def setJets(self, jets):
        self.cached = None
        self.jets = jets

    def newEvent(self, ev):
        self.cached = None
        self.ev = ev
        self.getter.newEvent(self.ev)
        self.jets = None

    # etaHalf = 0 - both
    # etaHalf = + - positive
    # etaHalf = - - negative
    def getWeight(self, etaHalf=0):
        # in case of etaHalf!=0 execute normally
        # result will be cached in etaHalf==0 case
        if etaHalf == 0 and self.cached != None:
            return self.cached

        if self.jets != None:
            jets = self.jets
        else:
            jets = self.getter.get("_central")
        plus = 0
        minus = 0
        '''
        for j in jets:
            if j.pt() < 35: continue
            if abs(j.eta()) < 3.: continue
            if j.eta() < 0.: minus += 1
            else: plus += 1

        if plus > 0 and minus > 0:
            printD = True
        else:
            printD = False
        '''
        printD = False
        #printD = True

        if printD: print "################################", self.ev.event
        if etaHalf == 0 and self.fb:
            w = self.getWeight(-1) * self.getWeight(1)
            if printD: print "FB weight", w
            return w

        trgFactor = 1.
        #print "#"*10
        for j in jets:
            #eta = abs(j[0].eta())
            eta = j.eta()
            if printD: print j.eta(), j.pt(), etaHalf
            if etaHalf != 0 and self.fb:
                if eta * etaHalf < 0:
                    if printD: print " ---> etaHalf skip"
                    continue

            if abs(eta) > 5.1: continue
            aeta = abs(eta)
            if aeta < self.etaRangeLowForMax or aeta > self.etaRangeHighForMax:
                if printD: print "  ---> print etaRange skip"
                continue
            pt = j.pt()

            w1 = self.getEfficiency(eta, pt)
            if printD: print " --->", w1
            if w1 < 0.01 and pt > 50 and aeta > self.etaRangeLowForMax and aeta < self.etaRangeHighForMax:
                w1 = 1
                if printD: print " Changing w to 1"

            trgFactor *= 1 - w1
            if printD: print " --> factor:", trgFactor

        #print 1.- trgFactor

        ret = 1. - trgFactor
        self.cached = ret
        return ret

    def dumpEfficiencyHisto(self, name=""):
        '''
        binx = self.efficiencyHisto.GetXaxis().FindBin(55)
        for i in xrange(15):
            eta = 4.5 + float(i)/10.
            biny = self.efficiencyHisto.GetYaxis().FindBin(eta)
            w = self.efficiencyHisto.GetBinContent(binx,biny)
            print "a", eta, binx, biny, w
        '''

        #ROOT.gStyle.SetPadTopMargin(0.05)
        ROOT.gStyle.SetPadBottomMargin(0.10)
        ROOT.gStyle.SetPadLeftMargin(0.10)
        ROOT.gStyle.SetPadRightMargin(0.125)

        #ROOT.gStyle.SetPalette(1)
        self.set_palette()
        ROOT.gStyle.SetOptStat(0)
        c = ROOT.TCanvas("cc")
        self.efficiencyHisto.SetXTitle("p_{T}^{raw}")
        self.efficiencyHisto.SetYTitle("#eta_{jet}")
        self.efficiencyHisto.Draw("COLZ")
        c.Print("~/tmp/HLTMCWeighter_" + name + ".png")
        rf = ROOT.TFile("~/tmp/HLTMCWeighter_" + name + ".root", "RECREATE")

        todo = [self.efficiencyHisto, self.nom, self.denom]
        for t in todo:
            t.Write()
    def __init__(self, triggerName, period=None, weight=False):

        if period == None:
            runMin = 0
            runMax = 9999999
        elif period == "A":
            runMin = 0
            runMax = 146219
        elif period == "B":
            runMin = 146240
            runMax = 9999999
        elif isinstance(period, (int, long)):
            runMin = period
            runMax = period
        else:
            print "HLTMCWeighter: Period not known:", period
            sys.exit()

        self.label = triggerName

        shortName = triggerName.replace("HLT_", "")
        shortName1 = shortName
        shortName2 = shortName
        if "_raw" in shortName:
            shortName2 = shortName2.replace("_raw", "")
            self.getter = BetterJetGetter("CaloRaw")
        else:
            self.getter = BetterJetGetter("Calo")

        self.l1seeding = False
        if "_L1Seeding" in shortName:
            self.l1seeding = True
            shortName2 = shortName2.replace("_L1Seeding", "")

        self.etaRangeLowForMax = 3.0  # dj fb
        self.etaRangeHighForMax = 5.1
        self.fb = True

        if shortName2 == "Jet15U":
            self.fb = False
            self.etaRangeLowForMax = -1.0
            self.etaRangeHighForMax = 5.1

        # hltEffHistos.root  prescales_Jet15U.p
        # CommonFSQFramework.Core/test/MNxsectionAna/trgEfficiency
        fPrescales = edm.FileInPath(
            "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/prescales_" + shortName2 + ".p"
        ).fullPath()
        prescales = pickle.load(open(fPrescales, "rb"))

        fLumi = edm.FileInPath(
            "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/runLumi_" + shortName2 + ".p"
        ).fullPath()
        runLumi = pickle.load(open(fLumi, "rb"))

        # hltEffHistos_DoubleJet15U_ForwardBackward.root  hltEffHistos_Jet15U.root

        fName = "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/hltEffHistos_" + shortName1 + ".root"
        print self.label, "- using", fName
        filePath = edm.FileInPath(fName).fullPath()
        curPath = ROOT.gDirectory.GetPath()
        rootFileTF = ROOT.TFile(filePath, "READ")
        lst = rootFileTF.GetListOfKeys()
        # nom_142304
        h = {}
        h["nom"] = None
        h["denom"] = None
        denom = None
        self.runs = set()
        binx = 38
        biny = 4
        sumNom = 0

        for l in lst:
            current = l.ReadObj()
            name = current.GetName()
            if not "nom_" in name:
                continue
            spl = name.split("_")
            hType = spl[0]
            run = int(spl[1])
            if run < runMin or run > runMax:
                continue
            self.runs.add(run)

            if weight:
                if run not in prescales:
                    print "HLTMCWeighter: run not found", run
                    continue
                if len(prescales[run]) == 0:
                    print "HLTMCWeighter: run found but empty", run
                    continue
                prescale = iter(prescales[run]).next()
                if run not in runLumi:
                    print "Lumi missing:", run
                    lumi = 0
                else:
                    lumi = runLumi[run][0]

                factor = lumi / prescale
            else:
                factor = 1
            if hType == "nom":
                a = 1
                sumNom += current.GetBinContent(binx, biny)

            if h[hType] == None:
                # print "Clone"
                h[hType] = current.Clone("clone_" + str(hType) + str(run))
                h[hType].Scale(factor)
            else:
                h[hType].Add(current, factor)

            # print "TTT", hType, h[hType].GetName(), h[hType].Integral()

        binx = h["nom"].GetXaxis().FindBin(50)
        biny = h["nom"].GetYaxis().FindBin(1)
        # print binx, biny
        nnom = h["nom"].GetBinContent(binx, biny)
        ndenom = h["denom"].GetBinContent(binx, biny)
        r = -1
        if ndenom != 0:
            r = float(nnom) / ndenom
        if ndenom < nnom:
            print "asdfa", period
        # print r, period,"|", nnom, ndenom

        # print sumNom

        nom = h["nom"].Clone()
        # nom.Scale(1000)
        denom = h["denom"].Clone()

        h["nom"].Divide(h["denom"])

        #  the histogram is associated with a currently open rootfile (which soon will be closed). A clone is needed in root main dir
        ROOT.gDirectory.cd(curPath)
        self.efficiencyHisto = h["nom"].Clone()
        self.nom = nom.Clone("nomAA")
        self.denom = denom.Clone("denomAA")
class HLTMCWeighter:

    # https://wiki.physik.uzh.ch/lhcb/root:colorscheme
    def set_palette(name="palette", ncontours=999):

        if name == "gray" or name == "grayscale":
            stops = [0.00, 0.34, 0.61, 0.84, 1.001]
            # stops = [0.00, 340, 611, 840, 1000]
            red = [1.00, 0.84, 0.61, 0.34, 0.00]
            green = [1.00, 0.84, 0.61, 0.34, 0.00]
            blue = [1.00, 0.84, 0.61, 0.34, 0.00]
        # elif name == "whatever":
        # (define more palettes)
        else:
            # default palette, looks cool
            stops = [0.00, 0.34, 0.61, 0.84, 1.00]
            red = [0.00, 0.00, 0.87, 1.00, 0.51]
            green = [0.00, 0.81, 1.00, 0.20, 0.00]
            blue = [0.51, 1.00, 0.12, 0.00, 0.00]

        s = array("d", stops)
        r = array("d", red)
        g = array("d", green)
        b = array("d", blue)

        npoints = len(s)
        TColor.CreateGradientColorTable(npoints, s, r, g, b, ncontours)
        gStyle.SetNumberContours(ncontours)

    def __init__(self, triggerName, period=None, weight=False):

        if period == None:
            runMin = 0
            runMax = 9999999
        elif period == "A":
            runMin = 0
            runMax = 146219
        elif period == "B":
            runMin = 146240
            runMax = 9999999
        elif isinstance(period, (int, long)):
            runMin = period
            runMax = period
        else:
            print "HLTMCWeighter: Period not known:", period
            sys.exit()

        self.label = triggerName

        shortName = triggerName.replace("HLT_", "")
        shortName1 = shortName
        shortName2 = shortName
        if "_raw" in shortName:
            shortName2 = shortName2.replace("_raw", "")
            self.getter = BetterJetGetter("CaloRaw")
        else:
            self.getter = BetterJetGetter("Calo")

        self.l1seeding = False
        if "_L1Seeding" in shortName:
            self.l1seeding = True
            shortName2 = shortName2.replace("_L1Seeding", "")

        self.etaRangeLowForMax = 3.0  # dj fb
        self.etaRangeHighForMax = 5.1
        self.fb = True

        if shortName2 == "Jet15U":
            self.fb = False
            self.etaRangeLowForMax = -1.0
            self.etaRangeHighForMax = 5.1

        # hltEffHistos.root  prescales_Jet15U.p
        # CommonFSQFramework.Core/test/MNxsectionAna/trgEfficiency
        fPrescales = edm.FileInPath(
            "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/prescales_" + shortName2 + ".p"
        ).fullPath()
        prescales = pickle.load(open(fPrescales, "rb"))

        fLumi = edm.FileInPath(
            "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/runLumi_" + shortName2 + ".p"
        ).fullPath()
        runLumi = pickle.load(open(fLumi, "rb"))

        # hltEffHistos_DoubleJet15U_ForwardBackward.root  hltEffHistos_Jet15U.root

        fName = "CommonFSQFramework/Core/test/MNxsectionAna/trgEfficiency/hltEffHistos_" + shortName1 + ".root"
        print self.label, "- using", fName
        filePath = edm.FileInPath(fName).fullPath()
        curPath = ROOT.gDirectory.GetPath()
        rootFileTF = ROOT.TFile(filePath, "READ")
        lst = rootFileTF.GetListOfKeys()
        # nom_142304
        h = {}
        h["nom"] = None
        h["denom"] = None
        denom = None
        self.runs = set()
        binx = 38
        biny = 4
        sumNom = 0

        for l in lst:
            current = l.ReadObj()
            name = current.GetName()
            if not "nom_" in name:
                continue
            spl = name.split("_")
            hType = spl[0]
            run = int(spl[1])
            if run < runMin or run > runMax:
                continue
            self.runs.add(run)

            if weight:
                if run not in prescales:
                    print "HLTMCWeighter: run not found", run
                    continue
                if len(prescales[run]) == 0:
                    print "HLTMCWeighter: run found but empty", run
                    continue
                prescale = iter(prescales[run]).next()
                if run not in runLumi:
                    print "Lumi missing:", run
                    lumi = 0
                else:
                    lumi = runLumi[run][0]

                factor = lumi / prescale
            else:
                factor = 1
            if hType == "nom":
                a = 1
                sumNom += current.GetBinContent(binx, biny)

            if h[hType] == None:
                # print "Clone"
                h[hType] = current.Clone("clone_" + str(hType) + str(run))
                h[hType].Scale(factor)
            else:
                h[hType].Add(current, factor)

            # print "TTT", hType, h[hType].GetName(), h[hType].Integral()

        binx = h["nom"].GetXaxis().FindBin(50)
        biny = h["nom"].GetYaxis().FindBin(1)
        # print binx, biny
        nnom = h["nom"].GetBinContent(binx, biny)
        ndenom = h["denom"].GetBinContent(binx, biny)
        r = -1
        if ndenom != 0:
            r = float(nnom) / ndenom
        if ndenom < nnom:
            print "asdfa", period
        # print r, period,"|", nnom, ndenom

        # print sumNom

        nom = h["nom"].Clone()
        # nom.Scale(1000)
        denom = h["denom"].Clone()

        h["nom"].Divide(h["denom"])

        #  the histogram is associated with a currently open rootfile (which soon will be closed). A clone is needed in root main dir
        ROOT.gDirectory.cd(curPath)
        self.efficiencyHisto = h["nom"].Clone()
        self.nom = nom.Clone("nomAA")
        self.denom = denom.Clone("denomAA")

    # TODO: check limits
    def getEfficiency(self, eta, pt):
        # if self.fb: # temporary, till workaround for HLT_FB logic is implemented
        #    eta = abs(eta)

        binx = self.efficiencyHisto.GetXaxis().FindBin(pt)
        biny = self.efficiencyHisto.GetYaxis().FindBin(eta)
        return self.efficiencyHisto.GetBinContent(binx, biny)

    def setGetter(self, getter):
        self.getter = getter
        self.cached = None
        self.jets = None

    def setJets(self, jets):
        self.cached = None
        self.jets = jets

    def newEvent(self, ev):
        self.cached = None
        self.ev = ev
        self.getter.newEvent(self.ev)
        self.jets = None

    # etaHalf = 0 - both
    # etaHalf = + - positive
    # etaHalf = - - negative
    def getWeight(self, etaHalf=0):
        # in case of etaHalf!=0 execute normally
        # result will be cached in etaHalf==0 case
        if etaHalf == 0 and self.cached != None:
            return self.cached

        if self.jets != None:
            jets = self.jets
        else:
            jets = self.getter.get("_central")
        plus = 0
        minus = 0
        """
        for j in jets:
            if j.pt() < 35: continue
            if abs(j.eta()) < 3.: continue
            if j.eta() < 0.: minus += 1
            else: plus += 1

        if plus > 0 and minus > 0:
            printD = True
        else:
            printD = False
        """
        printD = False
        # printD = True

        if printD:
            print "################################", self.ev.event
        if etaHalf == 0 and self.fb:
            w = self.getWeight(-1) * self.getWeight(1)
            if printD:
                print "FB weight", w
            return w

        trgFactor = 1.0
        # print "#"*10
        for j in jets:
            # eta = abs(j[0].eta())
            eta = j.eta()
            if printD:
                print j.eta(), j.pt(), etaHalf
            if etaHalf != 0 and self.fb:
                if eta * etaHalf < 0:
                    if printD:
                        print " ---> etaHalf skip"
                    continue

            if abs(eta) > 5.1:
                continue
            aeta = abs(eta)
            if aeta < self.etaRangeLowForMax or aeta > self.etaRangeHighForMax:
                if printD:
                    print "  ---> print etaRange skip"
                continue
            pt = j.pt()

            w1 = self.getEfficiency(eta, pt)
            if printD:
                print " --->", w1
            if w1 < 0.01 and pt > 50 and aeta > self.etaRangeLowForMax and aeta < self.etaRangeHighForMax:
                w1 = 1
                if printD:
                    print " Changing w to 1"

            trgFactor *= 1 - w1
            if printD:
                print " --> factor:", trgFactor

        # print 1.- trgFactor

        ret = 1.0 - trgFactor
        self.cached = ret
        return ret

    def dumpEfficiencyHisto(self, name=""):
        """
        binx = self.efficiencyHisto.GetXaxis().FindBin(55)
        for i in xrange(15):
            eta = 4.5 + float(i)/10.
            biny = self.efficiencyHisto.GetYaxis().FindBin(eta)
            w = self.efficiencyHisto.GetBinContent(binx,biny)
            print "a", eta, binx, biny, w
        """

        # ROOT.gStyle.SetPadTopMargin(0.05)
        ROOT.gStyle.SetPadBottomMargin(0.10)
        ROOT.gStyle.SetPadLeftMargin(0.10)
        ROOT.gStyle.SetPadRightMargin(0.125)

        # ROOT.gStyle.SetPalette(1)
        self.set_palette()
        ROOT.gStyle.SetOptStat(0)
        c = ROOT.TCanvas("cc")
        self.efficiencyHisto.SetXTitle("p_{T}^{raw}")
        self.efficiencyHisto.SetYTitle("#eta_{jet}")
        self.efficiencyHisto.Draw("COLZ")
        c.Print("~/tmp/HLTMCWeighter_" + name + ".png")
        rf = ROOT.TFile("~/tmp/HLTMCWeighter_" + name + ".root", "RECREATE")

        todo = [self.efficiencyHisto, self.nom, self.denom]
        for t in todo:
            t.Write()
    def init( self):

        self.variantFilter = BaseDijetAna.variant(self.variant)

        if not self.isData:
            #self.hltMCWeighter = HLTMCWeighter("HLT_Jet15U")
            self.HLTMCWeighterJ15Raw = HLTMCWeighter("HLT_Jet15U_raw")
            self.HLTMCWeighterJ15L1Raw = HLTMCWeighter("HLT_Jet15U_L1Seeding_raw")
            self.HLTMCWeighterJ15FBL1Raw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_L1Seeding_raw")
            self.HLTMCWeighterJ15FBRaw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_raw")

        self.normFactor = self.getNormalizationFactor()

        #sys.stdout = sys.stderr
        #self.pr = cProfile.Profile()
        print "XXX init - MNxsAnalyzerClean", self.datasetName, self.isData

        self.todoShifts = ["_central"]
        if not self.isData and self.doPtShiftsJEC:
            self.todoShifts.append("_jecUp")
            self.todoShifts.append("_jecDown")

        if not self.isData and self.doPtShiftsJER:
            self.todoShifts.append("_jerUp")
            self.todoShifts.append("_jerDown")

        # since shifts for PU are in fact changes in weight
        # there is no sense to repeat whole analaysis
        # we will use the central value
        self.shiftsPU = ["_central"]
        if not self.isData and self.doShiftsPU:
            self.shiftsPU.append("_puUp")
            self.shiftsPU.append("_puDown")

        self.hist = {}
        todoTrg = ["_jet15", "_dj15fb"]

        binsNew = self.variantFilter.bins()

        # note: set gives as unique items, since _central is repeated
        self.hist["ptHat"] = ROOT.TH1F("ptHat",   "ptHat",  100, 0, 50)

        for shift in set(self.todoShifts+self.shiftsPU):
            for trg in todoTrg:
                t = shift+trg
                self.hist["ptLead"+t] =  ROOT.TH1F("ptLead"+t,   "ptLead"+t,  100, 0, 100)
                self.hist["ptSublead"+t] =  ROOT.TH1F("ptSublead"+t,   "ptSublead"+t,  100, 0, 100)
                self.hist["etaLead"+t] =  ROOT.TH1F("etaLead"+t,   "etaLead"+t,  100, -5, 5)
                self.hist["etaSublead"+t] =  ROOT.TH1F("etaSublead"+t,   "etaSublead"+t,  100, -5, 5)
                self.hist["xsVsDeltaEta"+t] =  ROOT.TH1F("xs"+t,   "xs"+t, len(binsNew)-1, binsNew)
                self.hist["miss"+t] = self.hist["xsVsDeltaEta"+t].Clone("miss"+t)

                self.hist["vtx"+t] =  ROOT.TH1F("vtx"+t,   "vtx"+t,  10, -0.5, 9.5)

                if self.unfoldEnabled:
                    dummy = ROOT.TH2F("dummy"+t, "dummy"+t, len(binsNew)-1, binsNew, len(binsNew)-1, binsNew)
                    self.hist["response"+t]= ROOT.RooUnfoldResponse(self.hist["xsVsDeltaEta"+t], 
                                                                    self.hist["xsVsDeltaEta"+t], 
                                                                    dummy,
                                                                    "response"+t,"response"+t)


        # in principle trigger does not applies to gen plots. We keep consistent naming though, so the unfolded result to gen level plots is possible
        # in each category
        self.hist["detaGen_jet15"] =  ROOT.TH1F("detaGen_central_jet15", "detaGen_central_jet15",
                                                len(binsNew)-1, binsNew)
        self.hist["detaGen_dj15fb"] =  ROOT.TH1F("detaGen_central_dj15fb", "detaGen_central_dj15fb",  
                                                len(binsNew)-1, binsNew)


        if self.onlyPtHatReweighing:
            self.var = {}
            self.var["leadPt"] = array('d', [0])
            self.var["leadEta"] = array('d', [0])
            self.var["weight"] = array('d', [0]) # only jet15 trigger??
            #self.var["alphaQCD"] = array('d', [0])
            self.var["qScale"]   = array('d', [0])
            self.tree = ROOT.TTree("data", "data")
            for v in self.var:
                self.tree.Branch(v, self.var[v], v+"/D")
            self.addToOutput(self.tree)

        else:
            for h in self.hist:
                if not h.startswith("response"):
                    self.hist[h].Sumw2()
                #self.GetOutputList().Add(self.hist[h])
                self.addToOutput(self.hist[h])

        if self.applyPtHatReweighing and not self.isData:
                fp = "CommonFSQFramework/Core/test/MNxsectionAna/"
                todo = ["ptHatWeighters.root"]
                self.ptHatW = []
                for t in todo:
                    ptHatFileName = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/"+t).fullPath()
                    ptHatFile = ROOT.TFile(ptHatFileName)
                    self.ptHatW.append(ptHatFile.Get(self.datasetName+"/ptHatW"))




        puFiles = {}
        # CommonFSQFramework.Core/test/MNxsectionAna/
        jet15FileV2 = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/PUJet15V2.root").fullPath()   # MC gen distribution

        puFiles["dj15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_0.root").fullPath()
        puFiles["dj15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_05.root").fullPath()
        puFiles["dj15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_0_95.root").fullPath()
        puFiles["j15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_0.root").fullPath()
        puFiles["j15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_05.root").fullPath()
        puFiles["j15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_0_95.root").fullPath()

        self.lumiWeighters = {}
        self.lumiWeighters["_jet15_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1"], "MC", "pileup")
        self.lumiWeighters["_jet15_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1_05"], "MC", "pileup")
        self.lumiWeighters["_jet15_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_0_95"], "MC", "pileup")

        self.lumiWeighters["_dj15fb_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1_05"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_0_95"], "MC", "pileup")

        self.jetGetter = BetterJetGetter("PFAK5") 
        self.getterForTriggerModelling = BetterJetGetter("CaloRaw")
class SingleJet(CommonFSQFramework.Core.ExampleProofReader.ExampleProofReader):
    def init(self):
        self.hist = {}
        self.hist["numGenTracks"] = ROOT.TH1F("numGenTracks", "numGenTracks",
                                              100, -0.5, 99.5)

        # EX3
        self.hist["numVtx"] = ROOT.TH1F("numVtx", "numVtx", 5, -0.5, 4.5)
        self.hist["jetPT"] = ROOT.TH1F("jetPT", "jetPT", 100, 0, 100)

        # EX9
        self.hist["jetBelowEta3PT"] = ROOT.TH1F("jetBelowEta3PT",
                                                "jetBelowEta3PT", 100, 0, 100)
        self.hist["jetBelowEta3Eta"] = ROOT.TH1F("jetBelowEta3Eta",
                                                 "jetBelowEta3Eta", 100, -5, 5)
        for h in self.hist:
            self.hist[h].Sumw2()
            self.GetOutputList().Add(self.hist[h])

        # EX 8.0
        self.jetGetter = BetterJetGetter("PFAK5")

    def analyze(self):
        # ex 4.5
        if self.isData and self.fChain.jet15 < 0.5:
            return

        weight = 1.
        # EX 6.
        if not self.isData:
            weight *= self.fChain.genWeight

        num = 0

        # genTracks
        #num = self.fChain.genTracks.size()
        #print num
        #print self.maxEta # see slaveParams below
        self.hist["numGenTracks"].Fill(num, weight)

        # EX2.0
        #print "vtx", self.fChain.ngoodVTX

        # EX3.0
        self.hist["numVtx"].Fill(self.fChain.ngoodVTX, weight)

        # EX5.0
        for i in xrange(self.fChain.PFAK5pt.size()):
            pt = self.fChain.PFAK5pt.at(i)
            if pt < 35: continue
            self.hist["jetPT"].Fill(pt, weight)

        # EX 8.0
        self.jetGetter.newEvent(self.fChain)
        #print "New event!"
        for j in self.jetGetter.get("_central"):
            if j.pt() < 35.: continue
            #print "A jet: ", j.pt(), j.eta()

        # EX 9.0
        for j in self.jetGetter.get("_central"):
            if j.pt() < 35.: continue
            if abs(j.eta()) > 3.: continue
            self.hist["jetBelowEta3Eta"].Fill(j.eta(), weight)
            self.hist["jetBelowEta3PT"].Fill(j.pt(), weight)

        return 1

    def finalize(self):
        print "Finalize:"
        normFactor = self.getNormalizationFactor()
        # exercise A.2
        #  this is the lumi for jet15 trigger in JetMETtau
        if self.isData:
            print "Expected norm factor is 1. Got", normFactor
            print "Changeing norm factor to have properly normalized data histo"
            normFactor = 1 / 0.013781

        print "  applying norm", normFactor
        for h in self.hist:
            self.hist[h].Scale(normFactor)
class MNxsAnalyzerClean(CommonFSQFramework.Core.ExampleProofReader.ExampleProofReader):
    def init( self):

        self.variantFilter = BaseDijetAna.variant(self.variant)

        if not self.isData:
            #self.hltMCWeighter = HLTMCWeighter("HLT_Jet15U")
            self.HLTMCWeighterJ15Raw = HLTMCWeighter("HLT_Jet15U_raw")
            self.HLTMCWeighterJ15L1Raw = HLTMCWeighter("HLT_Jet15U_L1Seeding_raw")
            self.HLTMCWeighterJ15FBL1Raw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_L1Seeding_raw")
            self.HLTMCWeighterJ15FBRaw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_raw")

        self.normFactor = self.getNormalizationFactor()

        #sys.stdout = sys.stderr
        #self.pr = cProfile.Profile()
        print "XXX init - MNxsAnalyzerClean", self.datasetName, self.isData

        self.todoShifts = ["_central"]
        if not self.isData and self.doPtShiftsJEC:
            self.todoShifts.append("_jecUp")
            self.todoShifts.append("_jecDown")

        if not self.isData and self.doPtShiftsJER:
            self.todoShifts.append("_jerUp")
            self.todoShifts.append("_jerDown")

        # since shifts for PU are in fact changes in weight
        # there is no sense to repeat whole analaysis
        # we will use the central value
        self.shiftsPU = ["_central"]
        if not self.isData and self.doShiftsPU:
            self.shiftsPU.append("_puUp")
            self.shiftsPU.append("_puDown")

        self.hist = {}
        todoTrg = ["_jet15", "_dj15fb"]

        binsNew = self.variantFilter.bins()

        # note: set gives as unique items, since _central is repeated
        self.hist["ptHat"] = ROOT.TH1F("ptHat",   "ptHat",  100, 0, 50)

        for shift in set(self.todoShifts+self.shiftsPU):
            for trg in todoTrg:
                t = shift+trg
                self.hist["ptLead"+t] =  ROOT.TH1F("ptLead"+t,   "ptLead"+t,  100, 0, 100)
                self.hist["ptSublead"+t] =  ROOT.TH1F("ptSublead"+t,   "ptSublead"+t,  100, 0, 100)
                self.hist["etaLead"+t] =  ROOT.TH1F("etaLead"+t,   "etaLead"+t,  100, -5, 5)
                self.hist["etaSublead"+t] =  ROOT.TH1F("etaSublead"+t,   "etaSublead"+t,  100, -5, 5)
                self.hist["xsVsDeltaEta"+t] =  ROOT.TH1F("xs"+t,   "xs"+t, len(binsNew)-1, binsNew)
                self.hist["miss"+t] = self.hist["xsVsDeltaEta"+t].Clone("miss"+t)

                self.hist["vtx"+t] =  ROOT.TH1F("vtx"+t,   "vtx"+t,  10, -0.5, 9.5)

                if self.unfoldEnabled:
                    dummy = ROOT.TH2F("dummy"+t, "dummy"+t, len(binsNew)-1, binsNew, len(binsNew)-1, binsNew)
                    self.hist["response"+t]= ROOT.RooUnfoldResponse(self.hist["xsVsDeltaEta"+t], 
                                                                    self.hist["xsVsDeltaEta"+t], 
                                                                    dummy,
                                                                    "response"+t,"response"+t)


        # in principle trigger does not applies to gen plots. We keep consistent naming though, so the unfolded result to gen level plots is possible
        # in each category
        self.hist["detaGen_jet15"] =  ROOT.TH1F("detaGen_central_jet15", "detaGen_central_jet15",
                                                len(binsNew)-1, binsNew)
        self.hist["detaGen_dj15fb"] =  ROOT.TH1F("detaGen_central_dj15fb", "detaGen_central_dj15fb",  
                                                len(binsNew)-1, binsNew)


        if self.onlyPtHatReweighing:
            self.var = {}
            self.var["leadPt"] = array('d', [0])
            self.var["leadEta"] = array('d', [0])
            self.var["weight"] = array('d', [0]) # only jet15 trigger??
            #self.var["alphaQCD"] = array('d', [0])
            self.var["qScale"]   = array('d', [0])
            self.tree = ROOT.TTree("data", "data")
            for v in self.var:
                self.tree.Branch(v, self.var[v], v+"/D")
            self.addToOutput(self.tree)

        else:
            for h in self.hist:
                if not h.startswith("response"):
                    self.hist[h].Sumw2()
                #self.GetOutputList().Add(self.hist[h])
                self.addToOutput(self.hist[h])

        if self.applyPtHatReweighing and not self.isData:
                fp = "CommonFSQFramework/Core/test/MNxsectionAna/"
                todo = ["ptHatWeighters.root"]
                self.ptHatW = []
                for t in todo:
                    ptHatFileName = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/"+t).fullPath()
                    ptHatFile = ROOT.TFile(ptHatFileName)
                    self.ptHatW.append(ptHatFile.Get(self.datasetName+"/ptHatW"))




        puFiles = {}
        # CommonFSQFramework.Core/test/MNxsectionAna/
        jet15FileV2 = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/PUJet15V2.root").fullPath()   # MC gen distribution

        puFiles["dj15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_0.root").fullPath()
        puFiles["dj15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_05.root").fullPath()
        puFiles["dj15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_0_95.root").fullPath()
        puFiles["j15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_0.root").fullPath()
        puFiles["j15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_05.root").fullPath()
        puFiles["j15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_0_95.root").fullPath()

        self.lumiWeighters = {}
        self.lumiWeighters["_jet15_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1"], "MC", "pileup")
        self.lumiWeighters["_jet15_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1_05"], "MC", "pileup")
        self.lumiWeighters["_jet15_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_0_95"], "MC", "pileup")

        self.lumiWeighters["_dj15fb_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1_05"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_0_95"], "MC", "pileup")

        self.jetGetter = BetterJetGetter("PFAK5") 
        self.getterForTriggerModelling = BetterJetGetter("CaloRaw")

    # note: for the ptHat reweighing we will do only the central variation.
    #       otherwise the changes from the JEC/JER variations would be fixed
    #       by the ptHat reweighing procedure

    #
    # leadPt:qScale gives a nice linear response
    #
    # todo: trigger correction for data
    def doPtHatReweighing(self, weightBase):
        if self.isData:
            if self.fChain.jet15 < 0.5:
                return
            weight = weightBase
        else:
            if not self.triggerFired("_jet15"):
                return
            truePU = self.fChain.puTrueNumInteractions
            puWeight =  self.lumiWeighters["_jet15_central"].weight(truePU)
            weight = weightBase*puWeight

        sortKey = lambda j: j.pt()*(j.pt()>self.threshold)\
                          *(j.jetid()>0.5)*(abs(j.eta())<4.7)

        # if empty sequence...
        try:
            bestJet = max(self.jetGetter.get("_central"), key=sortKey)
        except ValueError:
            return

        if not sortKey(bestJet): return # do we really have a jet passing the criteria?
        pt, eta =  bestJet.pt(), bestJet.eta()
        self.var["leadPt"][0] = pt
        self.var["leadEta"][0] = eta
        self.var["weight"][0] = weight
        if not self.isData:
            #self.var["alphaQCD"][0] = self.fChain.alphaQCD
            self.var["qScale"][0] = self.fChain.qScale
        self.tree.Fill()

        
    def triggerFired(self, case):
        if case == "_jet15" and self.MC_jet15_triggerFired_cached != None:
            return self.MC_jet15_triggerFired_cached
        if case == "_dj15fb" and self.MC_dj15fb_triggerFired_cached != None:
            return self.MC_dj15fb_triggerFired_cached

        ev = self.fChain.event
        rnd4eff = ev%10000/9999.


        if case == "_jet15":
            if self.MC_dj15fb_triggerFired_cached == None and self.MC_jet15_triggerFired_cached == None:
                self.getterForTriggerModelling.newEvent(self.fChain)
                self.jetsForTRG = list(self.getterForTriggerModelling.get("_central"))

            # calls needed to reset cached values
            self.HLTMCWeighterJ15L1Raw.setJets(self.jetsForTRG)
            self.HLTMCWeighterJ15Raw.setJets(self.jetsForTRG)
            #self.HLTMCWeighterJ15L1Raw.setGetter(self.getterForTriggerModelling)
            #self.HLTMCWeighterJ15Raw.setGetter(self.getterForTriggerModelling)
            #self.HLTMCWeighterJ15L1Raw.newEvent(self.fChain)
            #self.HLTMCWeighterJ15Raw.newEvent(self.fChain)
            w1 = self.HLTMCWeighterJ15L1Raw.getWeight()
            w2 = self.HLTMCWeighterJ15Raw.getWeight()
            self.MC_jet15_triggerFired_cached = w1*w2 > rnd4eff
            return self.MC_jet15_triggerFired_cached
        elif case == "_dj15fb":
            if self.MC_dj15fb_triggerFired_cached == None and self.MC_jet15_triggerFired_cached == None:
                self.getterForTriggerModelling.newEvent(self.fChain)
                self.jetsForTRG = list(self.getterForTriggerModelling.get("_central"))
            # calls needed to reset cached values
            self.HLTMCWeighterJ15FBL1Raw.setJets(self.jetsForTRG)
            self.HLTMCWeighterJ15FBRaw.setJets(self.jetsForTRG)
            #self.HLTMCWeighterJ15FBL1Raw.setGetter(self.getterForTriggerModelling)
            #self.HLTMCWeighterJ15FBRaw.setGetter(self.getterForTriggerModelling)
            #self.HLTMCWeighterJ15FBL1Raw.newEvent(self.fChain)
            #self.HLTMCWeighterJ15FBRaw.newEvent(self.fChain)
            w1 = self.HLTMCWeighterJ15FBL1Raw.getWeight()
            w2 = self.HLTMCWeighterJ15FBRaw.getWeight()
            self.MC_dj15fb_triggerFired_cached = w1*w2 > rnd4eff
            return self.MC_dj15fb_triggerFired_cached
        else:
            raise Excecption("triggerFired: case not known: "+str(case))

    def topology(self, j1, j2):
        eta1=j1.eta()
        eta2=j2.eta()
        if min(abs(eta1), abs(eta2)) > 3. and eta1*eta2<0: return "_dj15fb"
        return "_jet15"

    def dr(self, a,b):
        de = a.eta()-b.eta()
        dp = a.phi()-b.phi()
        pi = 3.1415
        if dp > pi: dp -= 2*pi
        if dp < -pi: dp += 2*pi
        return math.sqrt(de*de+dp*dp)

    '''
    def analyze(self):
        self.pr.enable()
        self.analyzeTT()
        self.pr.disable()
    #'''
    #def analyzeTT(self):
    def analyze(self):
        self.MC_jet15_triggerFired_cached = None
        self.MC_dj15fb_triggerFired_cached = None

        if self.fChain.ngoodVTX == 0: return
        self.jetGetter.newEvent(self.fChain)
        weightBase = 1. 
        weightBaseNoMCNorm = 1. 
        puWeights = {}
        puWeights["_jet15"] = {}
        puWeights["_dj15fb"] = {}


        if not self.isData:
            weightBase *= self.fChain.genWeight*self.normFactor 
            weightBaseNoMCNorm *= self.fChain.genWeight
            truePU = self.fChain.puTrueNumInteractions
            for lw in self.lumiWeighters:
                spl = lw.split("_")
                trgName = "_"+spl[1]
                variationName = "_"+spl[2]
                puWeights[trgName][variationName] = self.lumiWeighters[lw].weight(truePU)

        # note: this is intentionally before ptHat reweighing
        if not self.isData:
            self.hist["ptHat"].Fill(self.fChain.qScale, weightBase)

        if not self.isData and  self.applyPtHatReweighing:
            ptHat = self.fChain.qScale
            w = 1.
            for weighter in self.ptHatW:
                w*=max(weighter.Eval(ptHat), 0.)
                #print "W:", ptHat, weighter.Eval(ptHat)
            weightBase *= w
            weightBaseNoMCNorm*= w 

        if self.onlyPtHatReweighing:
            self.doPtHatReweighing(weightBase)
            return


        if not self.isData:
            goodGenJets = self.variantFilter.filterCol([j for j in self.fChain.genJets \
                                                        if j.pt()>self.threshold and abs(j.eta()) < 4.7 ])

        for shift in self.todoShifts:
            matchedPairs = set()
            # todo: j.jetID() > 0.5
            goodRecoJets = self.variantFilter.filterCol([j for j in self.jetGetter.get(shift) \
                                                        if j.pt()>self.threshold and abs(j.eta()) < 4.7 and  j.jetid()])

            for i1 in xrange(len(goodRecoJets)):
                for i2 in xrange(i1+1, len(goodRecoJets)):
                    j1 = goodRecoJets[i1]
                    j2 = goodRecoJets[i2]
                    if not self.variantFilter.filterPair(j1, j2): continue
                    topology = self.topology(j1, j2)
                    weight = {}
                    if self.isData:
                        if topology == "_jet15":
                            hasTrigger = self.fChain.jet15 > 0.5
                            weight["_central"] = 1
                        else:
                            hasTrigger = self.fChain.doubleJ15FB > 0.5
                            weight["_central"] = 1
                    else:
                        hasTrigger = self.triggerFired(topology)
                        weightNoNorm = {}
                        if shift == "_central":
                            for s in self.shiftsPU: # note: shifts pu contains central, puUp and puDown
                                weightPU = puWeights[topology][s]
                                weight[s] = weightPU*weightBase    
                                weightNoNorm[s] = weightPU*weightBaseNoMCNorm    
                        else:
                            weightPU = puWeights[topology]["_central"]
                            weight[shift] = weightPU*weightBase    
                            weightNoNorm[shift] = weightPU*weightBaseNoMCNorm    

                    if not hasTrigger: continue

                    detaDet = self.variantFilter.xsVariable(j1, j2) # note: we should rename this...
                    ptSorted = sorted( [j1, j2], key = lambda j: -j.pt())

                    for w in weight:
                        histoName = w + topology
                        self.hist["ptLead"+histoName].Fill(ptSorted[0].pt(), weight[w])
                        self.hist["etaLead"+histoName].Fill(ptSorted[0].eta(), weight[w])
                        self.hist["ptSublead"+histoName].Fill(ptSorted[1].pt(), weight[w])
                        self.hist["etaSublead"+histoName].Fill(ptSorted[1].eta(), weight[w])
                        self.hist["xsVsDeltaEta"+histoName].Fill(detaDet, weight[w])
                        self.hist["vtx"+histoName].Fill(self.fChain.ngoodVTX, weight[w])

                    # todo: fill detLevel Histograms
                    # for MC - check if there is a matching pair, save result inside matchedPairs set
                    if not self.isData: # and len(goodGenJets) > 1:
                        matched=() # empty tuple
                        if len(goodGenJets) > 1:
                            closestGenJetI1 = min(xrange(len(goodGenJets)), key = lambda i: self.dr(j1, goodGenJets[i]) )
                            closestGenJetI2 = min(xrange(len(goodGenJets)), key = lambda i: self.dr(j2, goodGenJets[i]) )
                            if self.variantFilter.filterPair(goodGenJets[closestGenJetI1], goodGenJets[closestGenJetI2]):
                                dr1 = self.dr(j1, goodGenJets[closestGenJetI1])
                                dr2 = self.dr(j2, goodGenJets[closestGenJetI2])
                                if max(dr1, dr2) < 0.3:
                                    if closestGenJetI1 != closestGenJetI2:
                                        # check the topology is correct
                                        genTopology = self.topology(goodGenJets[closestGenJetI1], goodGenJets[closestGenJetI2])
                                        if genTopology == topology:
                                            matchCand=(min(closestGenJetI1,closestGenJetI2), max(closestGenJetI1,closestGenJetI2))    
                                            if not matchCand in matchedPairs:
                                                matched=matchCand
                                                matchedPairs.add(matchCand)
                                    else:
                                        pass
                                        #print "XXX Warning, matched to same genJet"
                                        #print  j1.pt(), j1.eta(), j1.phi()
                                        #print  j2.pt(), j2.eta(), j2.phi()
                                        #def pr(x): print x
                                        #map(lambda x: pr("Gen: {0} {1} {2}".format(x.pt(), x.eta() , x.phi())),  goodGenJets  )

                        # add this point we know, if this is
                        #   a fake: no matched genJetPair (or genJet pair from different category)
                        #   a fill: matched genJetPai
                        #fill the response matrix
                        if len(matched)>0:
                            if self.unfoldEnabled:
                                detaGen = self.variantFilter.xsVariable(goodGenJets[matched[0]],goodGenJets[matched[1]])
                                for w in weightNoNorm:
                                    histoName = w + topology
                                    self.hist["response"+histoName].Fill(detaDet, detaGen, weightNoNorm[w])
                        else:
                            if self.unfoldEnabled:
                                for w in weightNoNorm:
                                    histoName = w + topology
                                    self.hist["response"+histoName].Fake(detaDet, weightNoNorm[w])

            # Now: fill miss cateogory
            # note: this is still happening in "shift" loop
            if self.unfoldEnabled and not self.isData:
                for i1 in xrange(len(goodGenJets)):
                    for i2 in xrange(i1+1, len(goodGenJets)):
                        if not self.variantFilter.filterPair(goodGenJets[i1], goodGenJets[i2]): continue
                        genTopology = None
                        detaGen = None
                        if shift == "_central":
                            genTopology = self.topology(goodGenJets[i1], goodGenJets[i2])
                            detaGen = self.variantFilter.xsVariable(goodGenJets[i1], goodGenJets[i2])
                            self.hist["detaGen"+genTopology].Fill(detaGen, weightBase)

                        if (i1, i2) in matchedPairs: continue
                        if genTopology == None:
                            genTopology = self.topology(goodGenJets[i1], goodGenJets[i2])
   
                        # note: code repeated here, see above defintion of weightNoNorm
                        weightNoNorm = {}
                        if shift == "_central":
                            for s in self.shiftsPU: # note: shifts pu contains central, puUp and puDown
                                weightPU = puWeights[genTopology][s]
                                weightNoNorm[s] = weightPU*weightBaseNoMCNorm    
                        else:
                            weightPU = puWeights[genTopology]["_central"]
                            weightNoNorm[shift] = weightPU*weightBaseNoMCNorm    

                        if detaGen == None:
                            detaGen = self.variantFilter.xsVariable(goodGenJets[i1], goodGenJets[i2])

                        for w in weightNoNorm:
                            histoName = w + genTopology
                            self.hist["response"+histoName].Miss(detaGen, weightNoNorm[w])
                            self.hist["miss"+histoName].Fill(detaGen, weightNoNorm[w])

    def finalize(self):
        print "Finalize:"
        if hasattr(self, "pr"):
            dname = "/nfs/dust/cms/user/fruboest/2015.01.MN/slc6/CMSSW_7_0_5/src/CommonFSQFramework/Core/test/MNxsectionAna/bak/"
            profName = dname + "stats"
            self.pr.dump_stats(profName)

        for h in self.hist:
            if not h.startswith("response"): continue
            def cloneAndAdd(h, name):
                hh = h.Clone(name)
                hh.SetName(name)
                self.addToOutput(hh)

            cloneAndAdd(self.hist[h].Hfakes(), "fake"+h)
            cloneAndAdd(self.hist[h].Htruth(), "truth"+h)
            cloneAndAdd(self.hist[h].Hmeasured(), "measured"+h)
            cloneAndAdd(self.hist[h].Hresponse(), "resp"+h)
class MNxsAnalyzerClean(CommonFSQFramework.Core.ExampleProofReader.ExampleProofReader):
    def init( self):

        self.variantFilter = BaseDijetAna.variant(self.variant)

        if not self.isData:
            #self.hltMCWeighter = HLTMCWeighter("HLT_Jet15U")
            self.HLTMCWeighterJ15Raw = HLTMCWeighter("HLT_Jet15U_raw")
            self.HLTMCWeighterJ15L1Raw = HLTMCWeighter("HLT_Jet15U_L1Seeding_raw")
            self.HLTMCWeighterJ15FBL1Raw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_L1Seeding_raw")
            self.HLTMCWeighterJ15FBRaw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_raw")

        self.normFactor = self.getNormalizationFactor()

        #sys.stdout = sys.stderr
        #self.pr = cProfile.Profile()
        print "XXX init - MNxsAnalyzerClean", self.datasetName, self.isData

        self.todoShifts = ["_central"]
        if not self.isData and self.doPtShiftsJEC:
            self.todoShifts.append("_jecUp")
            self.todoShifts.append("_jecDown")

        if not self.isData and self.doPtShiftsJER:
            self.todoShifts.append("_jerUp")
            self.todoShifts.append("_jerDown")

        # since shifts for PU are in fact changes in weight
        # there is no sense to repeat whole analaysis
        # we will use the central value
        self.shiftsPU = ["_central"]
        if not self.isData and self.doShiftsPU:
            self.shiftsPU.append("_puUp")
            self.shiftsPU.append("_puDown")

        self.hist = {}
        todoTrg = ["_jet15", "_dj15fb"]

        binsNew = self.variantFilter.bins()

        # note: set gives as unique items, since _central is repeated
        self.hist["ptHat"] = ROOT.TH1F("ptHat",   "ptHat",  100, 0, 50)

        for shift in set(self.todoShifts+self.shiftsPU):
            for trg in todoTrg:
                t = shift+trg
                self.hist["ptLead"+t] =  ROOT.TH1F("ptLead"+t,   "ptLead"+t,  100, 0, 100)
                self.hist["ptSublead"+t] =  ROOT.TH1F("ptSublead"+t,   "ptSublead"+t,  100, 0, 100)
                self.hist["etaLead"+t] =  ROOT.TH1F("etaLead"+t,   "etaLead"+t,  100, -5, 5)
                self.hist["etaSublead"+t] =  ROOT.TH1F("etaSublead"+t,   "etaSublead"+t,  100, -5, 5)
                self.hist["xsVsDeltaEta"+t] =  ROOT.TH1F("xs"+t,   "xs"+t, len(binsNew)-1, binsNew)
                self.hist["miss"+t] = self.hist["xsVsDeltaEta"+t].Clone("miss"+t)

                self.hist["vtx"+t] =  ROOT.TH1F("vtx"+t,   "vtx"+t,  10, -0.5, 9.5)

                if self.unfoldEnabled:
                    dummy = ROOT.TH2F("dummy"+t, "dummy"+t, len(binsNew)-1, binsNew, len(binsNew)-1, binsNew)
                    self.hist["response"+t]= ROOT.RooUnfoldResponse(self.hist["xsVsDeltaEta"+t], 
                                                                    self.hist["xsVsDeltaEta"+t], 
                                                                    dummy,
                                                                    "response"+t,"response"+t)


        # in principle trigger does not applies to gen plots. We keep consistent naming though, so the unfolded result to gen level plots is possible
        # in each category
        self.hist["detaGen_jet15"] =  ROOT.TH1F("detaGen_central_jet15", "detaGen_central_jet15",
                                                len(binsNew)-1, binsNew)
        self.hist["detaGen_dj15fb"] =  ROOT.TH1F("detaGen_central_dj15fb", "detaGen_central_dj15fb",  
                                                len(binsNew)-1, binsNew)


        if self.onlyPtHatReweighing:
            self.var = {}
            self.var["leadPt"] = array('d', [0])
            self.var["leadEta"] = array('d', [0])
            self.var["weight"] = array('d', [0]) # only jet15 trigger??
            #self.var["alphaQCD"] = array('d', [0])
            self.var["qScale"]   = array('d', [0])
            self.tree = ROOT.TTree("data", "data")
            for v in self.var:
                self.tree.Branch(v, self.var[v], v+"/D")
            self.addToOutput(self.tree)

        else:
            for h in self.hist:
                if not h.startswith("response"):
                    self.hist[h].Sumw2()
                #self.GetOutputList().Add(self.hist[h])
                self.addToOutput(self.hist[h])

        if self.applyPtHatReweighing and not self.isData:
                fp = "CommonFSQFramework/Core/test/MNxsectionAna/"
                todo = ["ptHatWeighters.root"]
                self.ptHatW = []
                for t in todo:
                    ptHatFileName = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/"+t).fullPath()
                    ptHatFile = ROOT.TFile(ptHatFileName)
                    self.ptHatW.append(ptHatFile.Get(self.datasetName+"/ptHatW"))




        puFiles = {}
        # CommonFSQFramework.Core/test/MNxsectionAna/
        jet15FileV2 = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/PUJet15V2.root").fullPath()   # MC gen distribution

        puFiles["dj15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_0.root").fullPath()
        puFiles["dj15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_05.root").fullPath()
        puFiles["dj15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_0_95.root").fullPath()
        puFiles["j15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_0.root").fullPath()
        puFiles["j15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_05.root").fullPath()
        puFiles["j15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_0_95.root").fullPath()

        self.lumiWeighters = {}
        self.lumiWeighters["_jet15_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1"], "MC", "pileup")
        self.lumiWeighters["_jet15_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1_05"], "MC", "pileup")
        self.lumiWeighters["_jet15_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_0_95"], "MC", "pileup")

        self.lumiWeighters["_dj15fb_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1_05"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_0_95"], "MC", "pileup")

        self.jetGetter = BetterJetGetter("PFAK5") 
        self.getterForTriggerModelling = BetterJetGetter("CaloRaw")

    # note: for the ptHat reweighing we will do only the central variation.
    #       otherwise the changes from the JEC/JER variations would be fixed
    #       by the ptHat reweighing procedure

    #
    # leadPt:qScale gives a nice linear response
    #
    # todo: trigger correction for data
    def doPtHatReweighing(self, weightBase):
        if self.isData:
            if self.fChain.jet15 < 0.5:
                return
            weight = weightBase
        else:
            if not self.triggerFired("_jet15"):
                return
            truePU = self.fChain.puTrueNumInteractions
            puWeight =  self.lumiWeighters["_jet15_central"].weight(truePU)
            weight = weightBase*puWeight

        sortKey = lambda j: j.pt()*(j.pt()>self.threshold)\
                          *(j.jetid()>0.5)*(abs(j.eta())<4.7)

        # if empty sequence...
        try:
            bestJet = max(self.jetGetter.get("_central"), key=sortKey)
        except ValueError:
            return

        if not sortKey(bestJet): return # do we really have a jet passing the criteria?
        pt, eta =  bestJet.pt(), bestJet.eta()
        self.var["leadPt"][0] = pt
        self.var["leadEta"][0] = eta
        self.var["weight"][0] = weight
        if not self.isData:
            #self.var["alphaQCD"][0] = self.fChain.alphaQCD
            self.var["qScale"][0] = self.fChain.qScale
        self.tree.Fill()

        
    def triggerFired(self, case):
        if case == "_jet15" and self.MC_jet15_triggerFired_cached != None:
            return self.MC_jet15_triggerFired_cached
        if case == "_dj15fb" and self.MC_dj15fb_triggerFired_cached != None:
            return self.MC_dj15fb_triggerFired_cached
    def init( self):
        if not self.isData:
            #self.hltMCWeighter = HLTMCWeighter("HLT_Jet15U")
            self.HLTMCWeighterJ15Raw = HLTMCWeighter("HLT_Jet15U_raw")
            self.HLTMCWeighterJ15L1Raw = HLTMCWeighter("HLT_Jet15U_L1Seeding_raw")
            self.HLTMCWeighterJ15FBL1Raw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_L1Seeding_raw")
            self.HLTMCWeighterJ15FBRaw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_raw")

        self.normFactor = self.getNormalizationFactor()


        #sys.stdout = sys.stderr
        #self.pr = cProfile.Profile()
        print "XXX init - MNxsAnalyzer", self.datasetName, self.isData

        self.todoShifts = ["_central"]
        if not self.isData and self.doPtShiftsJEC:
            self.todoShifts.append("_jecUp")
            self.todoShifts.append("_jecDown")

        if not self.isData and self.doPtShiftsJER:
            self.todoShifts.append("_jerUp")
            self.todoShifts.append("_jerDown")

        self.hist = {}
        todoTrg = ["_jet15", "_dj15fb"]

        binningDeta = (19, 0, 9.5)

        for shift in self.todoShifts:
            for trg in todoTrg:
                t = shift+trg
                self.hist["ptLead"+t] =  ROOT.TH1F("ptLead"+t,   "ptLead"+t,  100, 0, 100)
                self.hist["ptSublead"+t] =  ROOT.TH1F("ptSublead"+t,   "ptSublead"+t,  100, 0, 100)
                self.hist["etaLead"+t] =  ROOT.TH1F("etaLead"+t,   "etaLead"+t,  100, -5, 5)
                self.hist["etaSublead"+t] =  ROOT.TH1F("etaSublead"+t,   "etaSublead"+t,  100, -5, 5)
                self.hist["xsVsDeltaEta"+t] =  ROOT.TH1F("xs"+t,   "xs"+t, binningDeta[0], binningDeta[1], binningDeta[2])

                self.hist["xsVsDeltaEtaGen"+t] =  ROOT.TH1F("xsGen"+t,   "xsGen"+t, binningDeta[0], binningDeta[1], binningDeta[2])
                self.hist["xsVsDeltaEtaFake"+t] =  ROOT.TH1F("xsFake"+t,   "xsFake"+t, binningDeta[0], binningDeta[1], binningDeta[2])
                self.hist["xsVsDeltaEtaMiss"+t] =  ROOT.TH1F("xsMiss"+t,   "xsMiss"+t, binningDeta[0], binningDeta[1], binningDeta[2])

                self.hist["vtx"+t] =  ROOT.TH1F("vtx"+t,   "vtx"+t,  10, -0.5, 9.5)

                if self.unfoldEnabled:
                    self.hist["response"+t]= ROOT.RooUnfoldResponse(binningDeta[0], binningDeta[1], binningDeta[2], "response"+t,"response"+t)


        self.hist["evcnt"] =  ROOT.TH1F("evcnt_central_jet15", "evcnt_central_jet15",  1, -0.5, 0.5)
        #self.hist["detaGen"] =  ROOT.TH1F("detaGen_central_sum", "detaGen_central_sum",  binningDeta[0], binningDeta[1], binningDeta[2])

        # in principle trigger does not applies to gen plots. We keep consistent naming though, so the unfolded result to gen level plots is possible
        # in each category
        self.hist["detaGen_jet15"] =  ROOT.TH1F("detaGen_central_jet15", "detaGen_central_jet15",  binningDeta[0], binningDeta[1], binningDeta[2])
        self.hist["detaGen_dj15fb"] =  ROOT.TH1F("detaGen_central_dj15fb", "detaGen_central_dj15fb",  binningDeta[0], binningDeta[1], binningDeta[2])
        self.hist["detaGenVsRec"] =  ROOT.TH2F("detaGenVsRec_central_jet15", "detaGenVsRec_central_jet15",\
                                               binningDeta[0]*20, binningDeta[1], binningDeta[2],\
                                               binningDeta[0]*20, binningDeta[1], binningDeta[2])


        if self.onlyPtHatReweighing:
            self.var = {}
            self.var["leadPt"] = array('d', [0])
            self.var["leadEta"] = array('d', [0])
            self.var["weight"] = array('d', [0]) # only jet15 trigger??
            #self.var["alphaQCD"] = array('d', [0])
            self.var["qScale"]   = array('d', [0])
            self.tree = ROOT.TTree("data", "data")
            for v in self.var:
                self.tree.Branch(v, self.var[v], v+"/D")
            self.addToOutput(self.tree)

        else:
            for h in self.hist:
                if not h.startswith("response"):
                    self.hist[h].Sumw2()
                #self.GetOutputList().Add(self.hist[h])
                self.addToOutput(self.hist[h])

        if self.applyPtHatReweighing and not self.isData:
                fp = "CommonFSQFramework.Core/test/MNxsectionAna/"
                todo = ["ptHatWeighters.root"]
                #todo = ["ptHatWeighters_invx_pass1.root_invX", 
                #        "ptHatWeighters_invx_pass2.root_invX",
                #        "ptHatWeighters_invx_pass3.root_invX",]
                self.ptHatW = []
                for t in todo:
                    ptHatFileName = edm.FileInPath("CommonFSQFramework.Core/test/MNxsectionAna/"+t).fullPath()
                    ptHatFile = ROOT.TFile(ptHatFileName)
                    self.ptHatW.append(ptHatFile.Get(self.datasetName+"/ptHatW"))
                    #print "PTHat weighter set to", self.datasetName+"/ptHatW"
                    #print "PTHat test@30:", self.ptHatW.Eval(30)




        puFiles = {}
        # CommonFSQFramework.Core/test/MNxsectionAna/
        jet15FileV2 = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/PUJet15V2.root").fullPath()   # MC gen distribution

        puFiles["dj15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_0.root").fullPath()
        puFiles["dj15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_05.root").fullPath()
        puFiles["dj15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_0_95.root").fullPath()
        puFiles["j15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_0.root").fullPath()
        puFiles["j15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_05.root").fullPath()
        puFiles["j15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_0_95.root").fullPath()

        self.lumiWeighters = {}
        self.lumiWeighters["_jet15_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1"], "MC", "pileup")
        self.lumiWeighters["_jet15_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1_05"], "MC", "pileup")
        self.lumiWeighters["_jet15_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_0_95"], "MC", "pileup")

        self.lumiWeighters["_dj15fb_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1_05"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_0_95"], "MC", "pileup")

        #self.jetGetter = JetGetter("PF")
        #if hasattr(self, "jetUncFile"):
        #    self.jetGetter.setJecUncertainty(self.jetUncFile)

        self.jetGetter = BetterJetGetter("PFAK5") 
class MNxsAnalyzer(CommonFSQFramework.Core.ExampleProofReader.ExampleProofReader):
    def init( self):
        if not self.isData:
            #self.hltMCWeighter = HLTMCWeighter("HLT_Jet15U")
            self.HLTMCWeighterJ15Raw = HLTMCWeighter("HLT_Jet15U_raw")
            self.HLTMCWeighterJ15L1Raw = HLTMCWeighter("HLT_Jet15U_L1Seeding_raw")
            self.HLTMCWeighterJ15FBL1Raw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_L1Seeding_raw")
            self.HLTMCWeighterJ15FBRaw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_raw")

        self.normFactor = self.getNormalizationFactor()


        #sys.stdout = sys.stderr
        #self.pr = cProfile.Profile()
        print "XXX init - MNxsAnalyzer", self.datasetName, self.isData

        self.todoShifts = ["_central"]
        if not self.isData and self.doPtShiftsJEC:
            self.todoShifts.append("_jecUp")
            self.todoShifts.append("_jecDown")

        if not self.isData and self.doPtShiftsJER:
            self.todoShifts.append("_jerUp")
            self.todoShifts.append("_jerDown")

        self.hist = {}
        todoTrg = ["_jet15", "_dj15fb"]

        binningDeta = (19, 0, 9.5)

        for shift in self.todoShifts:
            for trg in todoTrg:
                t = shift+trg
                self.hist["ptLead"+t] =  ROOT.TH1F("ptLead"+t,   "ptLead"+t,  100, 0, 100)
                self.hist["ptSublead"+t] =  ROOT.TH1F("ptSublead"+t,   "ptSublead"+t,  100, 0, 100)
                self.hist["etaLead"+t] =  ROOT.TH1F("etaLead"+t,   "etaLead"+t,  100, -5, 5)
                self.hist["etaSublead"+t] =  ROOT.TH1F("etaSublead"+t,   "etaSublead"+t,  100, -5, 5)
                self.hist["xsVsDeltaEta"+t] =  ROOT.TH1F("xs"+t,   "xs"+t, binningDeta[0], binningDeta[1], binningDeta[2])

                self.hist["xsVsDeltaEtaGen"+t] =  ROOT.TH1F("xsGen"+t,   "xsGen"+t, binningDeta[0], binningDeta[1], binningDeta[2])
                self.hist["xsVsDeltaEtaFake"+t] =  ROOT.TH1F("xsFake"+t,   "xsFake"+t, binningDeta[0], binningDeta[1], binningDeta[2])
                self.hist["xsVsDeltaEtaMiss"+t] =  ROOT.TH1F("xsMiss"+t,   "xsMiss"+t, binningDeta[0], binningDeta[1], binningDeta[2])

                self.hist["vtx"+t] =  ROOT.TH1F("vtx"+t,   "vtx"+t,  10, -0.5, 9.5)

                if self.unfoldEnabled:
                    self.hist["response"+t]= ROOT.RooUnfoldResponse(binningDeta[0], binningDeta[1], binningDeta[2], "response"+t,"response"+t)


        self.hist["evcnt"] =  ROOT.TH1F("evcnt_central_jet15", "evcnt_central_jet15",  1, -0.5, 0.5)
        #self.hist["detaGen"] =  ROOT.TH1F("detaGen_central_sum", "detaGen_central_sum",  binningDeta[0], binningDeta[1], binningDeta[2])

        # in principle trigger does not applies to gen plots. We keep consistent naming though, so the unfolded result to gen level plots is possible
        # in each category
        self.hist["detaGen_jet15"] =  ROOT.TH1F("detaGen_central_jet15", "detaGen_central_jet15",  binningDeta[0], binningDeta[1], binningDeta[2])
        self.hist["detaGen_dj15fb"] =  ROOT.TH1F("detaGen_central_dj15fb", "detaGen_central_dj15fb",  binningDeta[0], binningDeta[1], binningDeta[2])
        self.hist["detaGenVsRec"] =  ROOT.TH2F("detaGenVsRec_central_jet15", "detaGenVsRec_central_jet15",\
                                               binningDeta[0]*20, binningDeta[1], binningDeta[2],\
                                               binningDeta[0]*20, binningDeta[1], binningDeta[2])


        if self.onlyPtHatReweighing:
            self.var = {}
            self.var["leadPt"] = array('d', [0])
            self.var["leadEta"] = array('d', [0])
            self.var["weight"] = array('d', [0]) # only jet15 trigger??
            #self.var["alphaQCD"] = array('d', [0])
            self.var["qScale"]   = array('d', [0])
            self.tree = ROOT.TTree("data", "data")
            for v in self.var:
                self.tree.Branch(v, self.var[v], v+"/D")
            self.addToOutput(self.tree)

        else:
            for h in self.hist:
                if not h.startswith("response"):
                    self.hist[h].Sumw2()
                #self.GetOutputList().Add(self.hist[h])
                self.addToOutput(self.hist[h])

        if self.applyPtHatReweighing and not self.isData:
                fp = "CommonFSQFramework.Core/test/MNxsectionAna/"
                todo = ["ptHatWeighters.root"]
                #todo = ["ptHatWeighters_invx_pass1.root_invX", 
                #        "ptHatWeighters_invx_pass2.root_invX",
                #        "ptHatWeighters_invx_pass3.root_invX",]
                self.ptHatW = []
                for t in todo:
                    ptHatFileName = edm.FileInPath("CommonFSQFramework.Core/test/MNxsectionAna/"+t).fullPath()
                    ptHatFile = ROOT.TFile(ptHatFileName)
                    self.ptHatW.append(ptHatFile.Get(self.datasetName+"/ptHatW"))
                    #print "PTHat weighter set to", self.datasetName+"/ptHatW"
                    #print "PTHat test@30:", self.ptHatW.Eval(30)




        puFiles = {}
        # CommonFSQFramework.Core/test/MNxsectionAna/
        jet15FileV2 = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/PUJet15V2.root").fullPath()   # MC gen distribution

        puFiles["dj15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_0.root").fullPath()
        puFiles["dj15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_05.root").fullPath()
        puFiles["dj15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_0_95.root").fullPath()
        puFiles["j15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_0.root").fullPath()
        puFiles["j15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_05.root").fullPath()
        puFiles["j15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_0_95.root").fullPath()

        self.lumiWeighters = {}
        self.lumiWeighters["_jet15_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1"], "MC", "pileup")
        self.lumiWeighters["_jet15_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1_05"], "MC", "pileup")
        self.lumiWeighters["_jet15_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_0_95"], "MC", "pileup")

        self.lumiWeighters["_dj15fb_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1_05"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_0_95"], "MC", "pileup")

        #self.jetGetter = JetGetter("PF")
        #if hasattr(self, "jetUncFile"):
        #    self.jetGetter.setJecUncertainty(self.jetUncFile)

        self.jetGetter = BetterJetGetter("PFAK5") 



    def dr(self, a,b):
        de = a.eta()-b.eta()
        dp = a.phi()-b.phi()
        pi = 3.1415
        if dp > pi: dp -= 2*pi
        if dp < -pi: dp += 2*pi
        #print  a.phi(), b.phi(), dp

        return math.sqrt(de*de+dp*dp)


    def doGri(self, weight, variation):
        fil = lambda x: x.pt() > self.threshold and abs(x.eta())<4.7
        genJ = filter(fil, self.fChain.genJets) # 1
        detJ  =filter(fil, self.jetGetter.get(variation)) #1

        ##print "AAA", len(genJ), len(detJ)

        postfix = variation+"_jet15"
        if len(genJ)<2: 
            if len(detJ) < 2:
                return
            detJB = min(detJ, key= lambda j: j.eta()  )
            detJF = max(detJ, key= lambda j: j.eta()  )
            deta = abs(detJB.eta()-detJF.eta())
            self.hist["xsVsDeltaEtaFake"+postfix].Fill(deta, weight)
            return # 2

        gjB = min(genJ, key= lambda j: j.eta()  )
        gjF = max(genJ, key= lambda j: j.eta()  )
        detaGen = gjF.eta() - gjB.eta()
        self.hist["xsVsDeltaEtaGen"+postfix].Fill(detaGen, weight)  # 3
        if len(detJ)<2:
            self.hist["xsVsDeltaEtaMiss"+postfix].Fill(detaGen, weight) # 4
            self.hist["response"+postfix].Miss(detaGen, weight)
            return

        closestDetJet1 = min(detJ, key = lambda j: self.dr(j, gjB) ) # 5, eta restriction imposed in step 1
        dr1 = self.dr(closestDetJet1, gjB)
        if dr1 > 0.3:
            self.hist["xsVsDeltaEtaMiss"+postfix].Fill(detaGen, weight) # 6
            self.hist["response"+postfix].Miss(detaGen, weight)
            return
        else:
            closestDetJet2 = min(detJ, key = lambda j: self.dr(j, gjF) ) # 5,
            dr2 = self.dr(closestDetJet2, gjF)
            if dr2 > 0.3:
                self.hist["xsVsDeltaEtaMiss"+postfix].Fill(detaGen, weight) # 6
                self.hist["response"+postfix].Miss(detaGen, weight)
                return

        detaDet = abs(closestDetJet1.eta()- closestDetJet2.eta())
        self.hist["response"+postfix].Fill(detaDet, detaGen, weight) # 7




    # note: for the ptHat reweighing we will do only the central variation.
    #       otherwise the changes from the JEC/JER variations would be fixed
    #       by the ptHat reweighing procedure

    #
    # leadPt:qScale gives a nice linear response
    #
    # todo: trigger correction for data
    def doPtHatReweighing(self, weightBase):
        if self.isData:
            if self.fChain.jet15 < 0.5:
                return
            weight = weightBase
        else:
            if not self.triggerFired("_jet15"):
                return
            truePU = self.fChain.puTrueNumInteractions
            puWeight =  self.lumiWeighters["_jet15_central"].weight(truePU)
            weight = weightBase*puWeight

        sortKey = lambda j: j.pt()*(j.pt()>self.threshold)\
                          *(j.jetid()>0.5)*(abs(j.eta())<4.7)

        # if empty sequence...
        try:
            bestJet = max(self.jetGetter.get("_central"), key=sortKey)
        except ValueError:
            return

        if not sortKey(bestJet): return # do we really have a jet passing the criteria?
        pt, eta =  bestJet.pt(), bestJet.eta()
        self.var["leadPt"][0] = pt
        self.var["leadEta"][0] = eta
        self.var["weight"][0] = weight
        if not self.isData:
            #self.var["alphaQCD"][0] = self.fChain.alphaQCD
            self.var["qScale"][0] = self.fChain.qScale
        self.tree.Fill()

        
    def triggerFired(self, case):
        if case == "_jet15" and self.MC_jet15_triggerFired_cached != None:
            return self.MC_jet15_triggerFired_cached
        if case == "_dj15fb" and self.MC_dj15fb_triggerFired_cached != None:
            return self.MC_dj15fb_triggerFired_cached

        ev = self.fChain.event
        rnd4eff = ev%10000/9999.

        if case == "_jet15":
            self.HLTMCWeighterJ15L1Raw.newEvent(self.fChain)
            self.HLTMCWeighterJ15Raw.newEvent(self.fChain)
            w1 = self.HLTMCWeighterJ15L1Raw.getWeight()
            w2 = self.HLTMCWeighterJ15Raw.getWeight()
            self.MC_jet15_triggerFired_cached = w1*w2 > rnd4eff
            return self.MC_jet15_triggerFired_cached
        elif case == "_dj15fb":
            self.HLTMCWeighterJ15FBL1Raw.newEvent(self.fChain)
            self.HLTMCWeighterJ15FBRaw.newEvent(self.fChain)
            w1 = self.HLTMCWeighterJ15FBL1Raw.getWeight()
            w2 = self.HLTMCWeighterJ15FBRaw.getWeight()
            self.MC_dj15fb_triggerFired_cached = w1*w2 > rnd4eff
            return self.MC_dj15fb_triggerFired_cached
        else:
            raise Excecption("triggerFired: case not known: "+str(case))
        
           

    def analyze(self):
        self.MC_jet15_triggerFired_cached = None
        self.MC_dj15fb_triggerFired_cached = None

        self.hist["evcnt"].Fill(0)
        if self.fChain.ngoodVTX == 0: return
        self.jetGetter.newEvent(self.fChain)
        weightBase = 1. 
        if not self.isData:
            weightBase *= self.fChain.genWeight*self.normFactor 

            #print ev, w1*w2, rnd4eff, triggerFired


        if not self.isData and  self.applyPtHatReweighing:
            ptHat = self.fChain.qScale
            w = 1.
            for weighter in self.ptHatW:
                w*=max(weighter.Eval(ptHat), 0.)
                #print "W:", ptHat, weighter.Eval(ptHat)
            weightBase *= w
 

        if self.onlyPtHatReweighing:
            self.doPtHatReweighing(weightBase)
            return
           

        # fill the roounfoldresponse
        if not self.isData:
            genDEta = None
            genTopology = None
            etas = []
            for j in self.fChain.genJets:
                if j.pt() < self.threshold: continue
                eta = j.eta()
                if abs(j.eta())>4.7: continue
                etas.append(eta)
            if len(etas)>1:
                fwd = max(etas)
                bkw = min(etas)
                genTopology = "CF"
                if fwd > 3 and bkw < -3:
                    genTopology = "FB"
                genDEta = fwd - bkw
                #self.hist["detaGen"].Fill(genDEta, weightBase) # basic gen level distribution shouldnt be PU dependent
                if genTopology == "FB":
                    self.hist["detaGen_dj15fb"].Fill(genDEta, weightBase) # basic gen level distribution shouldnt be PU dependent
                else:
                    self.hist["detaGen_jet15"].Fill(genDEta, weightBase) # basic gen level distribution shouldnt be PU dependent


        for shift in self.todoShifts:
            # Q&D warning: to test this you need to comment out all filling of the response object below
            #truePU = self.fChain.puTrueNumInteractions
            #puWeight =  self.lumiWeighters["_jet15_central"].weight(truePU)
            #self.doGri(weightBase*puWeight, shift)


            # find best dijet pair
            mostFwdJet = None
            mostBkgJet = None
            mostFwdJetEta = None
            mostBkgJetEta = None
            mostFwdJetPt = None
            mostBkgJetPt = None

            for jet in self.jetGetter.get(shift):
                #if jetID.at(i) < 0.5: continue
                if not jet.jetid(): continue
                eta =  jet.eta()
                if abs(eta) > 4.7: continue

                ptShifted = jet.pt()
                if ptShifted < self.threshold: continue

                if  mostFwdJet == None or mostFwdJetEta < eta:
                    mostFwdJet = jet
                    mostFwdJetEta = eta
                    mostFwdJetPt = ptShifted
                if  mostBkgJet == None or mostBkgJetEta > eta:
                    mostBkgJet = jet
                    mostBkgJetEta = eta
                    mostBkgJetPt = ptShifted

            pairFound = False
            if mostFwdJet != None and mostBkgJet != mostFwdJet:
                pairFound = True


            isMiss = True # mark if dijet pair was not found (needed to correctly fill response)
            # A dijet pair was found. Check trigger for data
            # fill histograms
            if pairFound:
                deta = abs(mostFwdJetEta - mostBkgJetEta)
                if not self.isData and genDEta:
                    if shift == "_central":
                        self.hist["detaGenVsRec"].Fill(genDEta, deta, weightBase)
                # detaGenVsRec

                triggerToUse = "_jet15"
                if abs(mostFwdJetEta) > 3 and abs(mostBkgJetEta) > 3 and mostFwdJetEta*mostBkgJetEta<0:
                    triggerToUse = "_dj15fb"

                # TODO: we need to separate gen level categories!!
                gotTrigger = True
                if self.isData: # check trigger
                    if triggerToUse == "_jet15":
                        gotTrigger = self.fChain.jet15 > 0.5
                    elif triggerToUse == "_dj15fb":
                        gotTrigger = self.fChain.doubleJ15FB > 0.5
                    else:
                        raise Exception("Trigger not known??? "+triggerToUse)
                else:
                    gotTrigger = self.triggerFired(triggerToUse)



                if gotTrigger:
                    # calculate weight for MC
                    weight = weightBase
                    if not self.isData:
                        truePU = self.fChain.puTrueNumInteractions
                        puWeight =  self.lumiWeighters[triggerToUse+"_central"].weight(truePU)
                        weight *= puWeight

                    histoName = shift +triggerToUse
                    self.hist["xsVsDeltaEta"+histoName].Fill(deta, weight)
                    if not self.isData:
                        isMiss = False
                        isCorrectTopo = (triggerToUse == "_jet15") and genTopology == "CF" or (triggerToUse == "_dj15fb") and genTopology == "FB"
                        #'''
                        if genDEta == None or not isCorrectTopo:    # fake pair, e.g. from bkg or we landed in a wrong category
                            if self.unfoldEnabled:
                                self.hist["response"+histoName].Fake(deta, weight)
                        else:
                            if self.unfoldEnabled:
                                self.hist["response"+histoName].Fill(deta, genDEta, weight)
                        #'''

                    # fill also some control plots
                    leadJet = mostBkgJet
                    subleadJet = mostFwdJet
                    ptLead =  mostBkgJetPt 
                    ptSublead = mostFwdJetPt
                    etaLead = mostBkgJetEta
                    etaSublead = mostFwdJetEta

                    if ptSublead > ptLead:
                        leadJet, subleadJet = subleadJet, leadJet
                        ptLead, ptSublead = ptSublead, ptLead
                        etaLead, etaSublead = etaSublead, etaLead

                    self.hist["vtx"+histoName].Fill(self.fChain.ngoodVTX, weight)
                    self.hist["ptLead"+histoName].Fill(ptLead, weight)
                    self.hist["ptSublead"+histoName].Fill(ptSublead, weight)
                    self.hist["etaLead"+histoName].Fill(etaLead, weight)
                    self.hist["etaSublead"+histoName].Fill(etaSublead, weight)

            if not self.isData and genDEta and isMiss:
                if genTopology == "CF":
                    triggerToUse = "_jet15"
                else:
                    triggerToUse = "_dj15fb"
                histoName = shift +triggerToUse
                weight = weightBase
                if not self.isData:
                    truePU = self.fChain.puTrueNumInteractions
                    puWeight =  self.lumiWeighters[triggerToUse+"_central"].weight(truePU)

                #print "Miss", triggerToUse, genDEta, shift
                #'''
                if self.unfoldEnabled:
                    self.hist["response"+histoName].Miss(genDEta, weight)
                #'''

    def finalize(self):
        print "Finalize:"
class MNxsAnalyzer(CommonFSQFramework.Core.ExampleProofReader.ExampleProofReader):
    def init( self):
        if not self.isData:
            #self.hltMCWeighter = HLTMCWeighter("HLT_Jet15U")
            self.HLTMCWeighterJ15Raw = HLTMCWeighter("HLT_Jet15U_raw")
            self.HLTMCWeighterJ15L1Raw = HLTMCWeighter("HLT_Jet15U_L1Seeding_raw")
            self.HLTMCWeighterJ15FBL1Raw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_L1Seeding_raw")
            self.HLTMCWeighterJ15FBRaw = HLTMCWeighter("HLT_DoubleJet15U_ForwardBackward_raw")

        self.normFactor = self.getNormalizationFactor()


        #sys.stdout = sys.stderr
        #self.pr = cProfile.Profile()
        print "XXX init - MNxsAnalyzer", self.datasetName, self.isData

        self.todoShifts = ["_central"]
        if not self.isData and self.doPtShiftsJEC:
            self.todoShifts.append("_jecUp")
            self.todoShifts.append("_jecDown")

        if not self.isData and self.doPtShiftsJER:
            self.todoShifts.append("_jerUp")
            self.todoShifts.append("_jerDown")

        self.hist = {}
        todoTrg = ["_jet15", "_dj15fb"]

        binningDeta = (19, 0, 9.5)

        for shift in self.todoShifts:
            for trg in todoTrg:
                t = shift+trg
                self.hist["ptLead"+t] =  ROOT.TH1F("ptLead"+t,   "ptLead"+t,  100, 0, 100)
                self.hist["ptSublead"+t] =  ROOT.TH1F("ptSublead"+t,   "ptSublead"+t,  100, 0, 100)
                self.hist["etaLead"+t] =  ROOT.TH1F("etaLead"+t,   "etaLead"+t,  100, -5, 5)
                self.hist["etaSublead"+t] =  ROOT.TH1F("etaSublead"+t,   "etaSublead"+t,  100, -5, 5)
                self.hist["xsVsDeltaEta"+t] =  ROOT.TH1F("xs"+t,   "xs"+t, binningDeta[0], binningDeta[1], binningDeta[2])

                self.hist["xsVsDeltaEtaGen"+t] =  ROOT.TH1F("xsGen"+t,   "xsGen"+t, binningDeta[0], binningDeta[1], binningDeta[2])
                self.hist["xsVsDeltaEtaFake"+t] =  ROOT.TH1F("xsFake"+t,   "xsFake"+t, binningDeta[0], binningDeta[1], binningDeta[2])
                self.hist["xsVsDeltaEtaMiss"+t] =  ROOT.TH1F("xsMiss"+t,   "xsMiss"+t, binningDeta[0], binningDeta[1], binningDeta[2])

                self.hist["vtx"+t] =  ROOT.TH1F("vtx"+t,   "vtx"+t,  10, -0.5, 9.5)

                if self.unfoldEnabled:
                    self.hist["response"+t]= ROOT.RooUnfoldResponse(binningDeta[0], binningDeta[1], binningDeta[2], "response"+t,"response"+t)


        self.hist["evcnt"] =  ROOT.TH1F("evcnt_central_jet15", "evcnt_central_jet15",  1, -0.5, 0.5)
        #self.hist["detaGen"] =  ROOT.TH1F("detaGen_central_sum", "detaGen_central_sum",  binningDeta[0], binningDeta[1], binningDeta[2])

        # in principle trigger does not applies to gen plots. We keep consistent naming though, so the unfolded result to gen level plots is possible
        # in each category
        self.hist["detaGen_jet15"] =  ROOT.TH1F("detaGen_central_jet15", "detaGen_central_jet15",  binningDeta[0], binningDeta[1], binningDeta[2])
        self.hist["detaGen_dj15fb"] =  ROOT.TH1F("detaGen_central_dj15fb", "detaGen_central_dj15fb",  binningDeta[0], binningDeta[1], binningDeta[2])
        self.hist["detaGenVsRec"] =  ROOT.TH2F("detaGenVsRec_central_jet15", "detaGenVsRec_central_jet15",\
                                               binningDeta[0]*20, binningDeta[1], binningDeta[2],\
                                               binningDeta[0]*20, binningDeta[1], binningDeta[2])


        if self.onlyPtHatReweighing:
            self.var = {}
            self.var["leadPt"] = array('d', [0])
            self.var["leadEta"] = array('d', [0])
            self.var["weight"] = array('d', [0]) # only jet15 trigger??
            #self.var["alphaQCD"] = array('d', [0])
            self.var["qScale"]   = array('d', [0])
            self.tree = ROOT.TTree("data", "data")
            for v in self.var:
                self.tree.Branch(v, self.var[v], v+"/D")
            self.addToOutput(self.tree)

        else:
            for h in self.hist:
                if not h.startswith("response"):
                    self.hist[h].Sumw2()
                #self.GetOutputList().Add(self.hist[h])
                self.addToOutput(self.hist[h])

        if self.applyPtHatReweighing and not self.isData:
                fp = "CommonFSQFramework.Core/test/MNxsectionAna/"
                todo = ["ptHatWeighters.root"]
                #todo = ["ptHatWeighters_invx_pass1.root_invX", 
                #        "ptHatWeighters_invx_pass2.root_invX",
                #        "ptHatWeighters_invx_pass3.root_invX",]
                self.ptHatW = []
                for t in todo:
                    ptHatFileName = edm.FileInPath("CommonFSQFramework.Core/test/MNxsectionAna/"+t).fullPath()
                    ptHatFile = ROOT.TFile(ptHatFileName)
                    self.ptHatW.append(ptHatFile.Get(self.datasetName+"/ptHatW"))
                    #print "PTHat weighter set to", self.datasetName+"/ptHatW"
                    #print "PTHat test@30:", self.ptHatW.Eval(30)




        puFiles = {}
        # CommonFSQFramework.Core/test/MNxsectionAna/
        jet15FileV2 = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/PUJet15V2.root").fullPath()   # MC gen distribution

        puFiles["dj15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_0.root").fullPath()
        puFiles["dj15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_1_05.root").fullPath()
        puFiles["dj15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_dj15_0_95.root").fullPath()
        puFiles["j15_1"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_0.root").fullPath()
        puFiles["j15_1_05"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_1_05.root").fullPath()
        puFiles["j15_0_95"] = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/pu_j15_0_95.root").fullPath()

        self.lumiWeighters = {}
        self.lumiWeighters["_jet15_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1"], "MC", "pileup")
        self.lumiWeighters["_jet15_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_1_05"], "MC", "pileup")
        self.lumiWeighters["_jet15_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["j15_0_95"], "MC", "pileup")

        self.lumiWeighters["_dj15fb_central"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puUp"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_1_05"], "MC", "pileup")
        self.lumiWeighters["_dj15fb_puDown"] = edm.LumiReWeighting(jet15FileV2, puFiles["dj15_0_95"], "MC", "pileup")

        #self.jetGetter = JetGetter("PF")
        #if hasattr(self, "jetUncFile"):
        #    self.jetGetter.setJecUncertainty(self.jetUncFile)

        self.jetGetter = BetterJetGetter("PFAK5") 



    def dr(self, a,b):
        de = a.eta()-b.eta()
        dp = a.phi()-b.phi()
        pi = 3.1415
        if dp > pi: dp -= 2*pi
        if dp < -pi: dp += 2*pi
        #print  a.phi(), b.phi(), dp

        return math.sqrt(de*de+dp*dp)


    def doGri(self, weight, variation):
        fil = lambda x: x.pt() > self.threshold and abs(x.eta())<4.7
        genJ = filter(fil, self.fChain.genJets) # 1
        detJ  =filter(fil, self.jetGetter.get(variation)) #1

        ##print "AAA", len(genJ), len(detJ)

        postfix = variation+"_jet15"
        if len(genJ)<2: 
            if len(detJ) < 2:
                return
            detJB = min(detJ, key= lambda j: j.eta()  )
            detJF = max(detJ, key= lambda j: j.eta()  )
            deta = abs(detJB.eta()-detJF.eta())
            self.hist["xsVsDeltaEtaFake"+postfix].Fill(deta, weight)
            return # 2

        gjB = min(genJ, key= lambda j: j.eta()  )
        gjF = max(genJ, key= lambda j: j.eta()  )
        detaGen = gjF.eta() - gjB.eta()
        self.hist["xsVsDeltaEtaGen"+postfix].Fill(detaGen, weight)  # 3
        if len(detJ)<2:
            self.hist["xsVsDeltaEtaMiss"+postfix].Fill(detaGen, weight) # 4
            self.hist["response"+postfix].Miss(detaGen, weight)
            return

        closestDetJet1 = min(detJ, key = lambda j: self.dr(j, gjB) ) # 5, eta restriction imposed in step 1
        dr1 = self.dr(closestDetJet1, gjB)
        if dr1 > 0.3:
            self.hist["xsVsDeltaEtaMiss"+postfix].Fill(detaGen, weight) # 6
            self.hist["response"+postfix].Miss(detaGen, weight)
            return
        else:
            closestDetJet2 = min(detJ, key = lambda j: self.dr(j, gjF) ) # 5,
            dr2 = self.dr(closestDetJet2, gjF)
            if dr2 > 0.3:
                self.hist["xsVsDeltaEtaMiss"+postfix].Fill(detaGen, weight) # 6
                self.hist["response"+postfix].Miss(detaGen, weight)
                return

        detaDet = abs(closestDetJet1.eta()- closestDetJet2.eta())
        self.hist["response"+postfix].Fill(detaDet, detaGen, weight) # 7




    # note: for the ptHat reweighing we will do only the central variation.
    #       otherwise the changes from the JEC/JER variations would be fixed
    #       by the ptHat reweighing procedure

    #
    # leadPt:qScale gives a nice linear response
    #
    # todo: trigger correction for data
    def doPtHatReweighing(self, weightBase):
        if self.isData:
            if self.fChain.jet15 < 0.5:
                return
            weight = weightBase
        else:
            if not self.triggerFired("_jet15"):
                return
            truePU = self.fChain.puTrueNumInteractions
            puWeight =  self.lumiWeighters["_jet15_central"].weight(truePU)
            weight = weightBase*puWeight

        sortKey = lambda j: j.pt()*(j.pt()>self.threshold)\
                          *(j.jetid()>0.5)*(abs(j.eta())<4.7)

        # if empty sequence...
        try:
            bestJet = max(self.jetGetter.get("_central"), key=sortKey)
        except ValueError:
            return

        if not sortKey(bestJet): return # do we really have a jet passing the criteria?
        pt, eta =  bestJet.pt(), bestJet.eta()
        self.var["leadPt"][0] = pt
        self.var["leadEta"][0] = eta
        self.var["weight"][0] = weight
        if not self.isData:
            #self.var["alphaQCD"][0] = self.fChain.alphaQCD
            self.var["qScale"][0] = self.fChain.qScale
        self.tree.Fill()

        
    def triggerFired(self, case):
        if case == "_jet15" and self.MC_jet15_triggerFired_cached != None:
            return self.MC_jet15_triggerFired_cached
        if case == "_dj15fb" and self.MC_dj15fb_triggerFired_cached != None:
            return self.MC_dj15fb_triggerFired_cached