def init(self):
        #self.pr = cProfile.Profile()

        print "Params:", self.etaMax, self.ptMin

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

        self.normFactor = self.getNormalizationFactor()
        self.dphi = ROOT.Math.VectorUtil.DeltaPhi

        self.tree = ROOT.TTree("data", "data")
        #self.GetOutputList().Add(self.tree)
        self.addToOutput(self.tree)

        self.var = {}
        self.histos = {}
        self.histos["evcnt"] =  ROOT.TH1F("evcnt_central_jet15", "evcnt_central_jet15",  1, -0.5, 0.5)

        self.todoShifts = ["_central"]

        if not self.isData and self.doPtShiftsJEC:
            #self.todoShifts.append("_ptUp")
            #self.todoShifts.append("_ptDown")
            self.todoShifts.append("_jecUp")
            self.todoShifts.append("_jecDown")

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


        trg = "_jet15"
        for t in self.todoShifts:
            self.var["tagPt"+t] = array('d', [0])
            self.var["tagEta"+t] = array('d', [0])
            self.var["probePt"+t] = array('d', [0])
            self.var["probeEta"+t] = array('d', [0])
            self.var["ptAve"+t] = array('d', [0])
            self.var["balance"+t] = array('d', [0])
            #//self.var["veto1"+t] = array('d', [0])
            self.var["veto2"+t] = array('d', [0])

            histoPostFix = t+trg
            self.histos["ptProbe"+t] = ROOT.TH1F("ptProbe"+histoPostFix, "ptProbe"+histoPostFix, 100, 0, 100)
            self.histos["ptTag"+t] = ROOT.TH1F("ptTag"+histoPostFix, "ptTag"+histoPostFix, 100, 0, 100)
            self.histos["etaProbe"+t] = ROOT.TH1F("etaProbe"+histoPostFix, "etaProbe"+histoPostFix, 35, 1.3, 4.8)
            self.histos["etaTag"+t] = ROOT.TH1F("etaTag"+histoPostFix, "etaTag"+histoPostFix, 15, 0, 1.5)
            self.histos["nvtx"+t] = ROOT.TH1F("nvtx"+histoPostFix, "nvtx"+histoPostFix, 10, -0.5, 9.5)
 

        for t in self.histos:
            #self.histos[t][1] = ROOT.TH1F(name, name, nbins, self.histos[t][2], self.histos[t][3])
            self.histos[t].Sumw2()
            #self.GetOutputList().Add(self.histos[t])
            self.addToOutput(self.histos[t])

        self.var["weight"] = array('d', [0])
        for v in self.var:
            self.tree.Branch(v, self.var[v], v+"/D")
        
        jet15FileV2 = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/PUJet15V2.root").fullPath()   # MC gen distribution
        puFiles = {}
        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")



        if self.HLT2015TempWorkaround:
            #self.jetGetter = JetGetter("PFAK4CHS", jetColOverride="recoPFAK4ChsCorrectedMyRhop4")
            #self.jetGetter = JetGetter("PFAK4CHS", jetColOverride="recoPFAK4ChsCorrectedp4")
            self.jetGetter = JetGetter("PFAK4CHS", jetColOverride="hltAK4PFJetsCorrectedp4")
            #self.jetGetter = JetGetter("PFAK4CHS")
            #self.jetGetter = JetGetter("PFAK5CHS")
            #self.jetGetter = JetGetter("PF")
            self.jetGetter.disableGenJet()
            self.jetGetter.disableJetId()
            #self.jetGetter = GenJetProxy()
        else:
            self.jetGetter = JetGetter("PFAK5")
            #self.jetGetter = JetGetter("PFlegacy")
            self.jetGetter.disableGenJet()

        #self.jetGetter = BetterJetGetter("PFAK5") 
        #self.jetGetter = BetterJetGetter("Calo") 

        '''
        if self.isData:
            self.jetGetter = JetGetter("PFAK5") 
        else:
            self.jetGetter = JetGetter("PFlegacy") 
        '''

        self.varE = {}
        sys.stdout.flush()
    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 BalanceTreeProducer(CommonFSQFramework.Core.ExampleProofReader.ExampleProofReader):
    def init(self):
        #self.pr = cProfile.Profile()

        print "Params:", self.etaMax, self.ptMin

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

        self.normFactor = self.getNormalizationFactor()
        self.dphi = ROOT.Math.VectorUtil.DeltaPhi

        self.tree = ROOT.TTree("data", "data")
        #self.GetOutputList().Add(self.tree)
        self.addToOutput(self.tree)

        self.var = {}
        self.histos = {}
        self.histos["evcnt"] =  ROOT.TH1F("evcnt_central_jet15", "evcnt_central_jet15",  1, -0.5, 0.5)

        self.todoShifts = ["_central"]

        if not self.isData and self.doPtShiftsJEC:
            #self.todoShifts.append("_ptUp")
            #self.todoShifts.append("_ptDown")
            self.todoShifts.append("_jecUp")
            self.todoShifts.append("_jecDown")

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


        trg = "_jet15"
        for t in self.todoShifts:
            self.var["tagPt"+t] = array('d', [0])
            self.var["tagEta"+t] = array('d', [0])
            self.var["probePt"+t] = array('d', [0])
            self.var["probeEta"+t] = array('d', [0])
            self.var["ptAve"+t] = array('d', [0])
            self.var["balance"+t] = array('d', [0])
            #//self.var["veto1"+t] = array('d', [0])
            self.var["veto2"+t] = array('d', [0])

            histoPostFix = t+trg
            self.histos["ptProbe"+t] = ROOT.TH1F("ptProbe"+histoPostFix, "ptProbe"+histoPostFix, 100, 0, 100)
            self.histos["ptTag"+t] = ROOT.TH1F("ptTag"+histoPostFix, "ptTag"+histoPostFix, 100, 0, 100)
            self.histos["etaProbe"+t] = ROOT.TH1F("etaProbe"+histoPostFix, "etaProbe"+histoPostFix, 35, 1.3, 4.8)
            self.histos["etaTag"+t] = ROOT.TH1F("etaTag"+histoPostFix, "etaTag"+histoPostFix, 15, 0, 1.5)
            self.histos["nvtx"+t] = ROOT.TH1F("nvtx"+histoPostFix, "nvtx"+histoPostFix, 10, -0.5, 9.5)
 

        for t in self.histos:
            #self.histos[t][1] = ROOT.TH1F(name, name, nbins, self.histos[t][2], self.histos[t][3])
            self.histos[t].Sumw2()
            #self.GetOutputList().Add(self.histos[t])
            self.addToOutput(self.histos[t])

        self.var["weight"] = array('d', [0])
        for v in self.var:
            self.tree.Branch(v, self.var[v], v+"/D")
        
        jet15FileV2 = edm.FileInPath("CommonFSQFramework/Core/test/MNxsectionAna/data/PUJet15V2.root").fullPath()   # MC gen distribution
        puFiles = {}
        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")



        if self.HLT2015TempWorkaround:
            #self.jetGetter = JetGetter("PFAK4CHS", jetColOverride="recoPFAK4ChsCorrectedMyRhop4")
            #self.jetGetter = JetGetter("PFAK4CHS", jetColOverride="recoPFAK4ChsCorrectedp4")
            self.jetGetter = JetGetter("PFAK4CHS", jetColOverride="hltAK4PFJetsCorrectedp4")
            #self.jetGetter = JetGetter("PFAK4CHS")
            #self.jetGetter = JetGetter("PFAK5CHS")
            #self.jetGetter = JetGetter("PF")
            self.jetGetter.disableGenJet()
            self.jetGetter.disableJetId()
            #self.jetGetter = GenJetProxy()
        else:
            self.jetGetter = JetGetter("PFAK5")
            #self.jetGetter = JetGetter("PFlegacy")
            self.jetGetter.disableGenJet()

        #self.jetGetter = BetterJetGetter("PFAK5") 
        #self.jetGetter = BetterJetGetter("Calo") 

        '''
        if self.isData:
            self.jetGetter = JetGetter("PFAK5") 
        else:
            self.jetGetter = JetGetter("PFlegacy") 
        '''

        self.varE = {}
        sys.stdout.flush()

    def addExternalVar(self, names):
        for name in names:
            self.varE[name] =  0.
            self.var[name] = array('d', [0])
            self.tree.Branch(name, self.var[name], name+"/D")

    def setExternals(self):
        for v in self.varE:
            self.var[v][0] = self.varE[v]
    def fill(self):
            self.tree.Fill()
    def resetExternals(self):
        for v in self.varE: 
            self.varE[v] = 0

    def fillGenWeight(self):
        weight = self.genWeight()
        self.var["weight"][0] = weight


    def setExternalVar(self, name, val):
        self.varE[name] = val

    def genWeight(self):
        #print "ASDFASD", self.fChain.genWeight
        return self.fChain.genWeight*self.normFactor
    
    def weight(self):
        if self.weightCache != None:
            return self.weightCache
        if not self.isData:
            weight = self.genWeight()
            if not self.HLT2015TempWorkaround:
                truePU = self.fChain.puTrueNumInteractions
                puWeight =  self.lumiWeighters["_jet15_central"].weight(truePU)
                weight *= puWeight
                w1 = self.HLTMCWeighterJ15L1Raw.getWeight()
                w2 = self.HLTMCWeighterJ15Raw.getWeight()
                triggerEff = w1*w2
                weight *= triggerEff
        else:
            weight = 1

        self.weightCache = weight
        return weight



    '''
    # stuff for code profiling
    def analyze(self):
        self.pr.enable()
        self.analyzeTT()
        self.pr.disable()
    def analyzeTT(self):
        '''
    def analyze(self):
        self.weightCache = None
        self.histos["evcnt"].Fill(0)
        # '''
        if not self.HLT2015TempWorkaround:
            if self.fChain.ngoodVTX == 0: return
            if self.fChain.HBHENoiseFilterResult == 0: return


        if self.isData:
            if self.fChain.jet15 < 0.5:
                return 1
            
        for v in self.var:
            self.var[v][0] = 0

        # reset is done after fill
        self.setExternals()

        self.jetGetter.newEvent(self.fChain)
        if not self.isData:
            self.HLTMCWeighterJ15L1Raw.newEvent(self.fChain)
            self.HLTMCWeighterJ15Raw.newEvent(self.fChain)


        # xxxwei

            

        fill = False
        for shift in self.todoShifts:
            tagJet = None
            probeJet = None
            probePT = None
            tagPT = None


            for jet in self.jetGetter.get(shift):
                pt = jet.pt()

                if pt < self.ptMin: continue
                eta = abs(jet.eta())
                if eta > self.etaMax: continue

                if not self.HLT2015TempWorkaround:
                    if not jet.jetid(): continue
                if eta < 1.4:
                    tagJet = jet
                    tagPT = pt
                else:
                    probeJet = jet
                    probePT = pt

            if tagJet != None and probeJet != None:
                dphi = abs(self.dphi(tagJet.p4(), probeJet.p4()))
                if dphi < 2.7: continue
                
                # check veto:
                ptAve = (probePT+tagPT)/2
                if ptAve < 25: continue


                veto2 = -1
                #for jet in self.jetGetter.get(shift):
                for jet in self.jetGetter.get(shift):
                    if jet == tagJet or probeJet == jet: continue
                    eta = abs(jet.eta())
                    if eta > self.etaMax: continue
                    vetoCand = jet.pt()/ptAve
                    if veto2 < vetoCand:
                        veto2 = vetoCand

                tagEta = abs(tagJet.eta())
                probeEta = abs(probeJet.eta())

                self.var["tagPt"+shift][0] = tagPT 
                self.var["tagEta"+shift][0] = tagEta
                self.var["probePt"+shift][0] = probePT
                self.var["probeEta"+shift][0] = probeEta
                self.var["ptAve"+shift][0] = ptAve
                self.var["balance"+shift][0] = (probePT-tagPT)/ptAve
                #self.var["veto1"+shift][0] = veto1
                self.var["veto2"+shift][0] = veto2
                fill = True


                #print "Hist fill", weight
                weight = self.weight()
                self.histos["ptProbe"+shift].Fill(probePT, weight)
                self.histos["ptTag"+shift].Fill(tagPT, weight)
                self.histos["etaProbe"+shift].Fill(probeEta, weight)
                self.histos["etaTag"+shift].Fill(tagEta, weight)
                #self.histos["nvtx"+shift].Fill(self.fChain.ngoodVTX, weight)

   
        # at least one variation ok.
        if fill:
            self.var["weight"][0] = self.weight()
            self.fill()

        self.resetExternals()

        return 1

    def finalize(self):
        print "Finalize:"
        if hasattr(self, "pr"):
            dname = "/nfs/dust/cms/user/fruboest/2014.11.MN2010/CMSSW_4_2_8_lowpupatch1/src/CommonFSQFramework.Core/test/MNxsectionAna/"
            profName = dname + "stats"
            self.pr.dump_stats(profName)
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)
    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:"
    def init(self):
        #self.pr = cProfile.Profile()

        print "Params:", self.etaMax, self.ptMin

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

        self.normFactor = self.getNormalizationFactor()
        self.dphi = ROOT.Math.VectorUtil.DeltaPhi

        self.tree = ROOT.TTree("data", "data")
        #self.GetOutputList().Add(self.tree)
        self.addToOutput(self.tree)

        self.var = {}
        self.histos = {}
        self.histos["evcnt"] = ROOT.TH1F("evcnt_central_jet15",
                                         "evcnt_central_jet15", 1, -0.5, 0.5)

        self.todoShifts = ["_central"]

        if not self.isData and self.doPtShiftsJEC:
            #self.todoShifts.append("_ptUp")
            #self.todoShifts.append("_ptDown")
            self.todoShifts.append("_jecUp")
            self.todoShifts.append("_jecDown")

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

        trg = "_jet15"
        for t in self.todoShifts:
            self.var["tagPt" + t] = array('d', [0])
            self.var["tagEta" + t] = array('d', [0])
            self.var["probePt" + t] = array('d', [0])
            self.var["probeEta" + t] = array('d', [0])
            self.var["ptAve" + t] = array('d', [0])
            self.var["balance" + t] = array('d', [0])
            #//self.var["veto1"+t] = array('d', [0])
            self.var["veto2" + t] = array('d', [0])

            histoPostFix = t + trg
            self.histos["ptProbe" + t] = ROOT.TH1F("ptProbe" + histoPostFix,
                                                   "ptProbe" + histoPostFix,
                                                   100, 0, 100)
            self.histos["ptTag" + t] = ROOT.TH1F("ptTag" + histoPostFix,
                                                 "ptTag" + histoPostFix, 100,
                                                 0, 100)
            self.histos["etaProbe" + t] = ROOT.TH1F("etaProbe" + histoPostFix,
                                                    "etaProbe" + histoPostFix,
                                                    35, 1.3, 4.8)
            self.histos["etaTag" + t] = ROOT.TH1F("etaTag" + histoPostFix,
                                                  "etaTag" + histoPostFix, 15,
                                                  0, 1.5)
            self.histos["nvtx" + t] = ROOT.TH1F("nvtx" + histoPostFix,
                                                "nvtx" + histoPostFix, 10,
                                                -0.5, 9.5)

        for t in self.histos:
            #self.histos[t][1] = ROOT.TH1F(name, name, nbins, self.histos[t][2], self.histos[t][3])
            self.histos[t].Sumw2()
            #self.GetOutputList().Add(self.histos[t])
            self.addToOutput(self.histos[t])

        self.var["weight"] = array('d', [0])
        for v in self.var:
            self.tree.Branch(v, self.var[v], v + "/D")

        jet15FileV2 = edm.FileInPath(
            "CommonFSQFramework/Core/test/MNxsectionAna/data/PUJet15V2.root"
        ).fullPath()  # MC gen distribution
        puFiles = {}
        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")

        if self.HLT2015TempWorkaround:
            #self.jetGetter = JetGetter("PFAK4CHS", jetColOverride="recoPFAK4ChsCorrectedMyRhop4")
            #self.jetGetter = JetGetter("PFAK4CHS", jetColOverride="recoPFAK4ChsCorrectedp4")
            self.jetGetter = JetGetter(
                "PFAK4CHS", jetColOverride="hltAK4PFJetsCorrectedp4")
            #self.jetGetter = JetGetter("PFAK4CHS")
            #self.jetGetter = JetGetter("PFAK5CHS")
            #self.jetGetter = JetGetter("PF")
            self.jetGetter.disableGenJet()
            self.jetGetter.disableJetId()
            #self.jetGetter = GenJetProxy()
        else:
            self.jetGetter = JetGetter("PFAK5")
            #self.jetGetter = JetGetter("PFlegacy")
            self.jetGetter.disableGenJet()

        #self.jetGetter = BetterJetGetter("PFAK5")
        #self.jetGetter = BetterJetGetter("Calo")
        '''
        if self.isData:
            self.jetGetter = JetGetter("PFAK5") 
        else:
            self.jetGetter = JetGetter("PFlegacy") 
        '''

        self.varE = {}
        sys.stdout.flush()
class BalanceTreeProducer(
        CommonFSQFramework.Core.ExampleProofReader.ExampleProofReader):
    def init(self):
        #self.pr = cProfile.Profile()

        print "Params:", self.etaMax, self.ptMin

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

        self.normFactor = self.getNormalizationFactor()
        self.dphi = ROOT.Math.VectorUtil.DeltaPhi

        self.tree = ROOT.TTree("data", "data")
        #self.GetOutputList().Add(self.tree)
        self.addToOutput(self.tree)

        self.var = {}
        self.histos = {}
        self.histos["evcnt"] = ROOT.TH1F("evcnt_central_jet15",
                                         "evcnt_central_jet15", 1, -0.5, 0.5)

        self.todoShifts = ["_central"]

        if not self.isData and self.doPtShiftsJEC:
            #self.todoShifts.append("_ptUp")
            #self.todoShifts.append("_ptDown")
            self.todoShifts.append("_jecUp")
            self.todoShifts.append("_jecDown")

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

        trg = "_jet15"
        for t in self.todoShifts:
            self.var["tagPt" + t] = array('d', [0])
            self.var["tagEta" + t] = array('d', [0])
            self.var["probePt" + t] = array('d', [0])
            self.var["probeEta" + t] = array('d', [0])
            self.var["ptAve" + t] = array('d', [0])
            self.var["balance" + t] = array('d', [0])
            #//self.var["veto1"+t] = array('d', [0])
            self.var["veto2" + t] = array('d', [0])

            histoPostFix = t + trg
            self.histos["ptProbe" + t] = ROOT.TH1F("ptProbe" + histoPostFix,
                                                   "ptProbe" + histoPostFix,
                                                   100, 0, 100)
            self.histos["ptTag" + t] = ROOT.TH1F("ptTag" + histoPostFix,
                                                 "ptTag" + histoPostFix, 100,
                                                 0, 100)
            self.histos["etaProbe" + t] = ROOT.TH1F("etaProbe" + histoPostFix,
                                                    "etaProbe" + histoPostFix,
                                                    35, 1.3, 4.8)
            self.histos["etaTag" + t] = ROOT.TH1F("etaTag" + histoPostFix,
                                                  "etaTag" + histoPostFix, 15,
                                                  0, 1.5)
            self.histos["nvtx" + t] = ROOT.TH1F("nvtx" + histoPostFix,
                                                "nvtx" + histoPostFix, 10,
                                                -0.5, 9.5)

        for t in self.histos:
            #self.histos[t][1] = ROOT.TH1F(name, name, nbins, self.histos[t][2], self.histos[t][3])
            self.histos[t].Sumw2()
            #self.GetOutputList().Add(self.histos[t])
            self.addToOutput(self.histos[t])

        self.var["weight"] = array('d', [0])
        for v in self.var:
            self.tree.Branch(v, self.var[v], v + "/D")

        jet15FileV2 = edm.FileInPath(
            "CommonFSQFramework/Core/test/MNxsectionAna/data/PUJet15V2.root"
        ).fullPath()  # MC gen distribution
        puFiles = {}
        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")

        if self.HLT2015TempWorkaround:
            #self.jetGetter = JetGetter("PFAK4CHS", jetColOverride="recoPFAK4ChsCorrectedMyRhop4")
            #self.jetGetter = JetGetter("PFAK4CHS", jetColOverride="recoPFAK4ChsCorrectedp4")
            self.jetGetter = JetGetter(
                "PFAK4CHS", jetColOverride="hltAK4PFJetsCorrectedp4")
            #self.jetGetter = JetGetter("PFAK4CHS")
            #self.jetGetter = JetGetter("PFAK5CHS")
            #self.jetGetter = JetGetter("PF")
            self.jetGetter.disableGenJet()
            self.jetGetter.disableJetId()
            #self.jetGetter = GenJetProxy()
        else:
            self.jetGetter = JetGetter("PFAK5")
            #self.jetGetter = JetGetter("PFlegacy")
            self.jetGetter.disableGenJet()

        #self.jetGetter = BetterJetGetter("PFAK5")
        #self.jetGetter = BetterJetGetter("Calo")
        '''
        if self.isData:
            self.jetGetter = JetGetter("PFAK5") 
        else:
            self.jetGetter = JetGetter("PFlegacy") 
        '''

        self.varE = {}
        sys.stdout.flush()

    def addExternalVar(self, names):
        for name in names:
            self.varE[name] = 0.
            self.var[name] = array('d', [0])
            self.tree.Branch(name, self.var[name], name + "/D")

    def setExternals(self):
        for v in self.varE:
            self.var[v][0] = self.varE[v]

    def fill(self):
        self.tree.Fill()

    def resetExternals(self):
        for v in self.varE:
            self.varE[v] = 0

    def fillGenWeight(self):
        weight = self.genWeight()
        self.var["weight"][0] = weight

    def setExternalVar(self, name, val):
        self.varE[name] = val

    def genWeight(self):
        #print "ASDFASD", self.fChain.genWeight
        return self.fChain.genWeight * self.normFactor

    def weight(self):
        if self.weightCache != None:
            return self.weightCache
        if not self.isData:
            weight = self.genWeight()
            if not self.HLT2015TempWorkaround:
                truePU = self.fChain.puTrueNumInteractions
                puWeight = self.lumiWeighters["_jet15_central"].weight(truePU)
                weight *= puWeight
                w1 = self.HLTMCWeighterJ15L1Raw.getWeight()
                w2 = self.HLTMCWeighterJ15Raw.getWeight()
                triggerEff = w1 * w2
                weight *= triggerEff
        else:
            weight = 1

        self.weightCache = weight
        return weight

    '''
    # stuff for code profiling
    def analyze(self):
        self.pr.enable()
        self.analyzeTT()
        self.pr.disable()
    def analyzeTT(self):
        '''

    def analyze(self):
        self.weightCache = None
        self.histos["evcnt"].Fill(0)
        # '''
        if not self.HLT2015TempWorkaround:
            if self.fChain.ngoodVTX == 0: return
            if self.fChain.HBHENoiseFilterResult == 0: return

        if self.isData:
            if self.fChain.jet15 < 0.5:
                return 1

        for v in self.var:
            self.var[v][0] = 0

        # reset is done after fill
        self.setExternals()

        self.jetGetter.newEvent(self.fChain)
        if not self.isData:
            self.HLTMCWeighterJ15L1Raw.newEvent(self.fChain)
            self.HLTMCWeighterJ15Raw.newEvent(self.fChain)

        # xxxwei

        fill = False
        for shift in self.todoShifts:
            tagJet = None
            probeJet = None
            probePT = None
            tagPT = None

            for jet in self.jetGetter.get(shift):
                pt = jet.pt()

                if pt < self.ptMin: continue
                eta = abs(jet.eta())
                if eta > self.etaMax: continue

                if not self.HLT2015TempWorkaround:
                    if not jet.jetid(): continue
                if eta < 1.4:
                    tagJet = jet
                    tagPT = pt
                else:
                    probeJet = jet
                    probePT = pt

            if tagJet != None and probeJet != None:
                dphi = abs(self.dphi(tagJet.p4(), probeJet.p4()))
                if dphi < 2.7: continue

                # check veto:
                ptAve = (probePT + tagPT) / 2
                if ptAve < 25: continue

                veto2 = -1
                #for jet in self.jetGetter.get(shift):
                for jet in self.jetGetter.get(shift):
                    if jet == tagJet or probeJet == jet: continue
                    eta = abs(jet.eta())
                    if eta > self.etaMax: continue
                    vetoCand = jet.pt() / ptAve
                    if veto2 < vetoCand:
                        veto2 = vetoCand

                tagEta = abs(tagJet.eta())
                probeEta = abs(probeJet.eta())

                self.var["tagPt" + shift][0] = tagPT
                self.var["tagEta" + shift][0] = tagEta
                self.var["probePt" + shift][0] = probePT
                self.var["probeEta" + shift][0] = probeEta
                self.var["ptAve" + shift][0] = ptAve
                self.var["balance" + shift][0] = (probePT - tagPT) / ptAve
                #self.var["veto1"+shift][0] = veto1
                self.var["veto2" + shift][0] = veto2
                fill = True

                #print "Hist fill", weight
                weight = self.weight()
                self.histos["ptProbe" + shift].Fill(probePT, weight)
                self.histos["ptTag" + shift].Fill(tagPT, weight)
                self.histos["etaProbe" + shift].Fill(probeEta, weight)
                self.histos["etaTag" + shift].Fill(tagEta, weight)
                #self.histos["nvtx"+shift].Fill(self.fChain.ngoodVTX, weight)

        # at least one variation ok.
        if fill:
            self.var["weight"][0] = self.weight()
            self.fill()

        self.resetExternals()

        return 1

    def finalize(self):
        print "Finalize:"
        if hasattr(self, "pr"):
            dname = "/nfs/dust/cms/user/fruboest/2014.11.MN2010/CMSSW_4_2_8_lowpupatch1/src/CommonFSQFramework.Core/test/MNxsectionAna/"
            profName = dname + "stats"
            self.pr.dump_stats(profName)