Exemple #1
0
class jetRecalib(Module):
    def __init__(self,  globalTag, archive, jetType = "AK4PFchs", redoJEC=False):

        self.redoJEC = redoJEC

        if "AK4" in jetType : 
            self.jetBranchName = "Jet"
        elif "AK8" in jetType :
            self.jetBranchName = "FatJet"
            self.subJetBranchName = "SubJet"
        else:
            raise ValueError("ERROR: Invalid jet type = '%s'!" % jetType)
        self.rhoBranchName = "fixedGridRhoFastjetAll"
        self.lenVar = "n" + self.jetBranchName        

        self.jesInputArchivePath = os.environ['CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/"
        # Text files are now tarred so must extract first into temporary directory (gets deleted during python memory management at script exit)
        self.jesArchive = tarfile.open(self.jesInputArchivePath+archive+".tgz", "r:gz")
        self.jesInputFilePath = tempfile.mkdtemp()
        self.jesArchive.extractall(self.jesInputFilePath)

        self.jetReCalibrator = JetReCalibrator(globalTag, jetType , True, self.jesInputFilePath, calculateSeparateCorrections = False, calculateType1METCorrection  = False)
	
        # load libraries for accessing JES scale factors and uncertainties from txt files
        for library in [ "libCondFormatsJetMETObjects", "libPhysicsToolsNanoAODTools" ]:
            if library not in ROOT.gSystem.GetLibraries():
                print("Load Library '%s'" % library.replace("lib", ""))
                ROOT.gSystem.Load(library)

        self.puppiCorrFile = ROOT.TFile.Open(os.environ['CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/puppiCorr.root")
        self.puppisd_corrGEN = self.puppiCorrFile.Get("puppiJECcorr_gen")
        self.puppisd_corrRECO_cen = self.puppiCorrFile.Get("puppiJECcorr_reco_0eta1v3")
        self.puppisd_corrRECO_for = self.puppiCorrFile.Get("puppiJECcorr_reco_1v3eta2v5")

    def beginJob(self):
	pass

    def endJob(self):
	pass

    def beginFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        self.out = wrappedOutputTree
        self.out.branch("%s_pt_raw" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_pt_nom" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_mass_raw" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_mass_nom" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_msoftdrop_raw" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_msoftdrop_nom" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_groomed_corr_PUPPI" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("MET_pt_nom" , "F")
        self.out.branch("MET_phi_nom", "F")
        self.out.branch("%s_corr_JEC" % self.jetBranchName, "F", lenVar=self.lenVar)
                        
    def endFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        pass
    
    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        jets = Collection(event, self.jetBranchName )
        subJets = Collection(event, self.subJetBranchName )
        met = Object(event, "MET") 

        jets_pt_raw = []
        jets_pt_nom = []
        jets_mass_raw = []
        jets_mass_nom = []
        jets_msoftdrop_raw = []
        jets_msoftdrop_nom = []
        jets_groomed_corr_PUPPI = []
        jets_corr_JEC = []
        ( met_px,         met_py         ) = ( met.pt*math.cos(met.phi), met.pt*math.sin(met.phi) )
        ( met_px_nom, met_py_nom ) = ( met_px, met_py )
        met_px_nom = met_px
        met_py_nom = met_py
                
        rho = getattr(event, self.rhoBranchName)
        
        for jet in jets:            
            #jet pt and mass corrections
            jet_pt=jet.pt
            jet_mass=jet.mass

            #redo JECs if desired
            if hasattr(jet, "rawFactor"):
                jet_rawpt = jet_pt * (1 - jet.rawFactor)
                jet_rawmass = jet_mass * (1 - jet.rawFactor)
            else:
                jet_rawpt = -1.0 * jet_pt #If factor not present factor will be saved as -1
                jet_rawmass = -1.0 * jet_mass #If factor not present factor will be saved as -1
            if self.redoJEC :
                (jet_pt, jet_mass) = self.jetReCalibrator.correct(jet,rho)
            jets_pt_raw.append(jet_rawpt)
            jets_mass_raw.append(jet_rawmass)
            jets_corr_JEC.append(jet_pt/jet_rawpt)

            jet_pt_nom           = jet_pt # don't smear resolution in data
            if jet_pt_nom < 0.0:
                jet_pt_nom *= -1.0
            jets_pt_nom    .append(jet_pt_nom)

            jet_mass_nom         = jet_mass
            if jet_mass_nom < 0.0:
                jet_mass_nom *= -1.0
            jets_mass_nom    .append(jet_mass_nom)

            if jet_pt_nom > 15.:
                jet_cosPhi = math.cos(jet.phi)
                jet_sinPhi = math.sin(jet.phi)
                met_px_nom = met_px_nom - (jet_pt_nom - jet.pt)*jet_cosPhi
                met_py_nom = met_py_nom - (jet_pt_nom - jet.pt)*jet_sinPhi

            # Do PUPPI SD mass correction
            if jet.subJetIdx1 >= 0 and jet.subJetIdx2 >= 0 :
                groomedP4 = subJets[ jet.subJetIdx1 ].p4() + subJets[ jet.subJetIdx2].p4() #check subjet jecs
            else : groomedP4 = None

            jets_msoftdrop_raw.append(0.0) if groomedP4 == None else jets_msoftdrop_raw.append(groomedP4.M())

            puppisd_genCorr = self.puppisd_corrGEN.Eval(jet.pt)
            if abs(jet.eta) <= 1.3: puppisd_recoCorr = self.puppisd_corrRECO_cen.Eval(jet.pt)
            else: puppisd_recoCorr = self.puppisd_corrRECO_for.Eval(jet.pt)

            puppisd_total = puppisd_genCorr * puppisd_recoCorr
            if groomedP4 != None:
                groomedP4.SetPtEtaPhiM(groomedP4.Perp(), groomedP4.Eta(), groomedP4.Phi(), groomedP4.M()*puppisd_total)

            jets_groomed_corr_PUPPI.append(puppisd_total)
            jets_msoftdrop_nom.append(0.0) if groomedP4 == None else jets_msoftdrop_nom.append(groomedP4.M())


        self.out.fillBranch("%s_pt_raw" % self.jetBranchName, jets_pt_raw)
        self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom)
        self.out.fillBranch("%s_mass_raw" % self.jetBranchName, jets_mass_raw)
        self.out.fillBranch("%s_mass_nom" % self.jetBranchName, jets_mass_nom)
        self.out.fillBranch("%s_groomed_corr_PUPPI" % self.jetBranchName, jets_groomed_corr_PUPPI)
        self.out.fillBranch("%s_msoftdrop_raw" % self.jetBranchName, jets_msoftdrop_raw)
        self.out.fillBranch("%s_msoftdrop_nom" % self.jetBranchName, jets_msoftdrop_nom)
        self.out.fillBranch("MET_pt_nom", math.sqrt(met_px_nom**2 + met_py_nom**2))
        self.out.fillBranch("MET_phi_nom", math.atan2(met_py_nom, met_px_nom))        
        self.out.fillBranch("%s_corr_JEC" % self.jetBranchName, jets_corr_JEC)

        return True
Exemple #2
0
class susysinglelep(Module):
    def __init__(
            self, isMC, isSig, era, muonSelectionTag, electronSelectionTag,
            CorrMET
    ):  #, HTFilter, LTFilter):#, muonSelection, electronSelection):
        self.isMC = isMC
        self.isSig = isSig
        self.era = era
        self.muonSelectionTag = muonSelectionTag
        self.electronSelectionTag = electronSelectionTag
        self.CorrMET = CorrMET

        #self.HTFilt = HTFilter
        #self.LTFilt = LTFilter
        # smear jet pT to account for measured difference in JER between data and simulation.
        self.jerInputFileName = "Spring16_25nsV10_MC_PtResolution_AK4PFchs.txt"
        self.jerUncertaintyInputFileName = "Spring16_25nsV10_MC_SF_AK4PFchs.txt"
        ###################### LepSF, JECSFs and JERSF for 2017 era ###############################################################
        if self.era == "2016":
            self.btag_LooseWP = 0.5426
            self.btag_MediumWP = 0.8484
            self.btag_TightWP = 0.9535
            #https://twiki.cern.ch/twiki/bin/viewauth/CMS/BtagRecommendation80XReReco
            self.btag_DeepLooseWP = 0.2219
            self.btag_DeepMediumWP = 0.6324
            self.btag_DeepTightWP = 0.8958
            if self.isMC:
                if self.muonSelectionTag == "LooseWP_2016":
                    mu_f = ["Mu_Trg.root", "Mu_ID.root", "Mu_Iso.root"]
                    mu_h = [
                        "IsoMu24_OR_IsoTkMu24_PtEtaBins/pt_abseta_ratio",
                        "MC_NUM_LooseID_DEN_genTracks_PAR_pt_eta/pt_abseta_ratio",
                        "LooseISO_LooseID_pt_eta/pt_abseta_ratio"
                    ]
                if self.electronSelectionTag == "GPMVA90_2016":
                    el_f = ["EGM2D_eleGSF.root", "EGM2D_eleMVA90.root"]
                    el_h = ["EGamma_SF2D", "EGamma_SF2D"]
                if self.muonSelectionTag == "MediumWP_2016":
                    mu_f = ["Mu_Trg.root", "Mu_ID.root", "Mu_Iso.root"]
                    mu_h = [
                        "IsoMu24_OR_IsoTkMu24_PtEtaBins/pt_abseta_ratio",
                        "MC_NUM_MediumID_DEN_genTracks_PAR_pt_eta/pt_abseta_ratio",
                        "LooseISO_MediumID_pt_eta/pt_abseta_ratio"
                    ]
                if self.electronSelectionTag == "Tight_2016":
                    el_f = ["EGM2D_eleGSF.root", "EGM2D_eleMVA90.root"]
                    el_h = ["EGamma_SF2D", "EGamma_SF2D"]
            #self.jerUncertaintyInputFileName = "Spring16_25nsV10_MC_SF_AK4PFchs.txt"
            self.jetSmearer = jetSmearer("Summer16_23Sep2016V4_MC", "AK4PFchs",
                                         self.jerInputFileName,
                                         self.jerUncertaintyInputFileName)
        ###################### LepSF, JECSFs and JERSF for 2017 era ###############################################################
        elif self.era == "2017":
            self.btag_LooseWP = 0.5803
            self.btag_MediumWP = 0.8838
            self.btag_TightWP = 0.9693
            # DeepCSV (new Deep Flavour tagger)
            #https://twiki.cern.ch/twiki/bin/viewauth/CMS/BtagRecommendation94X
            self.btag_DeepLooseWP = 0.1522
            self.btag_DeepMediumWP = 0.4941
            self.btag_DeepTightWP = 0.8001
            if self.isMC:
                if self.muonSelectionTag == "LooseWP_2017":
                    mu_f = ["Mu_Trg17.root", "Mu_ID17.root", "Mu_Iso17.root"]
                    mu_h = [
                        "IsoMu27_PtEtaBins/pt_abseta_ratio",
                        "NUM_LooseID_DEN_genTracks_pt_abseta",
                        "NUM_LooseRelIso_DEN_LooseID_pt_abseta"
                    ]
                if self.electronSelectionTag == "GPMVA90_2017":
                    el_f = ["EGM2D_eleGSF17.root", "EGM2D_eleMVA90_17.root"]
                    el_h = ["EGamma_SF2D", "EGamma_SF2D"]
                if self.muonSelectionTag == "MediumWP_2017":
                    mu_f = ["Mu_Trg17.root", "Mu_ID17.root", "Mu_Iso17.root"]
                    mu_h = [
                        "IsoMu27_PtEtaBins/pt_abseta_ratio",
                        "NUM_MediumID_DEN_genTracks_pt_abseta",
                        "NUM_LooseRelIso_DEN_MediumID_pt_abseta"
                    ]
                if self.electronSelectionTag == "Tight_2017":
                    el_f = ["EGM2D_eleGSF17.root", "EGM2D_eleMVA90_17.root"]
                    el_h = ["EGamma_SF2D", "EGamma_SF2D"]
            # Temporarly use the jetmet uncertainty for 2016
            #self.jerUncertaintyInputFileName = "Spring16_25nsV10_MC_SF_AK4PFchs.txt"
            #self.jetSmearer = jetSmearer("Summer16_23Sep2016V4_MC", "AK4PFchs", self.jerInputFileName, self.jerUncertaintyInputFileName)
            #self.jerUncertaintyInputFileName = "Fall17_17Nov2017_V6_MC_Uncertainty_AK4PFchs.txt"
            self.jetSmearer = jetSmearer("Fall17_17Nov2017_V6_MC", "AK4PFchs",
                                         self.jerInputFileName,
                                         self.jerUncertaintyInputFileName)
        else:
            raise ValueError("ERROR: Invalid era = '%s'!" % self.era)
        if self.isMC:
            mu_f = [
                "%s/src/PhysicsTools/NanoAODTools/python/postprocessing/data/leptonSF/"
                % os.environ['CMSSW_BASE'] + f for f in mu_f
            ]
            el_f = [
                "%s/src/PhysicsTools/NanoAODTools/python/postprocessing/data/leptonSF/"
                % os.environ['CMSSW_BASE'] + f for f in el_f
            ]
            self.mu_f = ROOT.std.vector(str)(len(mu_f))
            self.mu_h = ROOT.std.vector(str)(len(mu_f))
            for i in range(len(mu_f)):
                self.mu_f[i] = mu_f[i]
                self.mu_h[i] = mu_h[i]
            self.el_f = ROOT.std.vector(str)(len(el_f))
            self.el_h = ROOT.std.vector(str)(len(el_f))
            for i in range(len(el_f)):
                self.el_f[i] = el_f[i]
                self.el_h[i] = el_h[i]
            self.jetReCalibrator = JetReCalibrator(
                "Fall17_17Nov2017_V6_MC",
                "AK4PFchs",
                True,
                os.environ['CMSSW_BASE'] +
                "/src/PhysicsTools/NanoAODTools/data/jme/",
                calculateSeparateCorrections=False,
                calculateType1METCorrection=False)
            self.unclEnThreshold = 15.

        if "/LeptonEfficiencyCorrector_cc.so" not in ROOT.gSystem.GetLibraries(
        ):
            print "Load C++ Worker"
            ROOT.gROOT.ProcessLine(
                ".L %s/src/PhysicsTools/NanoAODTools/python/postprocessing/helpers/LeptonEfficiencyCorrector.cc+"
                % os.environ['CMSSW_BASE'])
        pass

    def beginJob(self):
        self.jetSmearer.beginJob()
        if self.isMC:
            self._worker_mu = ROOT.LeptonEfficiencyCorrector(
                self.mu_f, self.mu_h)
            self._worker_el = ROOT.LeptonEfficiencyCorrector(
                self.el_f, self.el_h)
        pass

    def endJob(self):
        self.jetSmearer.endJob()
        pass

    def matchLeptons(self, event):
        def plausible(rec, gen):
            if abs(rec.pdgId) == 11 and abs(gen.pdgId) != 11: return False
            if abs(rec.pdgId) == 13 and abs(gen.pdgId) != 13: return False
            dr = deltaR(rec.etc, rec.phi, gen.eta, gen.phi)
            if dr < 0.3: return True
            if rec.pt < 10 and abs(rec.pdgId) == 13 and gen.pdgId != rec.pdgId:
                return False
            if dr < 0.7: return True
            if min(rec.pt, gen.pt) / max(rec.pt, gen.pt) < 0.3: return False
            return True

        leps = event.selectedLeptons
        match = matchObjectCollectionMultiple(leps,
                                              event.genleps + event.gentauleps,
                                              dRmax=1.2,
                                              presel=lambda plausible: True)
        for lep in leps:
            gen = match[lep]
            lep.mcMatchId = (gen.sourceId if gen != None else 0)
            lep.mcMatchTau = (gen in event.gentauleps if gen else -99)
            lep.mcLep = gen

    def beginFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        self.out = wrappedOutputTree
        self.out.branch("isData", "I")
        self.out.branch("nLep", "I")
        self.out.branch("nVeto", "I")
        self.out.branch("nEl", "I")
        self.out.branch("nMu", "I")
        self.out.branch("nTightLeps", "I")
        self.out.branch("nTightMu", "I")
        self.out.branch("nTightEl", "I")
        self.out.branch("tightLepsIdx", "I", 10, "nTightLeps")
        #("tightLeps_DescFlag","I",10,"nTightLeps"),
        self.out.branch("Lep_pdgId", "F")
        self.out.branch("Lep_pt", "F")
        self.out.branch("Lep_eta", "F")
        self.out.branch("Lep_phi", "F")
        self.out.branch("Lep_Idx", "I")
        self.out.branch("Lep_relIso", "F")
        self.out.branch("Lep_miniIso", "F")
        self.out.branch("Lep_hOverE", "F")
        self.out.branch("Selected", "I")
        # selected (tight) or anti-selected lepton
        # second leading lepton
        self.out.branch("Lep2_pt", "F")
        self.out.branch("Selected2", "I")
        self.out.branch("LT", "F")
        self.out.branch("ST", "F")
        self.out.branch("MT", "F")
        self.out.branch("DeltaPhiLepW", "F")
        self.out.branch("dPhi", "F")
        self.out.branch("Lp", "F")
        self.out.branch("GendPhi", "F")
        self.out.branch("GenLT", "F")
        self.out.branch("GenMET", "F")
        ## jets
        self.out.branch("ST1", "F")
        self.out.branch("HT1", "F")
        self.out.branch("HT", "F")
        #self.out.branch("HTphi","F");
        self.out.branch("nJets", "I")
        self.out.branch("nBJet", "I")
        self.out.branch("nBJetDeep", "I")
        self.out.branch("nJets30", "I")
        self.out.branch("Jets30Idx", "I", 50, "nJets30")
        self.out.branch("nBJets30", "I")
        self.out.branch("nJets30Clean", "I")
        self.out.branch("nJets40", "I")
        self.out.branch("nBJets40", "I")
        self.out.branch("htJet30j", "F")
        self.out.branch("htJet30ja", "F")
        self.out.branch("htJet40j", "F")
        self.out.branch("Jet1_pt", "F")
        self.out.branch("Jet2_pt", "F")
        self.out.branch("Jet1_eta", "F")
        self.out.branch("Jet2_eta", "F")
        ## top tags
        self.out.branch("nHighPtTopTag", "I")
        self.out.branch("nHighPtTopTagPlusTau23", "I")
        ## special Vars
        self.out.branch("LSLjetptGT80", "F")
        # leading + subl. jet pt > 80
        self.out.branch("isSR", "I")
        # is it Signal or Control region
        self.out.branch("Mll", "F")
        #di-lepton mass
        #self.out.branch("METfilters","I"); not needed for nanoAOD
        #Datasets
        self.out.branch("PD_JetHT", "O")
        self.out.branch("PD_SingleEle", "O")
        self.out.branch("PD_SingleMu", "O")
        self.out.branch("PD_MET", "O")

        self.out.branch("isDPhiSignal", "I")
        self.out.branch("RA2_muJetFilter", "I")
        self.out.branch("Flag_fastSimCorridorJetCleaning", "I")
        self.out.branch("minMWjj", "F")
        self.out.branch("minMWjjPt", "F")
        self.out.branch("bestMWjj", "F")
        self.out.branch("bestMWjjPt", "F")
        self.out.branch("bestMTopHad", "F")
        self.out.branch("bestMTopHadPt", "F")
        # self.out.branch("Jet_mhtCleaning", "b", lenVar="nJet")
        #Iso_track parameters
        self.out.branch("iso_had", "I")
        self.out.branch("iso_pt", "F")
        self.out.branch("iso_MT2", "F")
        self.out.branch("iso_Veto", "O")
        self.out.branch("nLepGood", "F")
        self.out.branch("nLepOther", "F")
        self.out.branch("LepGood_Cutbased", "I")
        self.out.branch("LepOther_Cutbased", "I")
        # Store the Xsec
        self.out.branch("Xsec", "F")
        self.xs = getXsec(inputFile.GetName())
        self.filename = inputFile.GetName()
        print inputFile.GetName()
        print self.xs

        self.out.branch("Muon_effSF", "F")
        self.out.branch("Electron_effSF", "F")
        self.out.branch("lepSF", "F")
        # only for checking the electron corr
        self.out.branch("TightEl_eCorr", "F")
        self.h_eCorr_vs_eta_tight = ROOT.TH2F("h_eCorr_vs_eta_tight",
                                              "eCorr_vs_eta", 25, 0, 5, 68, -3,
                                              3)
        self.h_eCorr_vs_phi_tight = ROOT.TH2F("h_eCorr_vs_phi_tight",
                                              "eCorr_vs_phi", 25, 0, 5, 140,
                                              -math.pi, math.pi)
        self.h_eCorr_vs_pt_tight = ROOT.TH2F("h_eCorr_vs_pt_tight",
                                             "eCorr_vs_pt", 25, 0, 5, 200, 0,
                                             200)
        self.h_eCorr_vs_eta = ROOT.TH2F("h_eCorr_vs_eta", "eCorr_vs_eta", 25,
                                        0, 30, 68, -3, 3)
        self.h_eCorr_vs_phi = ROOT.TH2F("h_eCorr_vs_phi", "eCorr_vs_phi", 25,
                                        0, 30, 140, -math.pi, math.pi)
        self.h_eCorr_vs_pt = ROOT.TH2F("h_eCorr_vs_pt", "eCorr_vs_pt", 25, 0,
                                       30, 200, 0, 200)
        self.h_eCorr_vs_eta_veto = ROOT.TH2F("h_eCorr_vs_eta_veto",
                                             "eCorr_vs_eta_veto", 25, 0, 5, 68,
                                             -3, 3)
        self.h_eCorr_vs_phi_veto = ROOT.TH2F("h_eCorr_vs_phi_veto",
                                             "eCorr_vs_phi_veto", 25, 0, 5,
                                             140, -math.pi, math.pi)
        self.h_eCorr_vs_pt_veto = ROOT.TH2F("h_eCorr_vs_pt_veto",
                                            "eCorr_vs_pt_veto", 25, 0, 5, 200,
                                            0, 200)
        self.out.branch("Met", "F")

    def endFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        outputFile.cd()
        self.h_eCorr_vs_eta_veto.Write()
        self.h_eCorr_vs_phi_veto.Write()
        self.h_eCorr_vs_pt_veto.Write()
        self.h_eCorr_vs_eta_tight.Write()
        self.h_eCorr_vs_phi_tight.Write()
        self.h_eCorr_vs_pt_tight.Write()
        self.h_eCorr_vs_eta.Write()
        self.h_eCorr_vs_phi.Write()
        self.h_eCorr_vs_pt.Write()
        pass

    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        leptonSel(event)
        for elect in event.allelectrons:
            self.h_eCorr_vs_eta.Fill(elect.eCorr, elect.eta)
            self.h_eCorr_vs_phi.Fill(elect.eCorr, elect.phi)
            self.h_eCorr_vs_pt.Fill(elect.eCorr, elect.pt)
        Jets = Collection(event, "Jet")
        met = Object(event, "MET")
        genmet = Object(event, "GenMET")
        if self.isMC or self.isSig:
            Gen = Collection(event, "GenPart")
            event.genleps = [
                l for l in Gen if abs(l.pdgId) == 11 or abs(l.pdgId) == 13
            ]
            GenTau = Collection(event, "GenVisTau")
            event.gentauleps = [l for l in GenTau]
        goodLep = [l for l in event.selectedLeptons]
        LepOther = [l for l in event.otherLeptons]
        self.out.fillBranch("nLepGood", len(goodLep))
        self.out.fillBranch("nLepOther", len(LepOther))

        #LepOther = goodLep
        leps = goodLep
        nlep = len(leps)
        # adding the ST HT filter
        if nlep > 0:
            ST1 = leps[0].pt + met.pt
            self.out.fillBranch("ST1", ST1)
        HT1 = sum([j.pt for j in Jets if (j.pt > 30 and abs(j.eta) < 2.4)])
        self.out.fillBranch("HT1", HT1)
        ### LEPTONS
        Selected = False
        if self.isMC == False and self.isSig == False:
            self.out.fillBranch("isData", 1)
        else:
            self.out.fillBranch("isData", 0)
        # selected good leptons
        selectedTightLeps = []
        selectedTightLepsIdx = []
        selectedVetoLeps = []

        # anti-selected leptons
        antiTightLeps = []
        antiTightLepsIdx = []
        antiVetoLeps = []
        for idx, lep in enumerate(leps):
            # for acceptance check
            lepEta = abs(lep.eta)
            # Pt cut
            if lep.pt < 10: continue

            # Iso cut -- to be compatible with the trigger
            if lep.miniPFRelIso_all > trig_miniIsoCut: continue
            ###################
            # MUONS
            ###################
            if (abs(lep.pdgId) == 13):
                if lepEta > 2.4: continue

                ## Lower ID is POG_LOOSE (see cfg)

                # ID, IP and Iso check:
                passID = False
                #if muID=='ICHEPmediumMuonId': passID = lep.ICHEPmediumMuonId -->> not needed any more
                passID = lep.mediumId
                passIso = lep.miniPFRelIso_all < muo_miniIsoCut
                passIP = lep.sip3d < goodMu_sip3d

                # selected muons
                if passID and passIso and passIP:
                    selectedTightLeps.append(lep)
                    selectedTightLepsIdx.append(idx)
                    antiVetoLeps.append(lep)
                else:
                    selectedVetoLeps.append(lep)
                # anti-selected muons
                if not passIso:
                    antiTightLeps.append(lep)
                    antiTightLepsIdx.append(idx)
                else:
                    antiVetoLeps.append(lep)

            ###################
            # ELECTRONS
            ###################

            elif (abs(lep.pdgId) == 11):

                if lepEta > eleEta: continue

                # pass variables
                passIso = False
                passConv = False

                if eleID == 'CB':
                    # ELE CutBased ID
                    eidCB = lep.cutBased

                    passTightID = (
                        eidCB == 4
                    )  # and abs(lep.dxy) < 0.05 and abs(lep.dz) < 0.1) # and lep.convVeto)
                    passMediumID = (
                        eidCB >= 3
                    )  # and abs(lep.dxy) < 0.05 and abs(lep.dz) < 0.1)# and lep.convVeto)
                    #passLooseID = (eidCB >= 2)
                    passVetoID = (
                        eidCB >= 1
                    )  # and abs(lep.dxy) < 0.2 and abs(lep.dz) < 0.5) # and lep.convVeto)
                # selected
                if passTightID:

                    # all tight leptons are veto for anti
                    antiVetoLeps.append(lep)

                    # Iso check:
                    if lep.miniPFRelIso_all < ele_miniIsoCut:
                        passIso = True
                        # conversion check
                    elif eleID == 'CB':
                        passConv = True  #if lep.lostHits <= goodEl_lostHits and lep.convVeto and lep.sip3d < goodEl_sip3d else False  # cuts already included in POG_Cuts_ID_SPRING15_25ns_v1_ConvVetoDxyDz_X

                    passPostICHEPHLTHOverE = True  #if (lep.hoe < 0.04 and abs(lep.eta)>1.479) or abs(lep.eta)<=1.479 else False

                    # fill
                    if passIso and passConv and passPostICHEPHLTHOverE:
                        selectedTightLeps.append(lep)
                        selectedTightLepsIdx.append(idx)
                    else:
                        selectedVetoLeps.append(lep)

                # anti-selected
                elif not passMediumID:  #passVetoID:

                    # all anti leptons are veto for selected
                    selectedVetoLeps.append(lep)

                    # Iso check
                    passIso = lep.miniPFRelIso_all < Lep_miniIsoCut  # should be true anyway
                    # other checks
                    passOther = False
                    if hasattr(lep, "hoe"):
                        passOther = lep.hoe > 0.01

                    # fill
                    if passIso and passOther:
                        antiTightLeps.append(lep)
                        antiTightLepsIdx.append(idx)
                    else:
                        antiVetoLeps.append(lep)
                # Veto leptons
                elif passVetoID:
                    # the rest is veto for selected and anti
                    selectedVetoLeps.append(lep)
                    antiVetoLeps.append(lep)
# end lepton loop

###################
# EXTRA Loop for lepOther -- for anti-selected leptons
###################

        otherleps = [
            l for l in LepOther
        ]  #(set(selectedTightLeps) or set(selectedVetoLeps) or set(antiTightLeps) or set(antiVetoLeps) )]
        nLepOther = len(otherleps)

        for idx, lep in enumerate(otherleps):
            # check acceptance
            lepEta = abs(lep.eta)
            if lepEta > 2.4: continue
            # Pt cut
            if lep.pt < 10: continue
            # Iso cut -- to be compatible with the trigger
            if lep.miniPFRelIso_all > trig_miniIsoCut: continue

            ############
            # Muons
            if (abs(lep.pdgId) == 13):
                ## Lower ID is POG_LOOSE (see cfg)

                # ID, IP and Iso check:
                passIso = lep.miniPFRelIso_all > muo_miniIsoCut
                #if passIso and passID and passIP:
                if passIso:
                    antiTightLeps.append(lep)
                    antiTightLepsIdx.append(idx)
                else:
                    antiVetoLeps.append(lep)

            ############
            # Electrons
            elif (abs(lep.pdgId) == 11):

                if (lepEta > eleEta): continue

                ## Iso selection: ele should have MiniIso < 0.4 (for trigger)
                if lep.miniPFRelIso_all > Lep_miniIsoCut: continue

                ## Set Ele IDs
                if eleID == 'CB':
                    # ELE CutBased ID
                    eidCB = lep.cutBased

                    passMediumID = (
                        eidCB >= 3
                    )  # and lep.convVeto and abs(lep.dxy) < 0.05 and abs(lep.dz) < 0.1)
                    passVetoID = (
                        eidCB >= 1
                    )  #and lep.convVeto and abs(lep.dxy) < 0.05 and abs(lep.dz) < 0.1)
                else:
                    passMediumID = False
                    passVetoID = False

                # Cuts for Anti-selected electrons
                if not passMediumID:
                    # should always be true for LepOther

                    # other checks
                    passOther = False
                    if hasattr(lep, "hoe"):
                        passOther = lep.hoe > 0.01

                    #if not lep.conVeto:
                    if passOther:
                        antiTightLeps.append(lep)
                        antiTightLepsIdx.append(idx)
                    else:
                        antiVetoLeps.append(lep)

                elif passVetoID:  #all Medium+ eles in LepOther
                    antiVetoLeps.append(lep)
#############
#############
    # retrive and fill branches
    #############
    # choose common lepton collection: select selected or anti lepton
        if len(selectedTightLeps) > 0:
            tightLeps = selectedTightLeps
            tightLepsIdx = selectedTightLepsIdx
            vetoLeps = selectedVetoLeps

            self.out.fillBranch("nTightLeps", len(tightLeps))
            self.out.fillBranch(
                "nTightMu", sum([abs(lep.pdgId) == 13 for lep in tightLeps]))

            self.out.fillBranch(
                "nTightEl", sum([abs(lep.pdgId) == 11 for lep in tightLeps]))
            self.out.fillBranch("tightLepsIdx", tightLepsIdx)

            self.out.fillBranch("Selected", 1)

            # Is second leading lepton selected, too?
            if len(selectedTightLeps) > 1:
                self.out.fillBranch("Selected2", 1)
            else:
                self.out.fillBranch("Selected2", 0)

        elif len(antiTightLeps) > 0:
            tightLeps = antiTightLeps
            tightLepsIdx = antiTightLepsIdx

            vetoLeps = antiVetoLeps

            self.out.fillBranch("nTightLeps", 0)
            self.out.fillBranch("nTightMu", 0)
            self.out.fillBranch("nTightEl", 0)
            self.out.fillBranch("tightLepsIdx", [])

            self.out.fillBranch("Selected", -1)

        else:
            tightLeps = []
            tightLepsIdx = []
            vetoLeps = []
            self.out.fillBranch("nTightLeps", 0)
            self.out.fillBranch("nTightMu", 0)
            self.out.fillBranch("nTightEl", 0)

            self.out.fillBranch("tightLepsIdx", [])

            self.out.fillBranch("Selected", 0)

    # store Tight and Veto lepton numbers
        self.out.fillBranch("nLep", len(tightLeps))
        self.out.fillBranch("nVeto", len(vetoLeps))

        # get number of tight el and mu
        tightEl = [lep for lep in tightLeps if abs(lep.pdgId) == 11]
        tightMu = [lep for lep in tightLeps if abs(lep.pdgId) == 13]
        VetoEl = [lep for lep in vetoLeps if abs(lep.pdgId) == 11]
        VetoMu = [lep for lep in vetoLeps if abs(lep.pdgId) == 13]
        self.out.fillBranch("nEl", len(tightEl))
        self.out.fillBranch("nMu", len(tightMu))
        for El in tightEl:
            # this branch is for investigating the electron energy calibraition
            self.out.fillBranch("TightEl_eCorr", El.eCorr)
            self.h_eCorr_vs_eta_tight.Fill(El.eCorr, El.eta)
            self.h_eCorr_vs_phi_tight.Fill(El.eCorr, El.phi)
            self.h_eCorr_vs_pt_tight.Fill(El.eCorr, El.pt)
        for El in VetoEl:
            self.h_eCorr_vs_eta_veto.Fill(El.eCorr, El.eta)
            self.h_eCorr_vs_phi_veto.Fill(El.eCorr, El.phi)
            self.h_eCorr_vs_pt_veto.Fill(El.eCorr, El.pt)

    # save leading lepton vars
        if len(tightLeps) > 0:  # leading tight lep
            self.out.fillBranch("Lep_Idx", tightLepsIdx[0])

            self.out.fillBranch("Lep_pt", tightLeps[0].pt)
            self.out.fillBranch("Lep_eta", tightLeps[0].eta)
            self.out.fillBranch("Lep_phi", tightLeps[0].phi)
            self.out.fillBranch("Lep_pdgId", tightLeps[0].pdgId)

            self.out.fillBranch("Lep_relIso", tightLeps[0].pfRelIso03_all)
            self.out.fillBranch("Lep_miniIso", tightLeps[0].miniPFRelIso_all)
            if hasattr(tightLeps[0], "hoe"):
                self.out.fillBranch("Lep_hOverE", tightLeps[0].hoe)
            if self.isMC:
                for tlep in tightLeps:
                    if abs(tlep.pdgId) == 13:
                        sf_mu = self._worker_mu.getSF(tlep.pdgId, tlep.pt,
                                                      tlep.eta)
                        self.out.fillBranch("lepSF", sf_mu)
                        self.out.fillBranch("Muon_effSF", sf_mu)
                    elif abs(tlep.pdgId) == 11:
                        sf_el = self._worker_el.getSF(tlep.pdgId, tlep.pt,
                                                      tlep.eta)
                        self.out.fillBranch("lepSF", sf_el)
                        self.out.fillBranch("Electron_effSF", sf_el)
                    else:
                        self.out.fillBranch("Muon_effSF", 1.0)
                        self.out.fillBranch("Electron_effSF", 1.0)
                        self.out.fillBranch("lepSF", 1.0)
            else:
                self.out.fillBranch("Muon_effSF", 1.0)
                self.out.fillBranch("Electron_effSF", 1.0)
                self.out.fillBranch("lepSF", 1.0)

        elif len(leps) > 0:  # fill it with leading lepton
            self.out.fillBranch("Lep_Idx", 0)

            self.out.fillBranch("Lep_pt", leps[0].pt)
            self.out.fillBranch("Lep_eta", leps[0].eta)
            self.out.fillBranch("Lep_phi", leps[0].phi)
            self.out.fillBranch("Lep_pdgId", leps[0].pdgId)

            self.out.fillBranch("Lep_relIso", leps[0].pfRelIso03_all)
            self.out.fillBranch("Lep_miniIso", leps[0].miniPFRelIso_all)
            if hasattr(leps[0], "hoe"):
                self.out.fillBranch("Lep_hOverE", leps[0].hoe)

    # save second leading lepton vars
        if len(tightLeps) > 1:  # 2nd tight lep
            self.out.fillBranch("Lep2_pt", tightLeps[1].pt)
#		print " Nlep : ", len(leps) , " nTightleps " , len(tightLeps), " nVetoLEp ", len(vetoLeps)
#####################################################################
#####################################################################
#################Jets, BJets, METS and filters ######################
#####################################################################
#####################################################################
########
### Jets
########
        metp4 = ROOT.TLorentzVector(0, 0, 0, 0)
        Genmetp4 = ROOT.TLorentzVector(0, 0, 0, 0)

        if self.isMC:
            Genmetp4.SetPtEtaPhiM(genmet.pt, 0, genmet.phi, 0)
    #self.out.fillBranch("MET", metp4.Pt())
        Jets = Collection(event, "Jet")
        jets = [j for j in Jets if j.pt > 20 and abs(j.eta) < 2.4]
        njet = len(jets)
        (met_px, met_py) = (met.pt * math.cos(met.phi),
                            met.pt * math.sin(met.phi))
        (met_px_nom, met_py_nom) = (met_px, met_py)
        # match reconstructed jets to generator level ones
        # (needed to evaluate JER scale factors and uncertainties)
        if self.isMC and self.CorrMET:
            rho = getattr(event, "fixedGridRhoFastjetAll")
            genJets = Collection(event, "GenJet")
            pairs = matchObjectCollection(Jets, genJets)
            for jet in jets:
                genJet = pairs[jet]
                (jet_pt_jerNomVal, jet_pt_jerUpVal,
                 jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt(
                     jet, genJet, rho)
                # exclude this from the JECs correction to follow the SUSY recipe, well see if it will slove the prefire issue
                if self.era == "2017":
                    if jet.pt < 75 and (2.0 < abs(jet.eta) < 3.0):
                        jet_pt = jet.pt * (1. - jet.rawFactor)
                    else:
                        jet_pt = self.jetReCalibrator.correct(jet, rho)
                else:
                    jet_pt = jet.pt
                jet_pt_nom = jet_pt_jerNomVal * jet_pt
                if jet_pt_nom < 0.0: jet_pt_nom *= -1.0
                jet_pt_jerUp = jet_pt_jerUpVal * jet_pt
                jet_pt_jerDown = jet_pt_jerDownVal * jet_pt
                # recalculate the MET after applying the JEC JER
                if jet_pt > 15.:
                    jet_cosPhi = math.cos(jet.phi)
                    jet_sinPhi = math.sin(jet.phi)
                    met_px_nom = met_px_nom - (jet_pt_nom -
                                               jet_pt) * jet_cosPhi
                    met_py_nom = met_py_nom - (jet_pt_nom -
                                               jet_pt) * jet_sinPhi
                    met_pt_nom = math.sqrt(met_px_nom**2 + met_py_nom**2)
                    met_phi_nom = math.atan2(met_py_nom, met_px_nom)
                    met.pt = met_pt_nom
                    met.phi = met_phi_nom
                # JECs already applied so apply only JER
                jet.pt = jet_pt_jerNomVal * jet.pt
                if jet.pt < 0.0: jet.pt *= -1.0

        metp4.SetPtEtaPhiM(
            met.pt, 0., met.phi,
            0.)  # only use met vector to derive transverse quantities)
        self.out.fillBranch("Met", met.pt)
        centralJet30 = []
        centralJet30idx = []
        centralJet40 = []
        cleanJets25 = []
        cleanJets25idx = []
        cleanJets = []
        cleanJetsidx = []
        # fill this flage but defults to 1 and then change it after the proper selection
        self.out.fillBranch("Flag_fastSimCorridorJetCleaning", 1)
        for i, j in enumerate(jets):
            # Cleaning up of fastsim jets (from "corridor" studies) https://twiki.cern.ch/twiki/bin/viewauth/CMS/SUSRecommendationsMoriond17#Cleaning_up_of_fastsim_jets_from
            if self.isSig:  #only check for signals (see condition check above)
                self.out.fillBranch("isDPhiSignal", 1)
                genj = pairs[j]
                if genj is not None:
                    if j.pt > 20 and abs(
                            j.eta) < 2.5 and (genj.pt == 0) and j.chHEF < 0.1:
                        self.out.fillBranch("Flag_fastSimCorridorJetCleaning",
                                            0)
            if j.pt > 25:
                cleanJets25.append(j)
                cleanJets25idx.append(j)
            if j.pt > 30 and abs(j.eta) < centralEta:
                centralJet30.append(j)
                centralJet30idx.append(i)
            if j.pt > 40 and abs(j.eta) < centralEta:
                centralJet40.append(j)

    # jets 30 (cmg cleaning only)
        nJetC = len(centralJet30)
        self.out.fillBranch("nJets", nJetC)
        self.out.fillBranch("nJets30", nJetC)
        # store indeces
        self.out.fillBranch("Jets30Idx", centralJet30idx)
        #print "nJets30:", len(centralJet30), " nIdx:", len(centralJet30idx)

        # jets 40
        nJet40C = len(centralJet40)
        self.out.fillBranch("nJets40", nJet40C)

        ##############################
        ## Local cleaning from leptons
        ##############################
        cJet30Clean = []
        dRminCut = 0.4

        # Do cleaning a la CMG: clean max 1 jet for each lepton (the nearest)
        cJet30Clean = centralJet30
        cleanJets30 = centralJet30
        #clean selected leptons at First
        '''for lep in goodLep:
			if lep.pt < 20 : continue 
			jNear, dRmin = None, 99
			# find nearest jet
			for jet in centralJet30:
				dR = jet.p4().DeltaR(lep.p4())
				if dR < dRmin:
					jNear, dRmin = jet, dR
			# remove nearest jet
			if dRmin < dRminCut:
				cJet30Clean.remove(jNear)'''
        #then clean other tight leptons
        for lep in tightLeps:
            # don't clean LepGood, only LepOther
            #if lep not in otherleps: continue
            jNear, dRmin = None, 99
            # find nearest jet
            for jet in centralJet30:
                dR = jet.p4().DeltaR(lep.p4())
                if dR < dRmin:
                    jNear, dRmin = jet, dR
            # remove nearest jet
            if dRmin < dRminCut:
                cJet30Clean.remove(jNear)
            for ijet, jet25 in enumerate(cleanJets25):
                dR = jet25.p4().DeltaR(lep.p4())
                if dR < dRmin:
                    cleanJets.append(jet25)
                    cleanJetsidx.append(ijet)
    # cleaned jets
        nJet30C = len(cJet30Clean)
        self.out.fillBranch("nJets30Clean", len(cJet30Clean))

        if nJet30C > 0:
            self.out.fillBranch("Jet1_pt", cJet30Clean[0].pt)
            self.out.fillBranch("Jet1_eta", cJet30Clean[0].eta)
        if nJet30C > 1:
            self.out.fillBranch("Jet2_pt", cJet30Clean[1].pt)
            self.out.fillBranch("Jet2_eta", cJet30Clean[1].eta)

    # imho, use Jet2_pt > 80 instead
        self.out.fillBranch(
            "LSLjetptGT80",
            1 if sum([j.pt > 80 for j in cJet30Clean]) >= 2 else 0)

        self.out.fillBranch("htJet30j", sum([j.pt for j in cJet30Clean]))
        self.out.fillBranch("htJet30ja",
                            sum([j.pt for j in jets if j.pt > 30]))

        self.out.fillBranch("htJet40j", sum([j.pt for j in centralJet40]))

        self.out.fillBranch("HT", sum([j.pt for j in cJet30Clean]))

        ## B tagging WPs for CSVv2 (CSV-IVF)
        ## from: https://twiki.cern.ch/twiki/bin/view/CMSPublic/SWGuideBTagging#Preliminary_working_or_operating
        # WP defined on top
        btagWP = self.btag_MediumWP
        btag_DeepMediumWP = self.btag_DeepMediumWP
        btag_LooseWP = self.btag_LooseWP

        BJetMedium30 = []
        BJetMedium40 = []

        nBJetDeep = 0

        for i, j in enumerate(cJet30Clean):
            if j.btagCSVV2 > btagWP:
                BJetMedium30.append(j)
            if (j.btagDeepB) > btag_DeepMediumWP:
                nBJetDeep += 1

        for i, j in enumerate(centralJet40):
            if j.btagCSVV2 > btagWP:
                BJetMedium40.append(j)

    # using cleaned collection!
        self.out.fillBranch("nBJet", len(BJetMedium30))
        self.out.fillBranch("nBJets30", len(BJetMedium30))

        self.out.fillBranch("nBJetDeep", nBJetDeep)

        # using normal collection
        self.out.fillBranch("nBJets40", len(BJetMedium40))

        ######
        # MET
        #####

        #####################################################################
        #####################################################################
        #################High level variables ###############################
        #####################################################################
        #####################################################################
        dPhiLepW = -999  # set default value to -999 to spot "empty" entries
        GendPhiLepW = -999  # set default value to -999 to spot "empty" entries
        # LT of lepton and MET
        LT = -999
        GenLT = -999
        Lp = -99
        MT = -99

        if len(tightLeps) >= 1:
            recoWp4 = tightLeps[0].p4() + metp4
            GenrecoWp4 = tightLeps[0].p4() + Genmetp4
            GendPhiLepW = tightLeps[0].p4().DeltaPhi(GenrecoWp4)
            GenLT = tightLeps[0].pt + Genmetp4.Pt()
            dPhiLepW = tightLeps[0].p4().DeltaPhi(recoWp4)
            LT = tightLeps[0].pt + metp4.Pt()
            Lp = tightLeps[0].pt / recoWp4.Pt() * math.cos(dPhiLepW)

            #MT = recoWp4.Mt() # doesn't work
            MT = math.sqrt(2 * metp4.Pt() * tightLeps[0].pt *
                           (1 - math.cos(dPhiLepW)))
        self.out.fillBranch("DeltaPhiLepW", dPhiLepW)
        dPhi = abs(dPhiLepW)  # nickname for absolute dPhiLepW
        self.out.fillBranch("dPhi", dPhi)
        self.out.fillBranch("ST", LT)
        self.out.fillBranch("LT", LT)
        self.out.fillBranch("Lp", Lp)
        self.out.fillBranch("MT", MT)
        self.out.fillBranch("GendPhi", abs(GendPhiLepW))
        self.out.fillBranch("GenLT", GenLT)
        self.out.fillBranch("GenMET", Genmetp4.Pt())

        #####################
        ## SIGNAL REGION FLAG
        #####################

        ## Signal region flag
        # isSR SR vs CR flag
        isSR = 0

        # 0-B SRs -- simplified dPhi
        if len(BJetMedium30) == 0:  # check the no. of Bjets
            if LT < 250: isSR = 0
            elif LT > 250: isSR = dPhi > 0.75
            # BLIND data
            if (not self.isMC) and nJet30C >= 5:
                isSR = -isSR

    # Multi-B SRs
        elif nJet30C < 99:
            if LT < 250: isSR = 0
            elif LT < 350: isSR = dPhi > 1.0
            elif LT < 600: isSR = dPhi > 0.75
            elif LT > 600: isSR = dPhi > 0.5

            # BLIND data
            if (not self.isMC) and nJet30C >= 6:
                isSR = -isSR

        self.out.fillBranch("isSR", isSR)

        #############
        ## Playground
        #############

        # di-lepton mass: opposite-sign, same flavour
        Mll = 0

        if len(tightLeps) > 1:

            lep1 = tightLeps[0]
            id1 = lep1.pdgId

            for lep2 in leps[1:]:
                if lep2.pdgId + lep1.pdgId == 0:
                    dilepP4 = lep1.p4() + lep2.p4()
                    Mll = dilepP4.M()

        self.out.fillBranch("Mll", Mll)

        # RA2 proposed filter
        self.out.fillBranch(
            "RA2_muJetFilter", True
        )  # normally true for now # don't know how to get the Muon energy fraction from EMEF
        #for j in cJet30Clean:
        #	if j.pt > 200 and j.chEmEF > 0.5 and abs(math.acos(math.cos(j.phi-metp4.Phi()))) > (math.pi - 0.4):
        #		self.out.fillBranch("RA2_muJetFilter", False)

        ## MET FILTERS for data looks like the met filters are applied already for nanoAOD
        #####################
        ## Top Tagging          ------->>>>>>. to be moved to different modules keep it commented here
        #####################
        lightJets = [j for j in cleanJets if not j.btagCSVV2 == btagWP]
        bjetsLoose = [j for j in cleanJets if j.btagCSVV2 == btag_LooseWP]
        minMWjj = 999
        minMWjjPt = 0
        bestMWjj = 0
        bestMWjjPt = 0
        bestMTopHad = 0
        bestMTopHadPt = 0
        for i1, j1 in enumerate(lightJets):
            for i2 in xrange(i1 + 1, len(lightJets)):
                j2 = lightJets[i2]
                jjp4 = j1.p4() + j2.p4()
                mjj = jjp4.M()
                if mjj > 30 and mjj < minMWjj:
                    minMWjj = mjj
                    minMWjjPt = jjp4.Pt()
                    self.out.fillBranch("minMWjj", minMWjj)
                    self.out.fillBranch("minMWjjPt", minMWjjPt)
                if abs(mjj - 80.4) < abs(bestMWjj - 80.4):
                    bestMWjj = mjj
                    bestMWjjPt = jjp4.Pt()
                    self.out.fillBranch("bestMWjj", bestMWjj)
                    self.out.fillBranch("bestMWjjPt", bestMWjjPt)
                    for bj in bjetsLoose:
                        if deltaR(bj.eta(), bj.phi(), j1.eta(),
                                  j1.phi()) < 0.1 or deltaR(
                                      bj.eta(), bj.phi(), j2.eta(),
                                      j2.phi()) < 0.1:
                            continue
                        tp4 = jjp4 + bj.p4()
                        mtop = tp4.M()
                        if abs(mtop - 172) < abs(bestMTopHad - 172):
                            bestMTopHad = mtop
                            bestMTopHadPt = tp4.Pt()
                            self.out.fillBranch("bestMTopHad", bestMTopHad)
                            self.out.fillBranch("bestMTopHadPt", bestMTopHadPt)


#####################################################################
#####################################################################
#################Fill MT2 here, not point to make a separate module##
#####################################################################
#####################################################################
# isolated tracks after basic selection (((pt>5 && (abs(pdgId) == 11 || abs(pdgId) == 13)) || pt > 10) && (abs(pdgId) < 15 || abs(eta) < 2.5) && abs(dxy) < 0.2 && abs(dz) < 0.1 && ((pfIsolationDR03().chargedHadronIso < 5 && pt < 25) || pfIsolationDR03().chargedHadronIso/pt < 0.2)) and lepton veto
# First check is the event has the IsoTrack or not
        if hasattr(event, "nIsoTrack"):
            trks = [j for j in Collection(event, "IsoTrack", "nIsoTrack")]
            tp4 = ROOT.TLorentzVector(0, 0, 0, 0)

            # min dR between good lep and iso track
            minDR = 0.1
            # MT2 cuts for hadronic and leptonic veto tracks
            hadMT2cut = 60
            lepMT2cut = 80
            if (len(tightLeps) >= 1) and len(trks) >= 1:
                for i, t in enumerate(trks):
                    # looking for opposite charged tracks
                    #if tightLeps[0].charge == t.charge: continue # not track charge is founded replace with the next copule of lines
                    if t.isHighPurityTrack == False: continue
                    #print t.miniPFRelIso_chg
                    # not track mass is founded
                    tp4.SetPtEtaPhiM(t.pt, t.eta, t.phi, 0.)
                    dR = tp4.DeltaR(tightLeps[0].p4())
                    if minDR > dR: continue
                    p1 = tightLeps[0].p4()
                    p2 = tp4
                    a = array.array('d', [p1.M(), p1.Px(), p1.Py()])
                    b = array.array('d', [p2.M(), p2.Px(), p2.Py()])
                    c = array.array('d', [metp4.M(), metp4.Px(), metp4.Py()])
                    mt2obj.set_momenta(a, b, c)
                    mt2obj.set_mn(0)
                    self.out.fillBranch("iso_MT2", mt2obj.get_mt2())
                    self.out.fillBranch("iso_pt", p2.Pt())
                    # cuts on MT2 as defined above
                    if abs(t.pdgId) > 10 and abs(t.pdgId) < 14:
                        self.out.fillBranch("iso_had", 0)  #leptonic
                        cut = lepMT2cut
                    else:
                        self.out.fillBranch("iso_had", 1)  #hadronic track
                        cut = hadMT2cut
                    if mt2obj.get_mt2() <= cut:
                        self.out.fillBranch("iso_Veto", True)
        self.out.fillBranch("Xsec", self.xs)
        if 'JetHT' in self.filename:
            self.out.fillBranch("PD_JetHT", True)
        else:
            self.out.fillBranch("PD_JetHT", False)
        if 'SingleEle' in self.filename:
            self.out.fillBranch("PD_SingleEle", True)
        else:
            self.out.fillBranch("PD_SingleEle", False)
        if 'SingleMu' in self.filename:
            self.out.fillBranch("PD_SingleMu", True)
        else:
            self.out.fillBranch("PD_SingleMu", False)
        if 'MET' in self.filename:
            self.out.fillBranch("PD_MET", True)
        else:
            self.out.fillBranch("PD_MET", False)
        return True
Exemple #3
0
class jetmetUncertaintiesProducer(Module):
    def __init__(self,
                 era,
                 globalTag,
                 jesUncertainties=["Total"],
                 jetType="AK4PFchs",
                 redoJEC=False,
                 noGroom=False):

        self.era = era
        self.redoJEC = redoJEC
        self.noGroom = noGroom
        #--------------------------------------------------------------------------------------------
        # CV: globalTag and jetType not yet used, as there is no consistent set of txt files for
        #     JES uncertainties and JER scale factors and uncertainties yet
        #--------------------------------------------------------------------------------------------

        self.jesUncertainties = jesUncertainties

        # smear jet pT to account for measured difference in JER between data and simulation.
        self.jerInputFileName = "Spring16_25nsV10_MC_PtResolution_" + jetType + ".txt"
        self.jerUncertaintyInputFileName = "Spring16_25nsV10_MC_SF_" + jetType + ".txt"
        self.jetSmearer = jetSmearer(globalTag, jetType, self.jerInputFileName,
                                     self.jerUncertaintyInputFileName)

        if "AK4" in jetType:
            self.jetBranchName = "Jet"
            self.genJetBranchName = "GenJet"
            self.genSubJetBranchName = None
            self.doGroomed = False
            self.corrMET = True
        elif "AK8" in jetType:
            self.jetBranchName = "FatJet"
            self.subJetBranchName = "SubJet"
            self.genJetBranchName = "GenJetAK8"
            self.genSubJetBranchName = "SubGenJetAK8"
            if not self.noGroom:
                self.doGroomed = True
            else:
                self.doGroomed = False
            self.corrMET = False
        else:
            raise ValueError("ERROR: Invalid jet type = '%s'!" % jetType)
        self.metBranchName = "MET"
        self.rhoBranchName = "fixedGridRhoFastjetAll"
        self.lenVar = "n" + self.jetBranchName
        # To do : change to real values
        self.jmsVals = [1.00, 0.99, 1.01]

        # read jet energy scale (JES) uncertainties
        # (downloaded from https://twiki.cern.ch/twiki/bin/view/CMS/JECDataMC )
        self.jesInputFilePath = os.environ[
            'CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/"
        if len(jesUncertainties) == 1 and jesUncertainties[0] == "Total":
            if self.era == "2016":
                self.jesUncertaintyInputFileName = "Summer16_23Sep2016V4_MC_Uncertainty_" + jetType + ".txt"
            elif self.era == "2017":
                self.jesUncertaintyInputFileName = "Fall17_17Nov2017_V6_MC_Uncertainty_" + jetType + ".txt"
            else:
                raise ValueError("ERROR: Invalid era = '%s'!" % self.era)
        else:
            if self.era == "2016":
                self.jesUncertaintyInputFileName = "Summer16_23Sep2016V4_MC_UncertaintySources_" + jetType + ".txt"
            elif self.era == "2017":
                self.jesUncertaintyInputFileName = "Fall17_17Nov2017_V6_MC_UncertaintySources_" + jetType + ".txt"
            else:
                raise ValueError("ERROR: Invalid era = '%s'!" % self.era)

        # read all uncertainty source names from the loaded file
        if jesUncertainties[0] == "All":
            with open(self.jesInputFilePath +
                      self.jesUncertaintyInputFileName) as f:
                lines = f.read().split("\n")
                sources = filter(
                    lambda x: x.startswith("[") and x.endswith("]"), lines)
                sources = map(lambda x: x[1:-1], sources)
                self.jesUncertainties = sources

        if self.redoJEC:
            self.jetReCalibrator = JetReCalibrator(
                globalTag,
                jetType,
                True,
                self.jesInputFilePath,
                calculateSeparateCorrections=False,
                calculateType1METCorrection=False)

        # define energy threshold below which jets are considered as "unclustered energy"
        # (cf. JetMETCorrections/Type1MET/python/correctionTermsPfMetType1Type2_cff.py )
        self.unclEnThreshold = 15.

        # load libraries for accessing JES scale factors and uncertainties from txt files
        for library in [
                "libCondFormatsJetMETObjects", "libPhysicsToolsNanoAODTools"
        ]:
            if library not in ROOT.gSystem.GetLibraries():
                print("Load Library '%s'" % library.replace("lib", ""))
                ROOT.gSystem.Load(library)

    def beginJob(self):

        print("Loading jet energy scale (JES) uncertainties from file '%s'" %
              os.path.join(self.jesInputFilePath,
                           self.jesUncertaintyInputFileName))
        #self.jesUncertainty = ROOT.JetCorrectionUncertainty(os.path.join(self.jesInputFilePath, self.jesUncertaintyInputFileName))

        self.jesUncertainty = {}
        # implementation didn't seem to work for factorized JEC, try again another way
        for jesUncertainty in self.jesUncertainties:
            jesUncertainty_label = jesUncertainty
            if self.era == "2016" and jesUncertainty == 'Total' and len(
                    self.jesUncertainties) == 1:
                jesUncertainty_label = ''
            pars = ROOT.JetCorrectorParameters(
                os.path.join(self.jesInputFilePath,
                             self.jesUncertaintyInputFileName),
                jesUncertainty_label)
            self.jesUncertainty[
                jesUncertainty] = ROOT.JetCorrectionUncertainty(pars)

        self.jetSmearer.beginJob()

    def endJob(self):

        self.jetSmearer.endJob()

    def beginFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        self.out = wrappedOutputTree
        self.out.branch("%s_pt_nom" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_mass_nom" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        if self.doGroomed:
            self.out.branch("%s_msoftdrop_nom" % self.jetBranchName,
                            "F",
                            lenVar=self.lenVar)

        if self.corrMET:
            self.out.branch("%s_pt_nom" % self.metBranchName, "F")
            self.out.branch("%s_phi_nom" % self.metBranchName, "F")

        for shift in ["Up", "Down"]:
            self.out.branch("%s_pt_jer%s" % (self.jetBranchName, shift),
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_mass_jer%s" % (self.jetBranchName, shift),
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_mass_jmr%s" % (self.jetBranchName, shift),
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_mass_jms%s" % (self.jetBranchName, shift),
                            "F",
                            lenVar=self.lenVar)

            if self.doGroomed:
                self.out.branch("%s_msoftdrop_jer%s" %
                                (self.jetBranchName, shift),
                                "F",
                                lenVar=self.lenVar)
                self.out.branch("%s_msoftdrop_jmr%s" %
                                (self.jetBranchName, shift),
                                "F",
                                lenVar=self.lenVar)
                self.out.branch("%s_msoftdrop_jms%s" %
                                (self.jetBranchName, shift),
                                "F",
                                lenVar=self.lenVar)

            if self.corrMET:
                self.out.branch("%s_pt_jer%s" % (self.metBranchName, shift),
                                "F")
                self.out.branch("%s_phi_jer%s" % (self.metBranchName, shift),
                                "F")
            for jesUncertainty in self.jesUncertainties:
                self.out.branch("%s_pt_jes%s%s" %
                                (self.jetBranchName, jesUncertainty, shift),
                                "F",
                                lenVar=self.lenVar)
                self.out.branch("%s_mass_jes%s%s" %
                                (self.jetBranchName, jesUncertainty, shift),
                                "F",
                                lenVar=self.lenVar)
                if self.doGroomed:
                    self.out.branch(
                        "%s_msoftdrop_jes%s%s" %
                        (self.jetBranchName, jesUncertainty, shift),
                        "F",
                        lenVar=self.lenVar)
                if self.corrMET:
                    self.out.branch(
                        "%s_pt_jes%s%s" %
                        (self.metBranchName, jesUncertainty, shift), "F")
                    self.out.branch(
                        "%s_phi_jes%s%s" %
                        (self.metBranchName, jesUncertainty, shift), "F")
            if self.corrMET:
                self.out.branch(
                    "%s_pt_unclustEn%s" % (self.metBranchName, shift), "F")
                self.out.branch(
                    "%s_phi_unclustEn%s" % (self.metBranchName, shift), "F")

    def endFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        pass

    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        jets = Collection(event, self.jetBranchName)
        genJets = Collection(event, self.genJetBranchName)

        if self.doGroomed:
            subJets = Collection(event, self.subJetBranchName)
            genSubJets = Collection(event, self.genSubJetBranchName)
            genSubJetMatcher = matchObjectCollectionMultiple(genJets,
                                                             genSubJets,
                                                             dRmax=0.8)

        jets_pt_nom = []
        jets_pt_jerUp = []
        jets_pt_jerDown = []
        jets_pt_jesUp = {}
        jets_pt_jesDown = {}
        jets_mass_nom = []
        jets_mass_jerUp = []
        jets_mass_jerDown = []
        jets_mass_jmrUp = []
        jets_mass_jmrDown = []
        jets_mass_jesUp = {}
        jets_mass_jesDown = {}
        jets_mass_jmsUp = []
        jets_mass_jmsDown = []
        for jesUncertainty in self.jesUncertainties:
            jets_pt_jesUp[jesUncertainty] = []
            jets_pt_jesDown[jesUncertainty] = []
            jets_mass_jesUp[jesUncertainty] = []
            jets_mass_jesDown[jesUncertainty] = []

        if self.corrMET:
            met = Object(event, self.metBranchName)
            (met_px, met_py) = (met.pt * math.cos(met.phi),
                                met.pt * math.sin(met.phi))
            (met_px_nom, met_py_nom) = (met_px, met_py)
            (met_px_jerUp, met_py_jerUp) = (met_px, met_py)
            (met_px_jerDown, met_py_jerDown) = (met_px, met_py)
            (met_px_jesUp, met_py_jesUp) = ({}, {})
            (met_px_jesDown, met_py_jesDown) = ({}, {})
            for jesUncertainty in self.jesUncertainties:
                met_px_jesUp[jesUncertainty] = met_px
                met_py_jesUp[jesUncertainty] = met_py
                met_px_jesDown[jesUncertainty] = met_px
                met_py_jesDown[jesUncertainty] = met_py

        if self.doGroomed:
            jets_msdcorr_nom = []
            jets_msdcorr_jerUp = []
            jets_msdcorr_jerDown = []
            jets_msdcorr_jmrUp = []
            jets_msdcorr_jmrDown = []
            jets_msdcorr_jesUp = {}
            jets_msdcorr_jesDown = {}
            jets_msdcorr_jmsUp = []
            jets_msdcorr_jmsDown = []
            for jesUncertainty in self.jesUncertainties:
                jets_msdcorr_jesUp[jesUncertainty] = []
                jets_msdcorr_jesDown[jesUncertainty] = []

        rho = getattr(event, self.rhoBranchName)

        # match reconstructed jets to generator level ones
        # (needed to evaluate JER scale factors and uncertainties)
        pairs = matchObjectCollection(jets, genJets)

        for jet in jets:
            genJet = pairs[jet]
            if self.doGroomed:
                genGroomedSubJets = genSubJetMatcher[
                    genJet] if genJet != None else None
                genGroomedJet = genGroomedSubJets[0].p4() + genGroomedSubJets[
                    1].p4() if genGroomedSubJets != None and len(
                        genGroomedSubJets) >= 2 else None
                if jet.subJetIdx1 >= 0 and jet.subJetIdx2 >= 0:
                    groomedP4 = subJets[jet.subJetIdx1].p4() + subJets[
                        jet.subJetIdx2].p4()
                else:
                    groomedP4 = None

            # evaluate JER scale factors and uncertainties
            # (cf. https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution and https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyResolution )
            (jet_pt_jerNomVal, jet_pt_jerUpVal,
             jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt(
                 jet, genJet, rho)

            jet_pt = jet.pt
            if self.redoJEC:
                jet_pt = self.jetReCalibrator.correct(jet, rho)
            jet_pt_nom = jet_pt_jerNomVal * jet_pt
            if jet_pt_nom < 0.0:
                jet_pt_nom *= -1.0
            jet_pt_jerUp = jet_pt_jerUpVal * jet_pt
            jet_pt_jerDown = jet_pt_jerDownVal * jet_pt
            jets_pt_nom.append(jet_pt_nom)
            jets_pt_jerUp.append(jet_pt_jerUpVal * jet_pt)
            jets_pt_jerDown.append(jet_pt_jerDownVal * jet_pt)
            # evaluate JES uncertainties
            jet_pt_jesUp = {}
            jet_pt_jesDown = {}
            jet_mass_jesUp = {}
            jet_mass_jesDown = {}
            jet_mass_jmsUp = []
            jet_mass_jmsDown = []

            # Evaluate JMS and JMR scale factors and uncertainties
            jmsNomVal = self.jmsVals[0]
            jmsDownVal = self.jmsVals[1]
            jmsUpVal = self.jmsVals[2]
            (jet_mass_jmrNomVal, jet_mass_jmrUpVal,
             jet_mass_jmrDownVal) = self.jetSmearer.getSmearValsM(jet, genJet)
            jet_mass_nom = jet_pt_jerNomVal * jet_mass_jmrNomVal * jmsNomVal * jet.mass
            if jet_mass_nom < 0.0:
                jet_mass_nom *= -1.0
            jets_mass_nom.append(jet_mass_nom)
            jets_mass_jerUp.append(jet_pt_jerUpVal * jet_mass_jmrNomVal *
                                   jmsNomVal * jet.mass)
            jets_mass_jerDown.append(jet_pt_jerDownVal * jet_mass_jmrNomVal *
                                     jmsNomVal * jet.mass)
            jets_mass_jmrUp.append(jet_pt_jerNomVal * jet_mass_jmrUpVal *
                                   jmsNomVal * jet.mass)
            jets_mass_jmrDown.append(jet_pt_jerNomVal * jet_mass_jmrDownVal *
                                     jmsNomVal * jet.mass)
            jets_mass_jmsUp.append(jet_pt_jerNomVal * jet_mass_jmrNomVal *
                                   jmsUpVal * jet.mass)
            jets_mass_jmsDown.append(jet_pt_jerNomVal * jet_mass_jmrNomVal *
                                     jmsDownVal * jet.mass)

            if self.doGroomed:
                # to evaluate JES uncertainties
                jet_msdcorr_jmsUp = []
                jet_msdcorr_jmsDown = []
                jet_msdcorr_jesUp = {}
                jet_msdcorr_jesDown = {}

                (jet_msdcorr_jmrNomVal, jet_msdcorr_jmrUpVal,
                 jet_msdcorr_jmrDownVal) = self.jetSmearer.getSmearValsM(
                     groomedP4, genGroomedJet
                 ) if groomedP4 != None and genGroomedJet != None else (0., 0.,
                                                                        0.)
                jet_msdcorr_raw = groomedP4.M() if groomedP4 != None else 0.0
                if jet_msdcorr_raw < 0.0:
                    jet_msdcorr_raw *= -1.0
                jet_msdcorr_nom = jet_pt_jerNomVal * jet_msdcorr_jmrNomVal * jet_msdcorr_raw
                jets_msdcorr_nom.append(jet_msdcorr_nom)
                jets_msdcorr_jerUp.append(jet_pt_jerUpVal *
                                          jet_msdcorr_jmrNomVal * jmsNomVal *
                                          jet_msdcorr_raw)
                jets_msdcorr_jerDown.append(jet_pt_jerDownVal *
                                            jet_msdcorr_jmrNomVal * jmsNomVal *
                                            jet_msdcorr_raw)
                jets_msdcorr_jmrUp.append(jet_pt_jerNomVal *
                                          jet_msdcorr_jmrUpVal * jmsNomVal *
                                          jet_msdcorr_raw)
                jets_msdcorr_jmrDown.append(
                    jet_pt_jerNomVal * jet_msdcorr_jmrDownVal * jmsNomVal *
                    jet_msdcorr_raw)
                jets_msdcorr_jmsUp.append(jet_pt_jerNomVal *
                                          jet_msdcorr_jmrNomVal * jmsUpVal *
                                          jet_msdcorr_raw)
                jets_msdcorr_jmsDown.append(
                    jet_pt_jerNomVal * jet_msdcorr_jmrNomVal * jmsDownVal *
                    jet_msdcorr_raw)

            for jesUncertainty in self.jesUncertainties:
                # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties )
                self.jesUncertainty[jesUncertainty].setJetPt(jet_pt_nom)
                self.jesUncertainty[jesUncertainty].setJetEta(jet.eta)
                delta = self.jesUncertainty[jesUncertainty].getUncertainty(
                    True)
                jet_pt_jesUp[jesUncertainty] = jet_pt_nom * (1. + delta)
                jet_pt_jesDown[jesUncertainty] = jet_pt_nom * (1. - delta)
                jets_pt_jesUp[jesUncertainty].append(
                    jet_pt_jesUp[jesUncertainty])
                jets_pt_jesDown[jesUncertainty].append(
                    jet_pt_jesDown[jesUncertainty])
                jet_mass_jesUp[jesUncertainty] = jet_mass_nom * (1. + delta)
                jet_mass_jesDown[jesUncertainty] = jet_mass_nom * (1. - delta)
                jets_mass_jesUp[jesUncertainty].append(
                    jet_mass_jesUp[jesUncertainty])
                jets_mass_jesDown[jesUncertainty].append(
                    jet_mass_jesDown[jesUncertainty])
                if self.doGroomed:
                    jet_msdcorr_jesUp[jesUncertainty] = jet_msdcorr_nom * (
                        1. + delta)
                    jet_msdcorr_jesDown[jesUncertainty] = jet_msdcorr_nom * (
                        1. - delta)
                    jets_msdcorr_jesUp[jesUncertainty].append(
                        jet_msdcorr_jesUp[jesUncertainty])
                    jets_msdcorr_jesDown[jesUncertainty].append(
                        jet_msdcorr_jesDown[jesUncertainty])

            # progate JER and JES corrections and uncertainties to MET
            if self.corrMET and jet_pt_nom > self.unclEnThreshold:
                jet_cosPhi = math.cos(jet.phi)
                jet_sinPhi = math.sin(jet.phi)
                met_px_nom = met_px_nom - (jet_pt_nom - jet_pt) * jet_cosPhi
                met_py_nom = met_py_nom - (jet_pt_nom - jet_pt) * jet_sinPhi
                met_px_jerUp = met_px_jerUp - (jet_pt_jerUp -
                                               jet_pt_nom) * jet_cosPhi
                met_py_jerUp = met_py_jerUp - (jet_pt_jerUp -
                                               jet_pt_nom) * jet_sinPhi
                met_px_jerDown = met_px_jerDown - (jet_pt_jerDown -
                                                   jet_pt_nom) * jet_cosPhi
                met_py_jerDown = met_py_jerDown - (jet_pt_jerDown -
                                                   jet_pt_nom) * jet_sinPhi
                for jesUncertainty in self.jesUncertainties:
                    met_px_jesUp[jesUncertainty] = met_px_jesUp[
                        jesUncertainty] - (jet_pt_jesUp[jesUncertainty] -
                                           jet_pt_nom) * jet_cosPhi
                    met_py_jesUp[jesUncertainty] = met_py_jesUp[
                        jesUncertainty] - (jet_pt_jesUp[jesUncertainty] -
                                           jet_pt_nom) * jet_sinPhi
                    met_px_jesDown[jesUncertainty] = met_px_jesDown[
                        jesUncertainty] - (jet_pt_jesDown[jesUncertainty] -
                                           jet_pt_nom) * jet_cosPhi
                    met_py_jesDown[jesUncertainty] = met_py_jesDown[
                        jesUncertainty] - (jet_pt_jesDown[jesUncertainty] -
                                           jet_pt_nom) * jet_sinPhi

        # propagate "unclustered energy" uncertainty to MET
        if self.corrMET:
            (met_px_unclEnUp, met_py_unclEnUp) = (met_px, met_py)
            (met_px_unclEnDown, met_py_unclEnDown) = (met_px, met_py)
            met_deltaPx_unclEn = getattr(
                event, self.metBranchName + "_MetUnclustEnUpDeltaX")
            met_deltaPy_unclEn = getattr(
                event, self.metBranchName + "_MetUnclustEnUpDeltaY")
            met_px_unclEnUp = met_px_unclEnUp + met_deltaPx_unclEn
            met_py_unclEnUp = met_py_unclEnUp + met_deltaPy_unclEn
            met_px_unclEnDown = met_px_unclEnDown - met_deltaPx_unclEn
            met_py_unclEnDown = met_py_unclEnDown - met_deltaPy_unclEn

            # propagate effect of jet energy smearing to MET
            met_px_jerUp = met_px_jerUp + (met_px_nom - met_px)
            met_py_jerUp = met_py_jerUp + (met_py_nom - met_py)
            met_px_jerDown = met_px_jerDown + (met_px_nom - met_px)
            met_py_jerDown = met_py_jerDown + (met_py_nom - met_py)
            for jesUncertainty in self.jesUncertainties:
                met_px_jesUp[jesUncertainty] = met_px_jesUp[jesUncertainty] + (
                    met_px_nom - met_px)
                met_py_jesUp[jesUncertainty] = met_py_jesUp[jesUncertainty] + (
                    met_py_nom - met_py)
                met_px_jesDown[jesUncertainty] = met_px_jesDown[
                    jesUncertainty] + (met_px_nom - met_px)
                met_py_jesDown[jesUncertainty] = met_py_jesDown[
                    jesUncertainty] + (met_py_nom - met_py)
            met_px_unclEnUp = met_px_unclEnUp + (met_px_nom - met_px)
            met_py_unclEnUp = met_py_unclEnUp + (met_py_nom - met_py)
            met_px_unclEnDown = met_px_unclEnDown + (met_px_nom - met_px)
            met_py_unclEnDown = met_py_unclEnDown + (met_py_nom - met_py)

        self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom)
        self.out.fillBranch("%s_pt_jerUp" % self.jetBranchName, jets_pt_jerUp)
        self.out.fillBranch("%s_pt_jerDown" % self.jetBranchName,
                            jets_pt_jerDown)
        self.out.fillBranch("%s_mass_nom" % self.jetBranchName, jets_mass_nom)
        self.out.fillBranch("%s_mass_jerUp" % self.jetBranchName,
                            jets_mass_jerUp)
        self.out.fillBranch("%s_mass_jerDown" % self.jetBranchName,
                            jets_mass_jerDown)
        self.out.fillBranch("%s_mass_jmrUp" % self.jetBranchName,
                            jets_mass_jmrUp)
        self.out.fillBranch("%s_mass_jmrDown" % self.jetBranchName,
                            jets_mass_jmrDown)
        self.out.fillBranch("%s_mass_jmsUp" % self.jetBranchName,
                            jets_mass_jmsUp)
        self.out.fillBranch("%s_mass_jmsDown" % self.jetBranchName,
                            jets_mass_jmsDown)

        if self.doGroomed:

            self.out.fillBranch("%s_msoftdrop_nom" % self.jetBranchName,
                                jets_msdcorr_nom)
            self.out.fillBranch("%s_msoftdrop_jerUp" % self.jetBranchName,
                                jets_msdcorr_jerUp)
            self.out.fillBranch("%s_msoftdrop_jerDown" % self.jetBranchName,
                                jets_msdcorr_jerDown)
            self.out.fillBranch("%s_msoftdrop_jmrUp" % self.jetBranchName,
                                jets_msdcorr_jmrUp)
            self.out.fillBranch("%s_msoftdrop_jmrDown" % self.jetBranchName,
                                jets_msdcorr_jmrDown)
            self.out.fillBranch("%s_msoftdrop_jmsUp" % self.jetBranchName,
                                jets_msdcorr_jmsUp)
            self.out.fillBranch("%s_msoftdrop_jmsDown" % self.jetBranchName,
                                jets_msdcorr_jmsDown)

        if self.corrMET:
            self.out.fillBranch("%s_pt_nom" % self.metBranchName,
                                math.sqrt(met_px_nom**2 + met_py_nom**2))
            self.out.fillBranch("%s_phi_nom" % self.metBranchName,
                                math.atan2(met_py_nom, met_px_nom))
            self.out.fillBranch("%s_pt_jerUp" % self.metBranchName,
                                math.sqrt(met_px_jerUp**2 + met_py_jerUp**2))
            self.out.fillBranch("%s_phi_jerUp" % self.metBranchName,
                                math.atan2(met_py_jerUp, met_px_jerUp))
            self.out.fillBranch(
                "%s_pt_jerDown" % self.metBranchName,
                math.sqrt(met_px_jerDown**2 + met_py_jerDown**2))
            self.out.fillBranch("%s_phi_jerDown" % self.metBranchName,
                                math.atan2(met_py_jerDown, met_px_jerDown))

        for jesUncertainty in self.jesUncertainties:
            self.out.fillBranch(
                "%s_pt_jes%sUp" % (self.jetBranchName, jesUncertainty),
                jets_pt_jesUp[jesUncertainty])
            self.out.fillBranch(
                "%s_pt_jes%sDown" % (self.jetBranchName, jesUncertainty),
                jets_pt_jesDown[jesUncertainty])
            self.out.fillBranch(
                "%s_mass_jes%sUp" % (self.jetBranchName, jesUncertainty),
                jets_mass_jesUp[jesUncertainty])
            self.out.fillBranch(
                "%s_mass_jes%sDown" % (self.jetBranchName, jesUncertainty),
                jets_mass_jesDown[jesUncertainty])

            if self.doGroomed:
                self.out.fillBranch(
                    "%s_msoftdrop_jes%sUp" %
                    (self.jetBranchName, jesUncertainty),
                    jets_msdcorr_jesUp[jesUncertainty])
                self.out.fillBranch(
                    "%s_msoftdrop_jes%sDown" %
                    (self.jetBranchName, jesUncertainty),
                    jets_msdcorr_jesDown[jesUncertainty])

            if self.corrMET:
                self.out.fillBranch(
                    "%s_pt_jes%sUp" % (self.metBranchName, jesUncertainty),
                    math.sqrt(met_px_jesUp[jesUncertainty]**2 +
                              met_py_jesUp[jesUncertainty]**2))
                self.out.fillBranch(
                    "%s_phi_jes%sUp" % (self.metBranchName, jesUncertainty),
                    math.atan2(met_py_jesUp[jesUncertainty],
                               met_px_jesUp[jesUncertainty]))
                self.out.fillBranch(
                    "%s_pt_jes%sDown" % (self.metBranchName, jesUncertainty),
                    math.sqrt(met_px_jesDown[jesUncertainty]**2 +
                              met_py_jesDown[jesUncertainty]**2))
                self.out.fillBranch(
                    "%s_phi_jes%sDown" % (self.metBranchName, jesUncertainty),
                    math.atan2(met_py_jesDown[jesUncertainty],
                               met_px_jesDown[jesUncertainty]))
        if self.corrMET:
            self.out.fillBranch(
                "%s_pt_unclustEnUp" % self.metBranchName,
                math.sqrt(met_px_unclEnUp**2 + met_py_unclEnUp**2))
            self.out.fillBranch("%s_phi_unclustEnUp" % self.metBranchName,
                                math.atan2(met_py_unclEnUp, met_px_unclEnUp))
            self.out.fillBranch(
                "%s_pt_unclustEnDown" % self.metBranchName,
                math.sqrt(met_px_unclEnDown**2 + met_py_unclEnDown**2))
            self.out.fillBranch(
                "%s_phi_unclustEnDown" % self.metBranchName,
                math.atan2(met_py_unclEnDown, met_px_unclEnDown))

        return True
class fatJetUncertaintiesProducer(Module):
    def __init__(self,
                 era,
                 globalTag,
                 jesUncertainties=["Total"],
                 archive=None,
                 jetType="AK8PFPuppi",
                 noGroom=False,
                 jerTag="",
                 jmrVals=[],
                 jmsVals=[],
                 isData=False,
                 applySmearing=True,
                 applyHEMfix=False,
                 splitJER=False):
        self.era = era
        self.noGroom = noGroom
        self.isData = isData
        self.applySmearing = applySmearing if not isData else False  # don't smear for data
        # ---------------------------------------------------------------------
        # CV: globalTag and jetType not yet used in the jet smearer, as there
        # is no consistent set of txt files for JES uncertainties and JER scale
        # factors and uncertainties yet
        # ---------------------------------------------------------------------
        self.splitJER = splitJER
        if self.splitJER:
            self.splitJERIDs = list(range(6))
        else:
            self.splitJERIDs = [""]  # "empty" ID for the overall JER

        self.jesUncertainties = jesUncertainties
        # smear jet pT to account for measured difference in JER between data
        # and simulation.
        if jerTag != "":
            self.jerInputFileName = jerTag + "_PtResolution_" + jetType + ".txt"
            self.jerUncertaintyInputFileName = jerTag + "_SF_" + jetType + ".txt"
        else:
            print("WARNING: jerTag is empty!!! This module will soon be "
                  "deprecated! Please use jetmetHelperRun2 in the future.")
            if era == "2016":
                self.jerInputFileName = ''.join(
                    ["Summer16_25nsV1_MC_PtResolution_", jetType, ".txt"])
                self.jerUncertaintyInputFileName = ''.join(
                    ["Summer16_25nsV1_MC_SF_", jetType, ".txt"])
            elif era == "2017" or era == "2018":
                # use Fall17 as temporary placeholder until
                # post-Moriond 2019 JERs are out
                self.jerInputFileName = ''.join(
                    ["Fall17_V3_MC_PtResolution_", jetType, ".txt"])
                self.jerUncertaintyInputFileName = ''.join(
                    ["Fall17_V3_MC_SF_", jetType, ".txt"])

        # jet mass resolution: https://twiki.cern.ch/twiki/bin/view/CMS/JetWtagging
        self.jmrVals = jmrVals
        if not self.jmrVals:
            print("WARNING: jmrVals is empty!!! Using default values. This "
                  "module will soon be deprecated! Please use "
                  "jetmetHelperRun2 in the future.")
            self.jmrVals = [1.0, 1.2, 0.8]  # nominal, up, down
            # Use 2017 values for 2018 until 2018 are released
            if self.era in ["2017", "2018"]:
                self.jmrVals = [1.09, 1.14, 1.04]

        self.jetSmearer = jetSmearer(globalTag, jetType, self.jerInputFileName,
                                     self.jerUncertaintyInputFileName,
                                     self.jmrVals)

        if "AK4" in jetType:
            self.jetBranchName = "Jet"
            self.genJetBranchName = "GenJet"
            self.genSubJetBranchName = None
            self.doGroomed = False
        elif "AK8" in jetType:
            self.jetBranchName = "FatJet"
            self.subJetBranchName = "SubJet"
            self.genJetBranchName = "GenJetAK8"
            self.genSubJetBranchName = "SubGenJetAK8"
            if not self.noGroom:
                self.doGroomed = True
                self.puppiCorrFile = ROOT.TFile.Open(
                    os.environ['CMSSW_BASE'] +
                    "/src/PhysicsTools/NanoAODTools/data/jme/puppiCorr.root")
                self.puppisd_corrGEN = self.puppiCorrFile.Get(
                    "puppiJECcorr_gen")
                self.puppisd_corrRECO_cen = self.puppiCorrFile.Get(
                    "puppiJECcorr_reco_0eta1v3")
                self.puppisd_corrRECO_for = self.puppiCorrFile.Get(
                    "puppiJECcorr_reco_1v3eta2v5")
            else:
                self.doGroomed = False
        else:
            raise ValueError("ERROR: Invalid jet type = '%s'!" % jetType)
        self.rhoBranchName = "fixedGridRhoFastjetAll"
        self.lenVar = "n" + self.jetBranchName

        # jet mass scale
        self.jmsVals = jmsVals
        if not self.jmsVals:
            print("WARNING: jmsVals is empty!!! Using default values! This " +
                  "module will soon be deprecated! Please use " +
                  "jetmetHelperRun2 in the future.")
            # 2016 values
            self.jmsVals = [1.00, 0.9906, 1.0094]  # nominal, down, up
            # Use 2017 values for 2018 until 2018 are released
            if self.era in ["2017", "2018"]:
                self.jmsVals = [0.982, 0.978, 0.986]

        # read jet energy scale (JES) uncertainties
        # (downloaded from https://twiki.cern.ch/twiki/bin/view/CMS/JECDataMC )
        self.jesInputArchivePath = os.environ['CMSSW_BASE'] + \
            "/src/PhysicsTools/NanoAODTools/data/jme/"

        # Text files are now tarred so must extract first into temporary
        # directory (gets deleted during python memory management at script exit)
        self.jesArchive = tarfile.open(
            self.jesInputArchivePath + globalTag +
            ".tgz", "r:gz") if not archive else tarfile.open(
                self.jesInputArchivePath + archive + ".tgz", "r:gz")
        self.jesInputFilePath = tempfile.mkdtemp()
        self.jesArchive.extractall(self.jesInputFilePath)

        if len(jesUncertainties) == 1 and jesUncertainties[0] == "Total":
            self.jesUncertaintyInputFileName = globalTag + "_Uncertainty_" + jetType + ".txt"
        elif jesUncertainties[0] == "Merged" and not self.isData:
            self.jesUncertaintyInputFileName = "Regrouped_" + \
                globalTag + "_UncertaintySources_" + jetType + ".txt"
        else:
            self.jesGroupedFilePath = os.environ[
                'CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/regrouped/"
            self.jesGroupedUncertaintyFileName = "RegroupedV2_" + globalTag + "_UncertaintySources_" + jetType + ".txt"
            self.jesGroupedUncertaintyFilePath = pjoin(
                self.jesGroupedFilePath, self.jesGroupedUncertaintyFileName)
            # Copy the uncertainty source file to the tmp directory
            shutil.copy(
                self.jesGroupedUncertaintyFilePath,
                pjoin(self.jesInputFilePath,
                      self.jesGroupedUncertaintyFileName))
            self.jesUncertaintyInputFileName = self.jesGroupedUncertaintyFileName
            #self.jesUncertaintyInputFileName = "RegroupedV2_" + globalTag + "_UncertaintySources_" + jetType + ".txt"

        # read all uncertainty source names from the loaded file
        if jesUncertainties[0] in ["All", "Merged"]:
            with open(self.jesInputFilePath + '/' +
                      self.jesUncertaintyInputFileName) as f:
                lines = f.read().split("\n")
                sources = [
                    x for x in lines if x.startswith("[") and x.endswith("]")
                ]
                sources = [x[1:-1] for x in sources]
                self.jesUncertainties = sources
        if applyHEMfix:
            self.jesUncertainties.append("HEMIssue")

        self.jetReCalibrator = JetReCalibrator(
            globalTag,
            jetType,
            True,
            self.jesInputFilePath,
            calculateSeparateCorrections=False,
            calculateType1METCorrection=False)

        # load libraries for accessing JES scale factors and uncertainties
        # from txt files
        for library in [
                "libCondFormatsJetMETObjects", "libPhysicsToolsNanoAODTools"
        ]:
            if library not in ROOT.gSystem.GetLibraries():
                print("Load Library '%s'" % library.replace("lib", ""))
                ROOT.gSystem.Load(library)

    def getJERsplitID(self, pt, eta):
        if not self.splitJER:
            return ""
        if abs(eta) < 1.93:
            return 0
        elif abs(eta) < 2.5:
            return 1
        elif abs(eta) < 3:
            if pt < 50:
                return 2
            else:
                return 3
        else:
            if pt < 50:
                return 4
            else:
                return 5

    def beginJob(self):

        print("Loading jet energy scale (JES) uncertainties from file '%s'" %
              os.path.join(self.jesInputFilePath,
                           self.jesUncertaintyInputFileName))
        # self.jesUncertainty = ROOT.JetCorrectionUncertainty(os.path.join(self.jesInputFilePath, self.jesUncertaintyInputFileName))

        self.jesUncertainty = {}
        # implementation didn't seem to work for factorized JEC,try again
        # another way
        for jesUncertainty in self.jesUncertainties:
            jesUncertainty_label = jesUncertainty
            if jesUncertainty == 'Total' \
                and (len(self.jesUncertainties) == 1
                     or len(self.jesUncertainties) == 2 and 'HEMIssue'
                     in self.jesUncertainties):
                jesUncertainty_label = ''
            if jesUncertainty != "HEMIssue":
                pars = ROOT.JetCorrectorParameters(
                    os.path.join(self.jesInputFilePath,
                                 self.jesUncertaintyInputFileName),
                    jesUncertainty_label)
                self.jesUncertainty[
                    jesUncertainty] = ROOT.JetCorrectionUncertainty(pars)

        if not self.isData:
            self.jetSmearer.beginJob()

    def endJob(self):
        if not self.isData:
            self.jetSmearer.endJob()
        shutil.rmtree(self.jesInputFilePath)

    def beginFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        self.out = wrappedOutputTree
        self.out.branch("%s_pt_raw" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_pt_nom" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_mass_raw" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_mass_nom" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_corr_JEC" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_corr_JMR" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_corr_JER" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_corr_JMS" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)

        if self.doGroomed:
            self.out.branch("%s_msoftdrop_raw" % self.jetBranchName,
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_nom" % self.jetBranchName,
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_corr_JMR" % self.jetBranchName,
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_corr_JMS" % self.jetBranchName,
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_corr_PUPPI" % self.jetBranchName,
                            "F",
                            lenVar=self.lenVar)

        if not self.isData:
            self.out.branch("%s_msoftdrop_tau21DDT_nom" % self.jetBranchName,
                            "F",
                            lenVar=self.lenVar)
            for shift in ["Up", "Down"]:
                for jerID in self.splitJERIDs:
                    self.out.branch("%s_pt_jer%s%s" %
                                    (self.jetBranchName, jerID, shift),
                                    "F",
                                    lenVar=self.lenVar)
                    self.out.branch("%s_mass_jer%s%s" %
                                    (self.jetBranchName, jerID, shift),
                                    "F",
                                    lenVar=self.lenVar)
                self.out.branch("%s_mass_jmr%s" % (self.jetBranchName, shift),
                                "F",
                                lenVar=self.lenVar)
                self.out.branch("%s_mass_jms%s" % (self.jetBranchName, shift),
                                "F",
                                lenVar=self.lenVar)

                if self.doGroomed:
                    for jerID in self.splitJERIDs:
                        self.out.branch("%s_msoftdrop_jer%s%s" %
                                        (self.jetBranchName, jerID, shift),
                                        "F",
                                        lenVar=self.lenVar)
                        self.out.branch("%s_msoftdrop_tau21DDT_jer%s%s" %
                                        (self.jetBranchName, jerID, shift),
                                        "F",
                                        lenVar=self.lenVar)
                    self.out.branch("%s_msoftdrop_jmr%s" %
                                    (self.jetBranchName, shift),
                                    "F",
                                    lenVar=self.lenVar)
                    self.out.branch("%s_msoftdrop_jms%s" %
                                    (self.jetBranchName, shift),
                                    "F",
                                    lenVar=self.lenVar)
                    self.out.branch("%s_msoftdrop_tau21DDT_jmr%s" %
                                    (self.jetBranchName, shift),
                                    "F",
                                    lenVar=self.lenVar)
                    self.out.branch("%s_msoftdrop_tau21DDT_jms%s" %
                                    (self.jetBranchName, shift),
                                    "F",
                                    lenVar=self.lenVar)

                for jesUncertainty in self.jesUncertainties:
                    self.out.branch(
                        "%s_pt_jes%s%s" %
                        (self.jetBranchName, jesUncertainty, shift),
                        "F",
                        lenVar=self.lenVar)
                    self.out.branch(
                        "%s_mass_jes%s%s" %
                        (self.jetBranchName, jesUncertainty, shift),
                        "F",
                        lenVar=self.lenVar)
                    if self.doGroomed:
                        self.out.branch(
                            "%s_msoftdrop_jes%s%s" %
                            (self.jetBranchName, jesUncertainty, shift),
                            "F",
                            lenVar=self.lenVar)

    def endFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        pass

    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        jets = Collection(event, self.jetBranchName)
        if not self.isData:
            genJets = Collection(event, self.genJetBranchName)

        if self.doGroomed:
            subJets = Collection(event, self.subJetBranchName)
            if not self.isData:
                genSubJets = Collection(event, self.genSubJetBranchName)
                genSubJetMatcher = matchObjectCollectionMultiple(genJets,
                                                                 genSubJets,
                                                                 dRmax=0.8)

        if not self.isData:
            self.jetSmearer.setSeed(event)

        jets_pt_raw = []
        jets_pt_nom = []
        jets_mass_raw = []
        jets_mass_nom = []

        jets_corr_JEC = []
        jets_corr_JER = []
        jets_corr_JMS = []
        jets_corr_JMR = []

        jets_pt_jerUp = {}
        jets_pt_jerDown = {}
        jets_pt_jesUp = {}
        jets_pt_jesDown = {}

        jets_mass_jerUp = {}
        jets_mass_jerDown = {}
        jets_mass_jmrUp = []
        jets_mass_jmrDown = []
        jets_mass_jesUp = {}
        jets_mass_jesDown = {}
        jets_mass_jmsUp = []
        jets_mass_jmsDown = []

        for jerID in self.splitJERIDs:
            jets_pt_jerUp[jerID] = []
            jets_pt_jerDown[jerID] = []
            jets_mass_jerUp[jerID] = []
            jets_mass_jerDown[jerID] = []

        for jesUncertainty in self.jesUncertainties:
            jets_pt_jesUp[jesUncertainty] = []
            jets_pt_jesDown[jesUncertainty] = []
            jets_mass_jesUp[jesUncertainty] = []
            jets_mass_jesDown[jesUncertainty] = []

        if self.doGroomed:
            jets_msdcorr_raw = []
            jets_msdcorr_nom = []
            jets_msdcorr_corr_JMR = []
            jets_msdcorr_corr_JMS = []
            jets_msdcorr_corr_PUPPI = []
            jets_msdcorr_jerUp = {}
            jets_msdcorr_jerDown = {}
            jets_msdcorr_jmrUp = []
            jets_msdcorr_jmrDown = []
            jets_msdcorr_jesUp = {}
            jets_msdcorr_jesDown = {}
            jets_msdcorr_jmsUp = []
            jets_msdcorr_jmsDown = []
            jets_msdcorr_tau21DDT_nom = []
            jets_msdcorr_tau21DDT_jerUp = {}
            jets_msdcorr_tau21DDT_jerDown = {}
            jets_msdcorr_tau21DDT_jmrUp = []
            jets_msdcorr_tau21DDT_jmrDown = []
            jets_msdcorr_tau21DDT_jmsUp = []
            jets_msdcorr_tau21DDT_jmsDown = []
            for jerID in self.splitJERIDs:
                jets_msdcorr_jerUp[jerID] = []
                jets_msdcorr_jerDown[jerID] = []
                jets_msdcorr_tau21DDT_jerUp[jerID] = []
                jets_msdcorr_tau21DDT_jerDown[jerID] = []
            for jesUncertainty in self.jesUncertainties:
                jets_msdcorr_jesUp[jesUncertainty] = []
                jets_msdcorr_jesDown[jesUncertainty] = []

        rho = getattr(event, self.rhoBranchName)

        # match reconstructed jets to generator level ones
        # (needed to evaluate JER scale factors and uncertainties)
        if not self.isData:
            pairs = matchObjectCollection(jets, genJets)

        for jet in jets:
            # jet pt and mass corrections
            jet_pt = jet.pt
            jet_mass = jet.mass

            if hasattr(jet, "rawFactor"):
                jet_rawpt = jet_pt * (1 - jet.rawFactor)
                jet_rawmass = jet_mass * (1 - jet.rawFactor)
            else:
                jet_rawpt = -1.0 * jet_pt  # If factor not present factor will be saved as -1
                jet_rawmass = -1.0 * jet_mass  # If factor not present factor will be saved as -1
            (jet_pt, jet_mass) = self.jetReCalibrator.correct(jet, rho)
            jet.pt = jet_pt
            jet.mass = jet_mass
            jets_pt_raw.append(jet_rawpt)
            jets_mass_raw.append(jet_rawmass)
            jets_corr_JEC.append(jet_pt / jet_rawpt)

            if not self.isData:
                genJet = pairs[jet]

            # evaluate JER scale factors and uncertainties
            # (cf. https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution and https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyResolution )
            if not self.isData:
                (jet_pt_jerNomVal, jet_pt_jerUpVal,
                 jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt(
                     jet, genJet, rho)
            else:
                # set values to 1 for data so that jet_pt_nom is not smeared
                (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = (1, 1,
                                                                          1)
            jets_corr_JER.append(jet_pt_jerNomVal)

            jet_pt_nom = jet_pt_jerNomVal * jet_pt if self.applySmearing else jet_pt
            if jet_pt_nom < 0.0:
                jet_pt_nom *= -1.0
            jets_pt_nom.append(jet_pt_nom)

            # Evaluate JMS and JMR scale factors and uncertainties
            jmsNomVal, jmsDownVal, jmsUpVal = self.jmsVals if not self.isData else (
                1, 1, 1)
            if not self.isData:
                (jet_mass_jmrNomVal, jet_mass_jmrUpVal,
                 jet_mass_jmrDownVal) = self.jetSmearer.getSmearValsM(
                     jet, genJet)
            else:
                # set values to 1 for data so that jet_mass_nom is not smeared
                (jet_mass_jmrNomVal, jet_mass_jmrUpVal,
                 jet_mass_jmrDownVal) = (1, 1, 1)
            jets_corr_JMS.append(jmsNomVal)
            jets_corr_JMR.append(jet_mass_jmrNomVal)

            jet_mass_nom = jet_pt_jerNomVal * jet_mass_jmrNomVal * \
                jmsNomVal * jet_mass if self.applySmearing else jet_mass
            if jet_mass_nom < 0.0:
                jet_mass_nom *= -1.0
            jets_mass_nom.append(jet_mass_nom)

            if not self.isData:
                jet_pt_jerUp = {
                    jerID: jet_pt_nom
                    for jerID in self.splitJERIDs
                }
                jet_pt_jerDown = {
                    jerID: jet_pt_nom
                    for jerID in self.splitJERIDs
                }
                jet_mass_jerUp = {
                    jerID: jet_mass_nom
                    for jerID in self.splitJERIDs
                }
                jet_mass_jerDown = {
                    jerID: jet_mass_nom
                    for jerID in self.splitJERIDs
                }
                thisJERID = self.getJERsplitID(jet_pt_nom, jet.eta)
                jet_pt_jerUp[thisJERID] = jet_pt_jerUpVal * jet_pt
                jet_pt_jerDown[thisJERID] = jet_pt_jerDownVal * jet_pt
                jet_mass_jerUp[thisJERID] = jet_pt_jerUpVal * \
                    jet_mass_jmrNomVal * jmsNomVal * jet_mass
                jet_mass_jerDown[thisJERID] = jet_pt_jerDownVal * \
                    jet_mass_jmrNomVal * jmsNomVal * jet_mass

                for jerID in self.splitJERIDs:
                    jets_pt_jerUp[jerID].append(jet_pt_jerUp[jerID])
                    jets_pt_jerDown[jerID].append(jet_pt_jerDown[jerID])
                    jets_mass_jerUp[jerID].append(jet_mass_jerUp[jerID])
                    jets_mass_jerDown[jerID].append(jet_mass_jerDown[jerID])

                jets_mass_jmrUp.append(jet_pt_jerNomVal * jet_mass_jmrUpVal *
                                       jmsNomVal * jet_mass)
                jets_mass_jmrDown.append(jet_pt_jerNomVal *
                                         jet_mass_jmrDownVal * jmsNomVal *
                                         jet_mass)
                jets_mass_jmsUp.append(jet_pt_jerNomVal * jet_mass_jmrNomVal *
                                       jmsUpVal * jet_mass)
                jets_mass_jmsDown.append(jet_pt_jerNomVal *
                                         jet_mass_jmrNomVal * jmsDownVal *
                                         jet_mass)

            if self.doGroomed:
                if not self.isData:
                    genGroomedSubJets = genSubJetMatcher[
                        genJet] if genJet is not None else None
                    genGroomedJet = genGroomedSubJets[0].p4(
                    ) + genGroomedSubJets[1].p4(
                    ) if genGroomedSubJets is not None and len(
                        genGroomedSubJets) >= 2 else None
                else:
                    genGroomedSubJets = None
                    genGroomedJet = None
                if jet.subJetIdx1 >= 0 and jet.subJetIdx2 >= 0:
                    groomedP4 = subJets[jet.subJetIdx1].p4() + subJets[
                        jet.subJetIdx2].p4()  # check subjet jecs
                else:
                    groomedP4 = None

                jet_msdcorr_raw = groomedP4.M(
                ) if groomedP4 is not None else 0.0
                # raw value always stored withoud mass correction
                jets_msdcorr_raw.append(jet_msdcorr_raw)
                # LC: Apply PUPPI SD mass correction https://github.com/cms-jet/PuppiSoftdropMassCorr/
                puppisd_genCorr = self.puppisd_corrGEN.Eval(jet.pt)
                if abs(jet.eta) <= 1.3:
                    puppisd_recoCorr = self.puppisd_corrRECO_cen.Eval(jet.pt)
                else:
                    puppisd_recoCorr = self.puppisd_corrRECO_for.Eval(jet.pt)

                puppisd_total = puppisd_genCorr * puppisd_recoCorr
                jets_msdcorr_corr_PUPPI.append(puppisd_total)
                if groomedP4 is not None:
                    groomedP4.SetPtEtaPhiM(groomedP4.Perp(), groomedP4.Eta(),
                                           groomedP4.Phi(),
                                           groomedP4.M() * puppisd_total)

                # now apply the mass correction to the raw value
                jet_msdcorr_raw = groomedP4.M(
                ) if groomedP4 is not None else 0.0
                if jet_msdcorr_raw < 0.0:
                    jet_msdcorr_raw *= -1.0

                # Evaluate JMS and JMR scale factors and uncertainties
                if not self.isData:
                    (jet_msdcorr_jmrNomVal, jet_msdcorr_jmrUpVal,
                     jet_msdcorr_jmrDownVal) = \
                        (self.jetSmearer.getSmearValsM(groomedP4,
                         genGroomedJet) if groomedP4 is not None
                         and genGroomedJet is not None else (0., 0., 0.))
                else:
                    (jet_msdcorr_jmrNomVal, jet_msdcorr_jmrUpVal,
                     jet_msdcorr_jmrDownVal) = (1, 1, 1)

                jets_msdcorr_corr_JMS.append(jmsNomVal)
                jets_msdcorr_corr_JMR.append(jet_msdcorr_jmrNomVal)

                jet_msdcorr_nom = jet_pt_jerNomVal * \
                    jet_msdcorr_jmrNomVal * jmsNomVal * jet_msdcorr_raw
                # store the nominal mass value
                jets_msdcorr_nom.append(jet_msdcorr_nom)

                if not self.isData:
                    jet_msdcorr_jerUp = {
                        jerID: jet_msdcorr_nom
                        for jerID in self.splitJERIDs
                    }
                    jet_msdcorr_jerDown = {
                        jerID: jet_msdcorr_nom
                        for jerID in self.splitJERIDs
                    }
                    thisJERID = self.getJERsplitID(jet_pt_nom, jet.eta)
                    jet_msdcorr_jerUp[thisJERID] = jet_pt_jerUpVal * \
                        jet_msdcorr_jmrNomVal * jmsNomVal * jet_msdcorr_raw
                    jet_msdcorr_jerDown[thisJERID] = jet_pt_jerDownVal * \
                        jet_msdcorr_jmrNomVal * jmsNomVal * jet_msdcorr_raw
                    for jerID in self.splitJERIDs:
                        jets_msdcorr_jerUp[jerID].append(
                            jet_msdcorr_jerUp[jerID])
                        jets_msdcorr_jerDown[jerID].append(
                            jet_msdcorr_jerDown[jerID])

                    jets_msdcorr_jmrUp.append(
                        jet_pt_jerNomVal * jet_msdcorr_jmrUpVal * jmsNomVal *
                        jet_msdcorr_raw)
                    jets_msdcorr_jmrDown.append(
                        jet_pt_jerNomVal * jet_msdcorr_jmrDownVal * jmsNomVal *
                        jet_msdcorr_raw)
                    jets_msdcorr_jmsUp.append(
                        jet_pt_jerNomVal * jet_msdcorr_jmrNomVal * jmsUpVal *
                        jet_msdcorr_raw)
                    jets_msdcorr_jmsDown.append(
                        jet_pt_jerNomVal * jet_msdcorr_jmrNomVal * jmsDownVal *
                        jet_msdcorr_raw)

                    # Also evaluated JMS&JMR SD corr in tau21DDT region: https://twiki.cern.ch/twiki/bin/viewauth/CMS/JetWtagging#tau21DDT_0_43
                    if self.era in ["2016"]:
                        jmstau21DDTNomVal = 1.014
                        jmstau21DDTDownVal = 1.007
                        jmstau21DDTUpVal = 1.021
                        self.jetSmearer.jmr_vals = [1.086, 1.176, 0.996]
                    elif self.era in ["2017"]:
                        jmstau21DDTNomVal = 0.983
                        jmstau21DDTDownVal = 0.976
                        jmstau21DDTUpVal = 0.99
                        self.jetSmearer.jmr_vals = [1.080, 1.161, 0.999]
                    elif self.era in ["2018"]:
                        jmstau21DDTNomVal = 1.000  # tau21DDT < 0.43 WP
                        jmstau21DDTDownVal = 0.990
                        jmstau21DDTUpVal = 1.010
                        self.jetSmearer.jmr_vals = [1.124, 1.208, 1.040]

                    (
                        jet_msdcorr_tau21DDT_jmrNomVal,
                        jet_msdcorr_tau21DDT_jmrUpVal,
                        jet_msdcorr_tau21DDT_jmrDownVal
                    ) = self.jetSmearer.getSmearValsM(
                        groomedP4, genGroomedJet
                    ) if groomedP4 is not None and genGroomedJet is not None else (
                        0., 0., 0.)

                    jet_msdcorr_tau21DDT_nom = jet_pt_jerNomVal * \
                        jet_msdcorr_tau21DDT_jmrNomVal * jmstau21DDTNomVal * jet_msdcorr_raw
                    jets_msdcorr_tau21DDT_nom.append(jet_msdcorr_tau21DDT_nom)

                    jet_msdcorr_tau21DDT_jerUp = {
                        jerID: jet_msdcorr_tau21DDT_nom
                        for jerID in self.splitJERIDs
                    }
                    jet_msdcorr_tau21DDT_jerDown = {
                        jerID: jet_msdcorr_tau21DDT_nom
                        for jerID in self.splitJERIDs
                    }
                    jet_msdcorr_tau21DDT_jerUp[thisJERID] = jet_pt_jerUpVal * \
                        jet_msdcorr_tau21DDT_jmrNomVal * jmstau21DDTNomVal * jet_msdcorr_raw
                    jet_msdcorr_tau21DDT_jerDown[thisJERID] = jet_pt_jerDownVal * \
                        jet_msdcorr_tau21DDT_jmrNomVal * jmstau21DDTNomVal * jet_msdcorr_raw
                    for jerID in self.splitJERIDs:
                        jets_msdcorr_tau21DDT_jerUp[jerID].append(
                            jet_msdcorr_tau21DDT_jerUp[jerID])
                        jets_msdcorr_tau21DDT_jerDown[jerID].append(
                            jet_msdcorr_tau21DDT_jerDown[jerID])

                    jets_msdcorr_tau21DDT_jmrUp.append(
                        jet_pt_jerNomVal * jet_msdcorr_tau21DDT_jmrUpVal *
                        jmstau21DDTNomVal * jet_msdcorr_raw)
                    jets_msdcorr_tau21DDT_jmrDown.append(
                        jet_pt_jerNomVal * jet_msdcorr_tau21DDT_jmrDownVal *
                        jmstau21DDTNomVal * jet_msdcorr_raw)
                    jets_msdcorr_tau21DDT_jmsUp.append(
                        jet_pt_jerNomVal * jet_msdcorr_tau21DDT_jmrNomVal *
                        jmstau21DDTUpVal * jet_msdcorr_raw)
                    jets_msdcorr_tau21DDT_jmsDown.append(
                        jet_pt_jerNomVal * jet_msdcorr_tau21DDT_jmrNomVal *
                        jmstau21DDTDownVal * jet_msdcorr_raw)

                    # Restore original jmr_vals in jetSmearer
                    self.jetSmearer.jmr_vals = self.jmrVals

            if not self.isData:
                # evaluate JES uncertainties
                jet_pt_jesUp = {}
                jet_pt_jesDown = {}
                jet_mass_jesUp = {}
                jet_mass_jesDown = {}
                jet_msdcorr_jesUp = {}
                jet_msdcorr_jesDown = {}

                for jesUncertainty in self.jesUncertainties:
                    # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties)
                    # cf. https://hypernews.cern.ch/HyperNews/CMS/get/JetMET/2000.html
                    if jesUncertainty == "HEMIssue":
                        delta = 1.
                        if jet_pt_nom > 15 and jet.jetId & 2 and jet.phi > -1.57 and jet.phi < -0.87:
                            if jet.eta > -2.5 and jet.eta < -1.3:
                                delta = 0.8
                            elif jet.eta <= -2.5 and jet.eta > -3:
                                delta = 0.65
                        jet_pt_jesUp[jesUncertainty] = jet_pt_nom
                        jet_pt_jesDown[jesUncertainty] = delta * jet_pt_nom
                        jet_mass_jesUp[jesUncertainty] = jet_mass_nom
                        jet_mass_jesDown[jesUncertainty] = delta * jet_mass_nom
                        if self.doGroomed:
                            jet_msdcorr_jesUp[jesUncertainty] = jet_msdcorr_nom
                            jet_msdcorr_jesDown[jesUncertainty] = delta * \
                                jet_msdcorr_nom
                    else:
                        self.jesUncertainty[jesUncertainty].setJetPt(
                            jet_pt_nom)
                        self.jesUncertainty[jesUncertainty].setJetEta(jet.eta)
                        delta = self.jesUncertainty[
                            jesUncertainty].getUncertainty(True)
                        jet_pt_jesUp[jesUncertainty] = jet_pt_nom * \
                            (1. + delta)
                        jet_pt_jesDown[jesUncertainty] = jet_pt_nom * \
                            (1. - delta)
                        jet_mass_jesUp[jesUncertainty] = jet_mass_nom * \
                            (1. + delta)
                        jet_mass_jesDown[jesUncertainty] = jet_mass_nom * \
                            (1. - delta)
                        if self.doGroomed:
                            jet_msdcorr_jesUp[jesUncertainty] = jet_msdcorr_nom * \
                                (1. + delta)
                            jet_msdcorr_jesDown[
                                jesUncertainty] = jet_msdcorr_nom * (1. -
                                                                     delta)
                    jets_pt_jesUp[jesUncertainty].append(
                        jet_pt_jesUp[jesUncertainty])
                    jets_pt_jesDown[jesUncertainty].append(
                        jet_pt_jesDown[jesUncertainty])
                    jets_mass_jesUp[jesUncertainty].append(
                        jet_mass_jesUp[jesUncertainty])
                    jets_mass_jesDown[jesUncertainty].append(
                        jet_mass_jesDown[jesUncertainty])
                    if self.doGroomed:
                        jets_msdcorr_jesUp[jesUncertainty].append(
                            jet_msdcorr_jesUp[jesUncertainty])
                        jets_msdcorr_jesDown[jesUncertainty].append(
                            jet_msdcorr_jesDown[jesUncertainty])

        self.out.fillBranch("%s_pt_raw" % self.jetBranchName, jets_pt_raw)
        self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom)
        self.out.fillBranch("%s_corr_JEC" % self.jetBranchName, jets_corr_JEC)
        self.out.fillBranch("%s_mass_raw" % self.jetBranchName, jets_mass_raw)
        self.out.fillBranch("%s_mass_nom" % self.jetBranchName, jets_mass_nom)

        if not self.isData:
            self.out.fillBranch("%s_corr_JER" % self.jetBranchName,
                                jets_corr_JER)
            self.out.fillBranch("%s_corr_JMS" % self.jetBranchName,
                                jets_corr_JMS)
            self.out.fillBranch("%s_corr_JMR" % self.jetBranchName,
                                jets_corr_JMR)
            for jerID in self.splitJERIDs:
                self.out.fillBranch(
                    "%s_pt_jer%sUp" % (self.jetBranchName, jerID),
                    jets_pt_jerUp[jerID])
                self.out.fillBranch(
                    "%s_pt_jer%sDown" % (self.jetBranchName, jerID),
                    jets_pt_jerDown[jerID])
                self.out.fillBranch(
                    "%s_mass_jer%sUp" % (self.jetBranchName, jerID),
                    jets_mass_jerUp[jerID])
                self.out.fillBranch(
                    "%s_mass_jer%sDown" % (self.jetBranchName, jerID),
                    jets_mass_jerDown[jerID])
            self.out.fillBranch("%s_mass_jmrUp" % self.jetBranchName,
                                jets_mass_jmrUp)
            self.out.fillBranch("%s_mass_jmrDown" % self.jetBranchName,
                                jets_mass_jmrDown)
            self.out.fillBranch("%s_mass_jmsUp" % self.jetBranchName,
                                jets_mass_jmsUp)
            self.out.fillBranch("%s_mass_jmsDown" % self.jetBranchName,
                                jets_mass_jmsDown)

        if self.doGroomed:
            self.out.fillBranch("%s_msoftdrop_raw" % self.jetBranchName,
                                jets_msdcorr_raw)
            self.out.fillBranch("%s_msoftdrop_nom" % self.jetBranchName,
                                jets_msdcorr_nom)
            self.out.fillBranch("%s_msoftdrop_corr_JMS" % self.jetBranchName,
                                jets_msdcorr_corr_JMS)
            self.out.fillBranch("%s_msoftdrop_corr_JMR" % self.jetBranchName,
                                jets_msdcorr_corr_JMR)
            self.out.fillBranch("%s_msoftdrop_corr_PUPPI" % self.jetBranchName,
                                jets_msdcorr_corr_PUPPI)
            if not self.isData:
                self.out.fillBranch(
                    "%s_msoftdrop_tau21DDT_nom" % self.jetBranchName,
                    jets_msdcorr_tau21DDT_nom)
                for jerID in self.splitJERIDs:
                    self.out.fillBranch(
                        "%s_msoftdrop_jer%sUp" % (self.jetBranchName, jerID),
                        jets_msdcorr_jerUp[jerID])
                    self.out.fillBranch(
                        "%s_msoftdrop_jer%sDown" % (self.jetBranchName, jerID),
                        jets_msdcorr_jerDown[jerID])
                    self.out.fillBranch(
                        "%s_msoftdrop_tau21DDT_jer%sUp" %
                        (self.jetBranchName, jerID),
                        jets_msdcorr_tau21DDT_jerUp[jerID])
                    self.out.fillBranch(
                        "%s_msoftdrop_tau21DDT_jer%sDown" %
                        (self.jetBranchName, jerID),
                        jets_msdcorr_tau21DDT_jerDown[jerID])
                self.out.fillBranch("%s_msoftdrop_jmrUp" % self.jetBranchName,
                                    jets_msdcorr_jmrUp)
                self.out.fillBranch(
                    "%s_msoftdrop_jmrDown" % self.jetBranchName,
                    jets_msdcorr_jmrDown)
                self.out.fillBranch("%s_msoftdrop_jmsUp" % self.jetBranchName,
                                    jets_msdcorr_jmsUp)
                self.out.fillBranch(
                    "%s_msoftdrop_jmsDown" % self.jetBranchName,
                    jets_msdcorr_jmsDown)
                self.out.fillBranch(
                    "%s_msoftdrop_tau21DDT_jmrUp" % self.jetBranchName,
                    jets_msdcorr_tau21DDT_jmrUp)
                self.out.fillBranch(
                    "%s_msoftdrop_tau21DDT_jmrDown" % self.jetBranchName,
                    jets_msdcorr_tau21DDT_jmrDown)
                self.out.fillBranch(
                    "%s_msoftdrop_tau21DDT_jmsUp" % self.jetBranchName,
                    jets_msdcorr_tau21DDT_jmsUp)
                self.out.fillBranch(
                    "%s_msoftdrop_tau21DDT_jmsDown" % self.jetBranchName,
                    jets_msdcorr_tau21DDT_jmsDown)

        if not self.isData:
            for jesUncertainty in self.jesUncertainties:
                self.out.fillBranch(
                    "%s_pt_jes%sUp" % (self.jetBranchName, jesUncertainty),
                    jets_pt_jesUp[jesUncertainty])
                self.out.fillBranch(
                    "%s_pt_jes%sDown" % (self.jetBranchName, jesUncertainty),
                    jets_pt_jesDown[jesUncertainty])
                self.out.fillBranch(
                    "%s_mass_jes%sUp" % (self.jetBranchName, jesUncertainty),
                    jets_mass_jesUp[jesUncertainty])
                self.out.fillBranch(
                    "%s_mass_jes%sDown" % (self.jetBranchName, jesUncertainty),
                    jets_mass_jesDown[jesUncertainty])

                if self.doGroomed:
                    self.out.fillBranch(
                        "%s_msoftdrop_jes%sUp" %
                        (self.jetBranchName, jesUncertainty),
                        jets_msdcorr_jesUp[jesUncertainty])
                    self.out.fillBranch(
                        "%s_msoftdrop_jes%sDown" %
                        (self.jetBranchName, jesUncertainty),
                        jets_msdcorr_jesDown[jesUncertainty])

        return True
Exemple #5
0
class jetmetUncertaintiesProducer(Module):
    def __init__(self,
                 era,
                 globalTag,
                 jesUncertainties=["Total"],
                 archive=None,
                 globalTagProd=None,
                 jetType="AK4PFchs",
                 metBranchName="MET",
                 jerTag="",
                 isData=False,
                 applySmearing=True):

        # globalTagProd only needs to be defined if METFixEE2017 is to be recorrected, and should be the GT that was used for the production of the nanoAOD files
        self.era = era
        self.isData = isData
        self.applySmearing = applySmearing if not isData else False  # if set to true, Jet_pt_nom will have JER applied. not to be switched on for data.

        self.metBranchName = metBranchName
        self.rhoBranchName = "fixedGridRhoFastjetAll"
        #--------------------------------------------------------------------------------------------
        # CV: globalTag and jetType not yet used in the jet smearer, as there is no consistent set of
        #     txt files for JES uncertainties and JER scale factors and uncertainties yet
        #--------------------------------------------------------------------------------------------

        self.jesUncertainties = jesUncertainties

        # smear jet pT to account for measured difference in JER between data and simulation.
        if jerTag != "":
            self.jerInputFileName = jerTag + "_PtResolution_" + jetType + ".txt"
            self.jerUncertaintyInputFileName = jerTag + "_SF_" + jetType + ".txt"
        else:
            print "WARNING: jerTag is empty!!! This module will soon be deprecated! Please use jetmetHelperRun2 in the future."
            if era == "2016":
                self.jerInputFileName = "Summer16_25nsV1_MC_PtResolution_" + jetType + ".txt"
                self.jerUncertaintyInputFileName = "Summer16_25nsV1_MC_SF_" + jetType + ".txt"
            elif era == "2017" or era == "2018":  ## use 2017 JER for 2018 for the time being
                self.jerInputFileName = "Fall17_V3_MC_PtResolution_" + jetType + ".txt"
                self.jerUncertaintyInputFileName = "Fall17_V3_MC_SF_" + jetType + ".txt"
            elif era == "2018" and False:  ## jetSmearer not working with 2018 JERs yet
                self.jerInputFileName = "Autumn18_V7_MC_PtResolution_" + jetType + ".txt"
                self.jerUncertaintyInputFileName = "Autumn18_V7_MC_SF_" + jetType + ".txt"

        self.jetSmearer = jetSmearer(globalTag, jetType, self.jerInputFileName,
                                     self.jerUncertaintyInputFileName)

        if "AK4" in jetType:
            self.jetBranchName = "Jet"
            self.genJetBranchName = "GenJet"
            self.genSubJetBranchName = None
        else:
            raise ValueError("ERROR: Invalid jet type = '%s'!" % jetType)
        self.lenVar = "n" + self.jetBranchName

        # read jet energy scale (JES) uncertainties
        # (downloaded from https://twiki.cern.ch/twiki/bin/view/CMS/JECDataMC )
        self.jesInputArchivePath = os.environ[
            'CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/"
        # Text files are now tarred so must extract first into temporary directory (gets deleted during python memory management at script exit)
        self.jesArchive = tarfile.open(
            self.jesInputArchivePath + globalTag +
            ".tgz", "r:gz") if not archive else tarfile.open(
                self.jesInputArchivePath + archive + ".tgz", "r:gz")
        self.jesInputFilePath = tempfile.mkdtemp()
        self.jesArchive.extractall(self.jesInputFilePath)

        # to fully re-calculate type-1 MET the JEC that are currently applied are also needed. IS THAT EVEN CORRECT?

        if len(jesUncertainties) == 1 and jesUncertainties[0] == "Total":
            self.jesUncertaintyInputFileName = globalTag + "_Uncertainty_" + jetType + ".txt"
        else:
            self.jesUncertaintyInputFileName = globalTag + "_UncertaintySources_" + jetType + ".txt"

        # read all uncertainty source names from the loaded file
        if jesUncertainties[0] == "All":
            with open(self.jesInputFilePath + '/' +
                      self.jesUncertaintyInputFileName) as f:
                lines = f.read().split("\n")
                sources = filter(
                    lambda x: x.startswith("[") and x.endswith("]"), lines)
                sources = map(lambda x: x[1:-1], sources)
                self.jesUncertainties = sources

        # Define the jet recalibrator
        self.jetReCalibrator = JetReCalibrator(
            globalTag,
            jetType,
            True,
            self.jesInputFilePath,
            calculateSeparateCorrections=False,
            calculateType1METCorrection=False)

        # Define the recalibrator for level 1 corrections only
        self.jetReCalibratorL1 = JetReCalibrator(
            globalTag,
            jetType,
            False,
            self.jesInputFilePath,
            calculateSeparateCorrections=True,
            calculateType1METCorrection=False,
            upToLevel=1)

        # Define the recalibrators for GT used in nanoAOD production (only needed to reproduce 2017 v2 MET)
        if globalTagProd:
            self.jetReCalibratorProd = JetReCalibrator(
                globalTagProd,
                jetType,
                True,
                self.jesInputFilePath,
                calculateSeparateCorrections=False,
                calculateType1METCorrection=False)
            self.jetReCalibratorProdL1 = JetReCalibrator(
                globalTagProd,
                jetType,
                False,
                self.jesInputFilePath,
                calculateSeparateCorrections=True,
                calculateType1METCorrection=False,
                upToLevel=1)
        else:
            self.jetReCalibratorProd = False
            self.jetReCalibratorProdL1 = False

        # define energy threshold below which jets are considered as "unclustered energy"
        # (cf. JetMETCorrections/Type1MET/python/correctionTermsPfMetType1Type2_cff.py )
        self.unclEnThreshold = 15.

        # load libraries for accessing JES scale factors and uncertainties from txt files
        for library in [
                "libCondFormatsJetMETObjects", "libPhysicsToolsNanoAODTools"
        ]:
            if library not in ROOT.gSystem.GetLibraries():
                print("Load Library '%s'" % library.replace("lib", ""))
                ROOT.gSystem.Load(library)

    def beginJob(self):

        print(
            "Loading jet energy scale (JES) uncertainties from file '%s'" %
            os.path.join(self.jesInputFilePath,
                         self.jesUncertaintyInputFileName))
        #self.jesUncertainty = ROOT.JetCorrectionUncertainty(os.path.join(self.jesInputFilePath, self.jesUncertaintyInputFileName))

        self.jesUncertainty = {}
        # implementation didn't seem to work for factorized JEC, try again another way
        for jesUncertainty in self.jesUncertainties:
            jesUncertainty_label = jesUncertainty
            if jesUncertainty == 'Total' and len(self.jesUncertainties) == 1:
                jesUncertainty_label = ''
            pars = ROOT.JetCorrectorParameters(
                os.path.join(self.jesInputFilePath,
                             self.jesUncertaintyInputFileName),
                jesUncertainty_label)
            self.jesUncertainty[
                jesUncertainty] = ROOT.JetCorrectionUncertainty(pars)

        if not self.isData:
            self.jetSmearer.beginJob()

    def endJob(self):
        if not self.isData:
            self.jetSmearer.endJob()
        shutil.rmtree(self.jesInputFilePath)

    def beginFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        self.out = wrappedOutputTree
        self.out.branch("%s_pt_raw" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_pt_nom" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_mass_raw" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_mass_nom" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_corr_JEC" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_corr_JER" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)

        self.out.branch("%s_pt_nom" % self.metBranchName, "F")
        self.out.branch("%s_phi_nom" % self.metBranchName, "F")

        if not self.isData:
            self.out.branch("%s_pt_jer" % self.metBranchName, "F")
            self.out.branch("%s_phi_jer" % self.metBranchName, "F")

            for shift in ["Up", "Down"]:
                self.out.branch("%s_pt_jer%s" % (self.jetBranchName, shift),
                                "F",
                                lenVar=self.lenVar)
                self.out.branch("%s_mass_jer%s" % (self.jetBranchName, shift),
                                "F",
                                lenVar=self.lenVar)

                self.out.branch("%s_pt_jer%s" % (self.metBranchName, shift),
                                "F")
                self.out.branch("%s_phi_jer%s" % (self.metBranchName, shift),
                                "F")
                for jesUncertainty in self.jesUncertainties:
                    self.out.branch(
                        "%s_pt_jes%s%s" %
                        (self.jetBranchName, jesUncertainty, shift),
                        "F",
                        lenVar=self.lenVar)
                    self.out.branch(
                        "%s_mass_jes%s%s" %
                        (self.jetBranchName, jesUncertainty, shift),
                        "F",
                        lenVar=self.lenVar)

                    self.out.branch(
                        "%s_pt_jes%s%s" %
                        (self.metBranchName, jesUncertainty, shift), "F")
                    self.out.branch(
                        "%s_phi_jes%s%s" %
                        (self.metBranchName, jesUncertainty, shift), "F")
                self.out.branch(
                    "%s_pt_unclustEn%s" % (self.metBranchName, shift), "F")
                self.out.branch(
                    "%s_phi_unclustEn%s" % (self.metBranchName, shift), "F")

        self.isV5NanoAOD = hasattr(inputTree, "Jet_muonSubtrFactor")
        print "nanoAODv5?", self.isV5NanoAOD

    def endFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        pass

    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        jets = Collection(event, self.jetBranchName)
        nJet = event.nJet
        lowPtJets = Collection(event,
                               "CorrT1METJet") if self.isV5NanoAOD else []
        muons = Collection(
            event, "Muon"
        )  # to subtract out of the jets for proper type-1 MET corrections
        if not self.isData:
            genJets = Collection(event, self.genJetBranchName)

        # prepare the low pt jets (they don't have a rawFactor)
        for jet in lowPtJets:
            jet.pt = jet.rawPt
            jet.rawFactor = 0
            jet.mass = 0
            # the following dummy values should be removed once the values are kept in nanoAOD
            jet.neEmEF = 0
            jet.chEmEF = 0

        if not self.isData:
            self.jetSmearer.setSeed(event)

        jets_pt_raw = []
        jets_pt_jer = []
        jets_pt_nom = []

        jets_mass_raw = []
        jets_mass_nom = []

        jets_corr_JEC = []
        jets_corr_JER = []

        jets_pt_jerUp = []
        jets_pt_jerDown = []
        jets_pt_jesUp = {}
        jets_pt_jesDown = {}

        jets_mass_jerUp = []
        jets_mass_jerDown = []
        jets_mass_jesUp = {}
        jets_mass_jesDown = {}

        for jesUncertainty in self.jesUncertainties:
            jets_pt_jesUp[jesUncertainty] = []
            jets_pt_jesDown[jesUncertainty] = []
            jets_mass_jesUp[jesUncertainty] = []
            jets_mass_jesDown[jesUncertainty] = []

        met = Object(event, self.metBranchName)
        rawmet = Object(event, "RawMET")
        if "Puppi" in self.metBranchName:
            rawmet = Object(event, "RawPuppiMET")
        defmet = Object(event, "MET")

        (t1met_px, t1met_py) = (met.pt * math.cos(met.phi),
                                met.pt * math.sin(met.phi))
        (def_met_px, def_met_py) = (defmet.pt * math.cos(defmet.phi),
                                    defmet.pt * math.sin(defmet.phi))
        (met_px, met_py) = (rawmet.pt * math.cos(rawmet.phi),
                            rawmet.pt * math.sin(rawmet.phi))
        (met_px_nom, met_py_nom) = (met_px, met_py)
        (met_px_jer, met_py_jer) = (met_px, met_py)
        (met_px_jerUp, met_py_jerUp) = (met_px, met_py)
        (met_px_jerDown, met_py_jerDown) = (met_px, met_py)
        (met_px_jesUp, met_py_jesUp) = ({}, {})
        (met_px_jesDown, met_py_jesDown) = ({}, {})

        for jesUncertainty in self.jesUncertainties:
            met_px_jesUp[jesUncertainty] = met_px
            met_py_jesUp[jesUncertainty] = met_py
            met_px_jesDown[jesUncertainty] = met_px
            met_py_jesDown[jesUncertainty] = met_py

        # variables needed for re-applying JECs to 2017 v2 MET
        delta_x_T1Jet, delta_y_T1Jet = 0, 0
        delta_x_rawJet, delta_y_rawJet = 0, 0

        rho = getattr(event, self.rhoBranchName)

        # match reconstructed jets to generator level ones
        # (needed to evaluate JER scale factors and uncertainties)
        def resolution_matching(jet, genjet):
            '''Helper function to match to gen based on pt difference'''
            params = ROOT.PyJetParametersWrapper()
            params.setJetEta(jet.eta)
            params.setJetPt(jet.pt)
            params.setRho(rho)

            resolution = self.jetSmearer.jer.getResolution(params)

            return abs(jet.pt - genjet.pt) < 3 * resolution * jet.pt

        if not self.isData:
            pairs = matchObjectCollection(jets,
                                          genJets,
                                          dRmax=0.2,
                                          presel=resolution_matching)
            lowPtPairs = matchObjectCollection(lowPtJets,
                                               genJets,
                                               dRmax=0.2,
                                               presel=resolution_matching)
            pairs.update(lowPtPairs)

        for iJet, jet in enumerate(itertools.chain(jets, lowPtJets)):
            #jet pt and mass corrections
            jet_pt = jet.pt
            jet_mass = jet.mass
            jet_pt_orig = jet_pt
            rawFactor = jet.rawFactor

            #redo JECs if desired
            if hasattr(jet, "rawFactor"):
                jet_rawpt = jet_pt * (1 - jet.rawFactor)
                jet_rawmass = jet_mass * (1 - jet.rawFactor)
            else:
                jet_rawpt = -1.0 * jet_pt  #If factor not present factor will be saved as -1
                jet_rawmass = -1.0 * jet_mass  #If factor not present factor will be saved as -1

            (jet_pt, jet_mass) = self.jetReCalibrator.correct(jet, rho)
            (jet_pt_l1, jet_mass_l1) = self.jetReCalibratorL1.correct(jet, rho)
            jet.pt = jet_pt
            jet.mass = jet_mass

            # Get the JEC factors
            jec = jet_pt / jet_rawpt
            jecL1 = jet_pt_l1 / jet_rawpt
            if self.jetReCalibratorProd:
                jecProd = self.jetReCalibratorProd.correct(jet,
                                                           rho)[0] / jet_rawpt
                jecL1Prod = self.jetReCalibratorProdL1.correct(
                    jet, rho)[0] / jet_rawpt

            if not self.isData:
                genJet = pairs[jet]

            # get the jet for type-1 MET
            newjet = ROOT.TLorentzVector()
            if self.isV5NanoAOD:
                newjet.SetPtEtaPhiM(
                    jet_pt_orig * (1 - jet.rawFactor) *
                    (1 - jet.muonSubtrFactor), jet.eta, jet.phi, jet.mass)
                muon_pt = jet_pt_orig * (1 -
                                         jet.rawFactor) * jet.muonSubtrFactor
            else:
                newjet.SetPtEtaPhiM(jet_pt_orig * (1 - jet.rawFactor), jet.eta,
                                    jet.phi, jet.mass)
                muon_pt = 0
                if hasattr(jet, 'muonIdx1'):
                    if jet.muonIdx1 > -1:
                        if muons[jet.muonIdx1].isGlobal:
                            newjet = newjet - muons[jet.muonIdx1].p4()
                            muon_pt += muons[jet.muonIdx1].pt
                    if jet.muonIdx2 > -1:
                        if muons[jet.muonIdx2].isGlobal:
                            newjet = newjet - muons[jet.muonIdx2].p4()
                            muon_pt += muons[jet.muonIdx2].pt

            # set the jet pt to the muon subtracted raw pt
            jet.pt = newjet.Pt()
            jet.rawFactor = 0
            # get the proper jet pts for type-1 MET
            jet_pt_noMuL1L2L3 = jet.pt * jec
            jet_pt_noMuL1 = jet.pt * jecL1

            # this step is only needed for v2 MET in 2017 when different JECs are applied compared to the nanoAOD production
            if self.jetReCalibratorProd:
                jet_pt_noMuProdL1L2L3 = jet.pt * jecProd if jet.pt * jecProd > self.unclEnThreshold else jet.pt
                jet_pt_noMuProdL1 = jet.pt * jecL1Prod if jet.pt * jecProd > self.unclEnThreshold else jet.pt
            else:
                jet_pt_noMuProdL1L2L3 = jet_pt_noMuL1L2L3
                jet_pt_noMuProdL1 = jet_pt_noMuL1

            ## setting jet back to central values
            jet.pt = jet_pt
            jet.rawFactor = rawFactor

            # evaluate JER scale factors and uncertainties
            # (cf. https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution and https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyResolution )
            if not self.isData:
                (jet_pt_jerNomVal, jet_pt_jerUpVal,
                 jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt(
                     jet, genJet, rho)
            else:
                # if you want to do something with JER in data, please add it here.
                (jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal) = (1, 1,
                                                                          1)

            # these are the important jet pt values
            #jet_pt_nom      = jet_pt if jet_pt > 0 else 0
            jet_pt_nom = jet_pt * jet_pt_jerNomVal if self.applySmearing else jet_pt
            jet_pt_L1L2L3 = jet_pt_noMuL1L2L3 + muon_pt
            jet_pt_L1 = jet_pt_noMuL1 + muon_pt

            # not nice, but needed for METv2 in 2017
            jet_pt_prodL1L2L3 = jet_pt_noMuProdL1L2L3 + muon_pt
            jet_pt_prodL1 = jet_pt_noMuProdL1 + muon_pt

            if self.metBranchName == 'METFixEE2017':
                # get the delta for removing L1L2L3-L1 corrected jets (corrected with GT from nanoAOD production!!) in the EE region from the default MET branch.
                if jet_pt_prodL1L2L3 > self.unclEnThreshold and 2.65 < abs(
                        jet.eta) < 3.14 and jet_rawpt < 50:
                    delta_x_T1Jet += (
                        jet_pt_prodL1L2L3 - jet_pt_prodL1) * math.cos(
                            jet.phi) + jet_rawpt * math.cos(jet.phi)
                    delta_y_T1Jet += (
                        jet_pt_prodL1L2L3 - jet_pt_prodL1) * math.sin(
                            jet.phi) + jet_rawpt * math.sin(jet.phi)

                # get the delta for removing raw jets in the EE region from the raw MET
                if jet_pt_prodL1L2L3 > self.unclEnThreshold and 2.65 < abs(
                        jet.eta) < 3.14 and jet_rawpt < 50:
                    delta_x_rawJet += jet_rawpt * math.cos(jet.phi)
                    delta_y_rawJet += jet_rawpt * math.sin(jet.phi)

            # don't store the low pt jets in the Jet_pt_nom branch
            if iJet < nJet:
                jets_pt_raw.append(jet_rawpt)
                jets_pt_nom.append(jet_pt_nom)
                jets_mass_raw.append(jet_rawmass)
                jets_corr_JEC.append(jet_pt / jet_rawpt)
                jets_corr_JER.append(
                    jet_pt_jerNomVal)  # can be used to undo JER

                # no need to do this for low pt jets
                jet_mass_nom = jet_pt_jerNomVal * jet_mass if self.applySmearing else jet_mass
                if jet_mass_nom < 0.0:
                    jet_mass_nom *= -1.0
                jets_mass_nom.append(jet_mass_nom)

            if not self.isData:
                jet_pt_jerUp = jet_pt_jerUpVal * jet_pt
                jet_pt_jerDown = jet_pt_jerDownVal * jet_pt

                # evaluate JES uncertainties
                jet_pt_jesUp = {}
                jet_pt_jesDown = {}
                jet_pt_jesUpT1 = {}
                jet_pt_jesDownT1 = {}

                jet_mass_jesUp = {}
                jet_mass_jesDown = {}

                # don't store the low pt jets in the Jet_pt_nom branch
                if iJet < nJet:
                    jets_pt_jerUp.append(jet_pt_jerUpVal * jet_pt)
                    jets_pt_jerDown.append(jet_pt_jerDownVal * jet_pt)
                    jets_mass_jerUp.append(jet_pt_jerUpVal * jet_mass)
                    jets_mass_jerDown.append(jet_pt_jerDownVal * jet_mass)

                for jesUncertainty in self.jesUncertainties:
                    # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties )
                    self.jesUncertainty[jesUncertainty].setJetPt(jet_pt_nom)
                    self.jesUncertainty[jesUncertainty].setJetEta(jet.eta)
                    delta = self.jesUncertainty[jesUncertainty].getUncertainty(
                        True)
                    jet_pt_jesUp[jesUncertainty] = jet_pt_nom * (1. + delta)
                    jet_pt_jesDown[jesUncertainty] = jet_pt_nom * (1. - delta)
                    if iJet < nJet:
                        jets_pt_jesUp[jesUncertainty].append(
                            jet_pt_jesUp[jesUncertainty])
                        jets_pt_jesDown[jesUncertainty].append(
                            jet_pt_jesDown[jesUncertainty])
                        jet_mass_jesUp[jesUncertainty] = jet_mass_nom * (1. +
                                                                         delta)
                        jet_mass_jesDown[jesUncertainty] = jet_mass_nom * (
                            1. - delta)
                        jets_mass_jesUp[jesUncertainty].append(
                            jet_mass_jesUp[jesUncertainty])
                        jets_mass_jesDown[jesUncertainty].append(
                            jet_mass_jesDown[jesUncertainty])

                    # redo JES variations for T1 MET
                    self.jesUncertainty[jesUncertainty].setJetPt(jet_pt_L1L2L3)
                    self.jesUncertainty[jesUncertainty].setJetEta(jet.eta)
                    delta = self.jesUncertainty[jesUncertainty].getUncertainty(
                        True)
                    jet_pt_jesUpT1[jesUncertainty] = jet_pt_L1L2L3 * (1. +
                                                                      delta)
                    jet_pt_jesDownT1[jesUncertainty] = jet_pt_L1L2L3 * (1. -
                                                                        delta)

            # progate JER and JES corrections and uncertainties to MET. Only propagate JECs to MET if the corrected pt without the muon is above the threshold
            if jet_pt_noMuL1L2L3 > self.unclEnThreshold and (jet.neEmEF +
                                                             jet.chEmEF) < 0.9:
                if not (
                        self.metBranchName == 'METFixEE2017'
                        and 2.65 < abs(jet.eta) < 3.14 and jet.pt *
                    (1 - jet.rawFactor) < 50
                ):  # do not re-correct for jets that aren't included in METv2 recipe
                    jet_cosPhi = math.cos(jet.phi)
                    jet_sinPhi = math.sin(jet.phi)
                    met_px_nom = met_px_nom - (jet_pt_L1L2L3 -
                                               jet_pt_L1) * jet_cosPhi
                    met_py_nom = met_py_nom - (jet_pt_L1L2L3 -
                                               jet_pt_L1) * jet_sinPhi
                    if not self.isData:
                        met_px_jer = met_px_jer - (
                            jet_pt_L1L2L3 * jet_pt_jerNomVal -
                            jet_pt_L1) * jet_cosPhi
                        met_py_jer = met_py_jer - (
                            jet_pt_L1L2L3 * jet_pt_jerNomVal -
                            jet_pt_L1) * jet_sinPhi
                        met_px_jerUp = met_px_jerUp - (
                            jet_pt_L1L2L3 * jet_pt_jerUpVal -
                            jet_pt_L1) * jet_cosPhi
                        met_py_jerUp = met_py_jerUp - (
                            jet_pt_L1L2L3 * jet_pt_jerUpVal -
                            jet_pt_L1) * jet_sinPhi
                        met_px_jerDown = met_px_jerDown - (
                            jet_pt_L1L2L3 * jet_pt_jerDownVal -
                            jet_pt_L1) * jet_cosPhi
                        met_py_jerDown = met_py_jerDown - (
                            jet_pt_L1L2L3 * jet_pt_jerDownVal -
                            jet_pt_L1) * jet_sinPhi
                        for jesUncertainty in self.jesUncertainties:
                            met_px_jesUp[jesUncertainty] = met_px_jesUp[
                                jesUncertainty] - (
                                    jet_pt_jesUpT1[jesUncertainty] -
                                    jet_pt_L1) * jet_cosPhi
                            met_py_jesUp[jesUncertainty] = met_py_jesUp[
                                jesUncertainty] - (
                                    jet_pt_jesUpT1[jesUncertainty] -
                                    jet_pt_L1) * jet_sinPhi
                            met_px_jesDown[jesUncertainty] = met_px_jesDown[
                                jesUncertainty] - (
                                    jet_pt_jesDownT1[jesUncertainty] -
                                    jet_pt_L1) * jet_cosPhi
                            met_py_jesDown[jesUncertainty] = met_py_jesDown[
                                jesUncertainty] - (
                                    jet_pt_jesDownT1[jesUncertainty] -
                                    jet_pt_L1) * jet_sinPhi

        # propagate "unclustered energy" uncertainty to MET
        if self.metBranchName == 'METFixEE2017':
            # Remove the L1L2L3-L1 corrected jets in the EE region from the default MET branch
            def_met_px += delta_x_T1Jet
            def_met_py += delta_y_T1Jet

            # get unclustered energy part that is removed in the v2 recipe
            met_unclEE_x = def_met_px - t1met_px
            met_unclEE_y = def_met_py - t1met_py

            # finalize the v2 recipe for the rawMET by removing the unclustered part in the EE region
            met_px_nom += delta_x_rawJet - met_unclEE_x
            met_py_nom += delta_y_rawJet - met_unclEE_y

            if not self.isData:
                # apply v2 recipe correction factor also to JER central value and variations
                met_px_jer += delta_x_rawJet - met_unclEE_x
                met_py_jer += delta_y_rawJet - met_unclEE_y
                met_px_jerUp += delta_x_rawJet - met_unclEE_x
                met_py_jerUp += delta_y_rawJet - met_unclEE_y
                met_px_jerDown += delta_x_rawJet - met_unclEE_x
                met_py_jerDown += delta_y_rawJet - met_unclEE_y
                for jesUncertainty in self.jesUncertainties:
                    met_px_jesUp[
                        jesUncertainty] += delta_x_rawJet - met_unclEE_x
                    met_py_jesUp[
                        jesUncertainty] += delta_y_rawJet - met_unclEE_y
                    met_px_jesDown[
                        jesUncertainty] += delta_x_rawJet - met_unclEE_x
                    met_py_jesDown[
                        jesUncertainty] += delta_y_rawJet - met_unclEE_y

        if not self.isData:
            (met_px_unclEnUp, met_py_unclEnUp) = (met_px_nom, met_py_nom)
            (met_px_unclEnDown, met_py_unclEnDown) = (met_px_nom, met_py_nom)
            met_deltaPx_unclEn = getattr(
                event, self.metBranchName + "_MetUnclustEnUpDeltaX")
            met_deltaPy_unclEn = getattr(
                event, self.metBranchName + "_MetUnclustEnUpDeltaY")
            met_px_unclEnUp = met_px_unclEnUp + met_deltaPx_unclEn
            met_py_unclEnUp = met_py_unclEnUp + met_deltaPy_unclEn
            met_px_unclEnDown = met_px_unclEnDown - met_deltaPx_unclEn
            met_py_unclEnDown = met_py_unclEnDown - met_deltaPy_unclEn

        self.out.fillBranch("%s_pt_raw" % self.jetBranchName, jets_pt_raw)
        self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom)
        self.out.fillBranch("%s_corr_JEC" % self.jetBranchName, jets_corr_JEC)
        self.out.fillBranch("%s_corr_JER" % self.jetBranchName, jets_corr_JER)
        if not self.isData:
            self.out.fillBranch("%s_pt_jerUp" % self.jetBranchName,
                                jets_pt_jerUp)
            self.out.fillBranch("%s_pt_jerDown" % self.jetBranchName,
                                jets_pt_jerDown)

        self.out.fillBranch("%s_pt_nom" % self.metBranchName,
                            math.sqrt(met_px_nom**2 + met_py_nom**2))
        self.out.fillBranch("%s_phi_nom" % self.metBranchName,
                            math.atan2(met_py_nom, met_px_nom))

        self.out.fillBranch("%s_mass_raw" % self.jetBranchName, jets_mass_raw)
        self.out.fillBranch("%s_mass_nom" % self.jetBranchName, jets_mass_nom)

        if not self.isData:
            self.out.fillBranch("%s_mass_jerUp" % self.jetBranchName,
                                jets_mass_jerUp)
            self.out.fillBranch("%s_mass_jerDown" % self.jetBranchName,
                                jets_mass_jerDown)

        if not self.isData:
            self.out.fillBranch("%s_pt_jer" % self.metBranchName,
                                math.sqrt(met_px_jer**2 + met_py_jer**2))
            self.out.fillBranch("%s_phi_jer" % self.metBranchName,
                                math.atan2(met_py_jer, met_px_jer))
            self.out.fillBranch("%s_pt_jerUp" % self.metBranchName,
                                math.sqrt(met_px_jerUp**2 + met_py_jerUp**2))
            self.out.fillBranch("%s_phi_jerUp" % self.metBranchName,
                                math.atan2(met_py_jerUp, met_px_jerUp))
            self.out.fillBranch(
                "%s_pt_jerDown" % self.metBranchName,
                math.sqrt(met_px_jerDown**2 + met_py_jerDown**2))
            self.out.fillBranch("%s_phi_jerDown" % self.metBranchName,
                                math.atan2(met_py_jerDown, met_px_jerDown))

            for jesUncertainty in self.jesUncertainties:
                self.out.fillBranch(
                    "%s_pt_jes%sUp" % (self.jetBranchName, jesUncertainty),
                    jets_pt_jesUp[jesUncertainty])
                self.out.fillBranch(
                    "%s_pt_jes%sDown" % (self.jetBranchName, jesUncertainty),
                    jets_pt_jesDown[jesUncertainty])

                self.out.fillBranch(
                    "%s_pt_jes%sUp" % (self.metBranchName, jesUncertainty),
                    math.sqrt(met_px_jesUp[jesUncertainty]**2 +
                              met_py_jesUp[jesUncertainty]**2))
                self.out.fillBranch(
                    "%s_phi_jes%sUp" % (self.metBranchName, jesUncertainty),
                    math.atan2(met_py_jesUp[jesUncertainty],
                               met_px_jesUp[jesUncertainty]))
                self.out.fillBranch(
                    "%s_pt_jes%sDown" % (self.metBranchName, jesUncertainty),
                    math.sqrt(met_px_jesDown[jesUncertainty]**2 +
                              met_py_jesDown[jesUncertainty]**2))
                self.out.fillBranch(
                    "%s_phi_jes%sDown" % (self.metBranchName, jesUncertainty),
                    math.atan2(met_py_jesDown[jesUncertainty],
                               met_px_jesDown[jesUncertainty]))

                self.out.fillBranch(
                    "%s_mass_jes%sUp" % (self.jetBranchName, jesUncertainty),
                    jets_mass_jesUp[jesUncertainty])
                self.out.fillBranch(
                    "%s_mass_jes%sDown" % (self.jetBranchName, jesUncertainty),
                    jets_mass_jesDown[jesUncertainty])

            self.out.fillBranch(
                "%s_pt_unclustEnUp" % self.metBranchName,
                math.sqrt(met_px_unclEnUp**2 + met_py_unclEnUp**2))
            self.out.fillBranch("%s_phi_unclustEnUp" % self.metBranchName,
                                math.atan2(met_py_unclEnUp, met_px_unclEnUp))
            self.out.fillBranch(
                "%s_pt_unclustEnDown" % self.metBranchName,
                math.sqrt(met_px_unclEnDown**2 + met_py_unclEnDown**2))
            self.out.fillBranch(
                "%s_phi_unclustEnDown" % self.metBranchName,
                math.atan2(met_py_unclEnDown, met_px_unclEnDown))

        return True
class jetmetUncertaintiesProducer(Module):
    def __init__(self, era, globalTag, jesUncertainties = [ "Total" ], jetType = "AK4PFchs", redoJEC=False, noGroom=False, jerTag="", jmrVals = [], jmsVals = []):

        self.era = era
        self.redoJEC = redoJEC
        self.noGroom = noGroom
        #--------------------------------------------------------------------------------------------
        # CV: globalTag and jetType not yet used in the jet smearer, as there is no consistent set of 
        #     txt files for JES uncertainties and JER scale factors and uncertainties yet
        #--------------------------------------------------------------------------------------------

        self.jesUncertainties = jesUncertainties
        # smear jet pT to account for measured difference in JER between data and simulation.
        if jerTag != "":
            self.jerInputFileName = jerTag + "_PtResolution_" + jetType + ".txt"
            self.jerUncertaintyInputFileName = jerTag + "_SF_"  + jetType + ".txt"
        else:
            print "WARNING: jerTag is empty!!! This module will soon be deprecated! Please use jetmetHelperRun2 in the future."
            if era == "2016":
                self.jerInputFileName = "Summer16_25nsV1_MC_PtResolution_" + jetType + ".txt"
                self.jerUncertaintyInputFileName = "Summer16_25nsV1_MC_SF_" + jetType + ".txt"
            elif era == "2017" or era == "2018": # use Fall17 as temporary placeholder until post-Moriond 2019 JERs are out
                self.jerInputFileName = "Fall17_V3_MC_PtResolution_" + jetType + ".txt"
                self.jerUncertaintyInputFileName = "Fall17_V3_MC_SF_" + jetType + ".txt"

        #jet mass resolution: https://twiki.cern.ch/twiki/bin/view/CMS/JetWtagging
        self.jmrVals = jmrVals
        if not self.jmrVals:
            print "WARNING: jmrVals is empty!!! Using default values. This module will soon be deprecated! Please use jetmetHelperRun2 in the future."
            self.jmrVals = [1.0, 1.2, 0.8] #nominal, up, down
            # Use 2017 values for 2018 until 2018 are released
            if self.era in ["2017","2018"]:
                self.jmrVals = [1.09, 1.14, 1.04] 

        self.jetSmearer = jetSmearer(globalTag, jetType, self.jerInputFileName, self.jerUncertaintyInputFileName, self.jmrVals)

        if "AK4" in jetType : 
            self.jetBranchName = "Jet"
            self.genJetBranchName = "GenJet"
            self.genSubJetBranchName = None
            self.doGroomed = False
            self.corrMET = True
        elif "AK8" in jetType :
            self.jetBranchName = "FatJet"
            self.subJetBranchName = "SubJet"
            self.genJetBranchName = "GenJetAK8"
            self.genSubJetBranchName = "SubGenJetAK8"
            if not self.noGroom:
                self.doGroomed = True
                self.puppiCorrFile = ROOT.TFile.Open(os.environ['CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/puppiCorr.root")
                self.puppisd_corrGEN = self.puppiCorrFile.Get("puppiJECcorr_gen")
                self.puppisd_corrRECO_cen = self.puppiCorrFile.Get("puppiJECcorr_reco_0eta1v3")
                self.puppisd_corrRECO_for = self.puppiCorrFile.Get("puppiJECcorr_reco_1v3eta2v5")
            else:
                self.doGroomed = False
            self.corrMET = False
        else:
            raise ValueError("ERROR: Invalid jet type = '%s'!" % jetType)
        self.metBranchName = "MET"
        self.rhoBranchName = "fixedGridRhoFastjetAll"
        self.lenVar = "n" + self.jetBranchName

        #jet mass scale
        self.jmsVals = jmsVals
        if not self.jmsVals:
            print "WARNING: jmsVals is empty!!! Using default values! This module will soon be deprecated! Please use jetmetHelperRun2 in the future."
            #2016 values 
            self.jmsVals = [1.00, 0.9906, 1.0094] #nominal, down, up
            # Use 2017 values for 2018 until 2018 are released
            if self.era in ["2017","2018"]:
                self.jmsVals = [0.982, 0.978, 0.986]

        # read jet energy scale (JES) uncertainties
        # (downloaded from https://twiki.cern.ch/twiki/bin/view/CMS/JECDataMC )
        self.jesInputArchivePath = os.environ['CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/"
        # Text files are now tarred so must extract first into temporary directory (gets deleted during python memory management at script exit)
        self.jesArchive = tarfile.open(self.jesInputArchivePath+globalTag+".tgz", "r:gz")
        self.jesInputFilePath = tempfile.mkdtemp()
        self.jesArchive.extractall(self.jesInputFilePath)
        
        
        if len(jesUncertainties) == 1 and jesUncertainties[0] == "Total":
            self.jesUncertaintyInputFileName = globalTag + "_Uncertainty_" + jetType + ".txt"
        else:
            self.jesUncertaintyInputFileName = globalTag + "_UncertaintySources_" + jetType + ".txt"

        # read all uncertainty source names from the loaded file
        if jesUncertainties[0] == "All":
            with open(self.jesInputFilePath+'/'+self.jesUncertaintyInputFileName) as f:
                lines = f.read().split("\n")
                sources = filter(lambda x: x.startswith("[") and x.endswith("]"), lines)
                sources = map(lambda x: x[1:-1], sources)
                self.jesUncertainties = sources
            
        if self.redoJEC :
            self.jetReCalibrator = JetReCalibrator(globalTag, jetType , True, self.jesInputFilePath, calculateSeparateCorrections = False, calculateType1METCorrection  = False)
        

        # define energy threshold below which jets are considered as "unclustered energy"
        # (cf. JetMETCorrections/Type1MET/python/correctionTermsPfMetType1Type2_cff.py )
        self.unclEnThreshold = 15.

        # load libraries for accessing JES scale factors and uncertainties from txt files
        for library in [ "libCondFormatsJetMETObjects", "libPhysicsToolsNanoAODTools" ]:
            if library not in ROOT.gSystem.GetLibraries():
                print("Load Library '%s'" % library.replace("lib", ""))
                ROOT.gSystem.Load(library)

    def beginJob(self):

        print("Loading jet energy scale (JES) uncertainties from file '%s'" % os.path.join(self.jesInputFilePath, self.jesUncertaintyInputFileName))
        #self.jesUncertainty = ROOT.JetCorrectionUncertainty(os.path.join(self.jesInputFilePath, self.jesUncertaintyInputFileName))
    
        self.jesUncertainty = {} 
        # implementation didn't seem to work for factorized JEC, try again another way
        for jesUncertainty in self.jesUncertainties:
            jesUncertainty_label = jesUncertainty
            if jesUncertainty == 'Total' and len(self.jesUncertainties) == 1:
                jesUncertainty_label = ''
            pars = ROOT.JetCorrectorParameters(os.path.join(self.jesInputFilePath, self.jesUncertaintyInputFileName),jesUncertainty_label)
            self.jesUncertainty[jesUncertainty] = ROOT.JetCorrectionUncertainty(pars)    

        self.jetSmearer.beginJob()

    def endJob(self):
        self.jetSmearer.endJob()
        shutil.rmtree(self.jesInputFilePath)

    def beginFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        self.out = wrappedOutputTree
        print inputFile, outputFile, inputTree, wrappedOutputTree
        self.out.branch("%s_pt_raw" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_pt_nom" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_mass_raw" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_mass_nom" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_corr_JEC" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_corr_JER" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_corr_JMS" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_corr_JMR" % self.jetBranchName, "F", lenVar=self.lenVar)

        self.out.branch("%s_L2L3" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_L1" % self.jetBranchName, "F", lenVar=self.lenVar)
        self.out.branch("%s_LRes" % self.jetBranchName, "F", lenVar=self.lenVar)

        if self.doGroomed:
            self.out.branch("%s_msoftdrop_raw" % self.jetBranchName, "F", lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_nom" % self.jetBranchName, "F", lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_tau21DDT_nom" % self.jetBranchName, "F", lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_corr_JMR" % self.jetBranchName, "F", lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_corr_JMS" % self.jetBranchName, "F", lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_corr_PUPPI" % self.jetBranchName, "F", lenVar=self.lenVar)
            
        if self.corrMET:
            self.out.branch("%s_pt_nom" % self.metBranchName, "F")
            self.out.branch("%s_phi_nom" % self.metBranchName, "F")
        
        for shift in [ "Up", "Down" ]:
            self.out.branch("%s_pt_jer%s" % (self.jetBranchName, shift), "F", lenVar=self.lenVar)
            self.out.branch("%s_mass_jer%s" % (self.jetBranchName, shift), "F", lenVar=self.lenVar)
            self.out.branch("%s_mass_jmr%s" % (self.jetBranchName, shift), "F", lenVar=self.lenVar)
            self.out.branch("%s_mass_jms%s" % (self.jetBranchName, shift), "F", lenVar=self.lenVar)

            if self.doGroomed: 
                self.out.branch("%s_msoftdrop_jer%s" % (self.jetBranchName, shift), "F", lenVar=self.lenVar)
                self.out.branch("%s_msoftdrop_jmr%s" % (self.jetBranchName, shift), "F", lenVar=self.lenVar)
                self.out.branch("%s_msoftdrop_jms%s" % (self.jetBranchName, shift), "F", lenVar=self.lenVar)
                self.out.branch("%s_msoftdrop_tau21DDT_jer%s" % (self.jetBranchName, shift), "F", lenVar=self.lenVar)
                self.out.branch("%s_msoftdrop_tau21DDT_jmr%s" % (self.jetBranchName, shift), "F", lenVar=self.lenVar)
                self.out.branch("%s_msoftdrop_tau21DDT_jms%s" % (self.jetBranchName, shift), "F", lenVar=self.lenVar)


            if self.corrMET :
                self.out.branch("%s_pt_jer%s" % (self.metBranchName, shift), "F")
                self.out.branch("%s_phi_jer%s" % (self.metBranchName, shift), "F")
            for jesUncertainty in self.jesUncertainties:
                self.out.branch("%s_pt_jes%s%s" % (self.jetBranchName, jesUncertainty, shift), "F", lenVar=self.lenVar)
                self.out.branch("%s_mass_jes%s%s" % (self.jetBranchName, jesUncertainty, shift), "F", lenVar=self.lenVar)
                if self.doGroomed:
                    self.out.branch("%s_msoftdrop_jes%s%s" % (self.jetBranchName, jesUncertainty, shift), "F", lenVar=self.lenVar)
                if self.corrMET :
                    self.out.branch("%s_pt_jes%s%s" % (self.metBranchName, jesUncertainty, shift), "F")
                    self.out.branch("%s_phi_jes%s%s" % (self.metBranchName, jesUncertainty, shift), "F")
            if self.corrMET :
                self.out.branch("%s_pt_unclustEn%s" % (self.metBranchName, shift), "F")
                self.out.branch("%s_phi_unclustEn%s" % (self.metBranchName, shift), "F")
                        
    def endFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        pass
    
    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        jets = Collection(event, self.jetBranchName )
        genJets = Collection(event, self.genJetBranchName )
        
        if self.doGroomed :
            subJets = Collection(event, self.subJetBranchName )
            genSubJets = Collection(event, self.genSubJetBranchName )
            genSubJetMatcher = matchObjectCollectionMultiple( genJets, genSubJets, dRmax=0.8 )
        
        self.jetSmearer.setSeed(event)

        jet_L1 = []
        jet_L2L3 = []
        jet_LRes = []
        
        jets_pt_raw = []
        jets_pt_nom = []
        jets_mass_raw = []
        jets_mass_nom = []
        
        jets_corr_JEC = []
        jets_corr_JER = []
        jets_corr_JMS = []
        jets_corr_JMR = []
        
        jets_pt_jerUp   = []
        jets_pt_jerDown = []
        jets_pt_jesUp   = {}
        jets_pt_jesDown = {}
        
        jets_mass_jerUp   = []
        jets_mass_jerDown = []
        jets_mass_jmrUp   = []
        jets_mass_jmrDown = []
        jets_mass_jesUp   = {}
        jets_mass_jesDown = {}
        jets_mass_jmsUp   = []
        jets_mass_jmsDown = []
        
        for jesUncertainty in self.jesUncertainties:
            jets_pt_jesUp[jesUncertainty]   = []
            jets_pt_jesDown[jesUncertainty] = []
            jets_mass_jesUp[jesUncertainty]   = []
            jets_mass_jesDown[jesUncertainty] = []
        
        if self.corrMET :
            met = Object(event, self.metBranchName)
            ( met_px,         met_py         ) = ( met.pt*math.cos(met.phi), met.pt*math.sin(met.phi) )
            ( met_px_nom, met_py_nom ) = ( met_px, met_py )
            ( met_px_jerUp,   met_py_jerUp   ) = ( met_px, met_py )
            ( met_px_jerDown, met_py_jerDown ) = ( met_px, met_py )
            ( met_px_jesUp,   met_py_jesUp   ) = ( {}, {} )
            ( met_px_jesDown, met_py_jesDown ) = ( {}, {} )
            for jesUncertainty in self.jesUncertainties:
                met_px_jesUp[jesUncertainty]   = met_px
                met_py_jesUp[jesUncertainty]   = met_py
                met_px_jesDown[jesUncertainty] = met_px
                met_py_jesDown[jesUncertainty] = met_py
        
        if self.doGroomed:
            jets_msdcorr_raw = []
            jets_msdcorr_nom = []
            jets_msdcorr_corr_JMR   = []
            jets_msdcorr_corr_JMS   = []
            jets_msdcorr_corr_PUPPI = []
            jets_msdcorr_jerUp   = []
            jets_msdcorr_jerDown = []
            jets_msdcorr_jmrUp   = []
            jets_msdcorr_jmrDown = []
            jets_msdcorr_jesUp   = {}
            jets_msdcorr_jesDown = {}
            jets_msdcorr_jmsUp   = []
            jets_msdcorr_jmsDown = []
            jets_msdcorr_tau21DDT_nom = []
            jets_msdcorr_tau21DDT_jerUp = []
            jets_msdcorr_tau21DDT_jerDown = []
            jets_msdcorr_tau21DDT_jmrUp = []
            jets_msdcorr_tau21DDT_jmrDown = []
            jets_msdcorr_tau21DDT_jmsUp = []
            jets_msdcorr_tau21DDT_jmsDown = []
            for jesUncertainty in self.jesUncertainties:
                jets_msdcorr_jesUp[jesUncertainty]   = []
                jets_msdcorr_jesDown[jesUncertainty] = []
        
        rho = getattr(event, self.rhoBranchName)
        
        # match reconstructed jets to generator level ones
        # (needed to evaluate JER scale factors and uncertainties)
        pairs = matchObjectCollection(jets, genJets)
        
        for jet in jets:
            #jet pt and mass corrections
            jet_pt=jet.pt
            jet_mass=jet.mass


            jet_L1.append(self.jetReCalibrator.getCorrection(jet,rho, corrector=self.jetReCalibrator.separateJetCorrectors["myL1"]))
            jet_L2L3.append(self.jetReCalibrator.getCorrection(jet,rho, corrector=self.jetReCalibrator.separateJetCorrectors["myL2L3"]))
            jet_LRes.append(self.jetReCalibrator.getCorrection(jet,rho, corrector=self.jetReCalibrator.separateJetCorrectors["myRes"]))

            #redo JECs if desired
            if hasattr(jet, "rawFactor"):
                jet_rawpt = jet_pt * (1 - jet.rawFactor)
                jet_rawmass = jet_mass * (1 - jet.rawFactor)
            else:
                jet_rawpt = -1.0 * jet_pt #If factor not present factor will be saved as -1
                jet_rawmass = -1.0 * jet_mass #If factor not present factor will be saved as -1
            if self.redoJEC :
                (jet_pt, jet_mass) = self.jetReCalibrator.correct(jet,rho)
                jet.pt = jet_pt
                jet.mass = jet_mass
            jets_pt_raw.append(jet_rawpt)
            jets_mass_raw.append(jet_rawmass)
            jets_corr_JEC.append(jet_pt/jet_rawpt)

            
            
            
            genJet = pairs[jet]
            if self.doGroomed:                
                genGroomedSubJets = genSubJetMatcher[genJet] if genJet != None else None
                genGroomedJet = genGroomedSubJets[0].p4() + genGroomedSubJets[1].p4() if genGroomedSubJets != None and len(genGroomedSubJets) >= 2 else None
                if jet.subJetIdx1 >= 0 and jet.subJetIdx2 >= 0 :
                    groomedP4 = subJets[ jet.subJetIdx1 ].p4() + subJets[ jet.subJetIdx2].p4() #check subjet jecs
                else :
                    groomedP4 = None
                
                # LC: Apply PUPPI SD mass correction https://github.com/cms-jet/PuppiSoftdropMassCorr/
                puppisd_genCorr = self.puppisd_corrGEN.Eval(jet.pt)
                if abs(jet.eta) <= 1.3:
                    puppisd_recoCorr = self.puppisd_corrRECO_cen.Eval(jet.pt)
                else:
                    puppisd_recoCorr = self.puppisd_corrRECO_for.Eval(jet.pt)
                
                puppisd_total = puppisd_genCorr * puppisd_recoCorr
                jets_msdcorr_corr_PUPPI.append(puppisd_total)
                if groomedP4 != None:
                    groomedP4.SetPtEtaPhiM(groomedP4.Perp(), groomedP4.Eta(), groomedP4.Phi(), groomedP4.M()*puppisd_total)
            
            # evaluate JER scale factors and uncertainties
            # (cf. https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution and https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyResolution )
            ( jet_pt_jerNomVal, jet_pt_jerUpVal, jet_pt_jerDownVal ) = self.jetSmearer.getSmearValsPt(jet, genJet, rho)
            jets_corr_JER.append(jet_pt_jerNomVal)
            
            jet_pt_nom           = jet_pt_jerNomVal *jet_pt
            if jet_pt_nom < 0.0:
                jet_pt_nom *= -1.0
            jet_pt_jerUp         = jet_pt_jerUpVal  *jet_pt
            jet_pt_jerDown       = jet_pt_jerDownVal*jet_pt
            jets_pt_nom    .append(jet_pt_nom)
            jets_pt_jerUp  .append(jet_pt_jerUpVal*jet_pt)
            jets_pt_jerDown.append(jet_pt_jerDownVal*jet_pt)

            # evaluate JES uncertainties
            jet_pt_jesUp   = {}
            jet_pt_jesDown = {}
            jet_mass_jesUp   = {}
            jet_mass_jesDown = {}
            jet_mass_jmsUp   = []
            jet_mass_jmsDown = []
            
            # Evaluate JMS and JMR scale factors and uncertainties
            jmsNomVal = self.jmsVals[0]
            jmsDownVal = self.jmsVals[1]
            jmsUpVal = self.jmsVals[2]
            ( jet_mass_jmrNomVal, jet_mass_jmrUpVal, jet_mass_jmrDownVal ) = self.jetSmearer.getSmearValsM(jet, genJet)
            jets_corr_JMS   .append(jmsNomVal)
            jets_corr_JMR   .append(jet_mass_jmrNomVal)

            jet_mass_nom           = jet_pt_jerNomVal*jet_mass_jmrNomVal*jmsNomVal*jet_mass
            if jet_mass_nom < 0.0:
                jet_mass_nom *= -1.0
            jets_mass_nom    .append(jet_mass_nom)
            jets_mass_jerUp  .append(jet_pt_jerUpVal  *jet_mass_jmrNomVal *jmsNomVal  *jet_mass)
            jets_mass_jerDown.append(jet_pt_jerDownVal*jet_mass_jmrNomVal *jmsNomVal  *jet_mass)
            jets_mass_jmrUp  .append(jet_pt_jerNomVal *jet_mass_jmrUpVal  *jmsNomVal  *jet_mass)
            jets_mass_jmrDown.append(jet_pt_jerNomVal *jet_mass_jmrDownVal*jmsNomVal  *jet_mass)
            jets_mass_jmsUp  .append(jet_pt_jerNomVal *jet_mass_jmrNomVal *jmsUpVal   *jet_mass)
            jets_mass_jmsDown.append(jet_pt_jerNomVal *jet_mass_jmrNomVal *jmsDownVal *jet_mass)

            if self.doGroomed :
                # evaluate JES uncertainties
                jet_msdcorr_jesUp   = {}
                jet_msdcorr_jesDown = {}

                # Evaluate JMS and JMR scale factors and uncertainties
                ( jet_msdcorr_jmrNomVal, jet_msdcorr_jmrUpVal, jet_msdcorr_jmrDownVal ) = self.jetSmearer.getSmearValsM(groomedP4, genGroomedJet) if groomedP4 != None and genGroomedJet != None else (0.,0.,0.)
                jet_msdcorr_raw = groomedP4.M() if groomedP4 != None else 0.0
                jets_msdcorr_corr_JMS.append(jmsNomVal)
                jets_msdcorr_corr_JMR.append(jet_msdcorr_jmrNomVal)

                if jet_msdcorr_raw < 0.0:
                    jet_msdcorr_raw *= -1.0
                jet_msdcorr_nom           = jet_pt_jerNomVal*jet_msdcorr_jmrNomVal*jmsNomVal*jet_msdcorr_raw
                jets_msdcorr_raw    .append(jet_msdcorr_raw) #fix later so jec's not applied - LC: Current PUPPI SD mass correction implementation needs the JECs applied before looking up the correction so make sure that's accounted for if this is changed.
                jets_msdcorr_nom    .append(jet_msdcorr_nom)
                jets_msdcorr_jerUp  .append(jet_pt_jerUpVal  *jet_msdcorr_jmrNomVal *jmsNomVal  *jet_msdcorr_raw)
                jets_msdcorr_jerDown.append(jet_pt_jerDownVal*jet_msdcorr_jmrNomVal *jmsNomVal  *jet_msdcorr_raw)
                jets_msdcorr_jmrUp  .append(jet_pt_jerNomVal *jet_msdcorr_jmrUpVal  *jmsNomVal  *jet_msdcorr_raw)
                jets_msdcorr_jmrDown.append(jet_pt_jerNomVal *jet_msdcorr_jmrDownVal*jmsNomVal  *jet_msdcorr_raw)
                jets_msdcorr_jmsUp  .append(jet_pt_jerNomVal *jet_msdcorr_jmrNomVal *jmsUpVal   *jet_msdcorr_raw)
                jets_msdcorr_jmsDown.append(jet_pt_jerNomVal *jet_msdcorr_jmrNomVal *jmsDownVal *jet_msdcorr_raw)

                #Also evaluated JMS&JMR SD corr in tau21DDT region: https://twiki.cern.ch/twiki/bin/viewauth/CMS/JetWtagging#tau21DDT_0_43
                if self.era in ["2016"]:
                    jmstau21DDTNomVal = 1.014
                    jmstau21DDTDownVal = 1.007
                    jmstau21DDTUpVal = 1.021
                    self.jetSmearer.jmr_vals = [1.086,1.176,0.996]
                elif self.era in ["2017","2018"]:
                    jmstau21DDTNomVal = 0.983
                    jmstau21DDTDownVal = 0.976
                    jmstau21DDTUpVal = 0.99
                    self.jetSmearer.jmr_vals = [1.080,1.161,0.999]

                ( jet_msdcorr_tau21DDT_jmrNomVal, jet_msdcorr_tau21DDT_jmrUpVal, jet_msdcorr_tau21DDT_jmrDownVal ) = self.jetSmearer.getSmearValsM(groomedP4, genGroomedJet) if groomedP4 != None and genGroomedJet != None else (0.,0.,0.)
                jet_msdcorr_tau21DDT_nom           = jet_pt_jerNomVal*jet_msdcorr_tau21DDT_jmrNomVal*jmstau21DDTNomVal*jet_msdcorr_raw
                jets_msdcorr_tau21DDT_nom    .append(jet_msdcorr_tau21DDT_nom)
                jets_msdcorr_tau21DDT_jerUp  .append(jet_pt_jerUpVal  *jet_msdcorr_tau21DDT_jmrNomVal *jmstau21DDTNomVal  *jet_msdcorr_raw)
                jets_msdcorr_tau21DDT_jerDown.append(jet_pt_jerDownVal*jet_msdcorr_tau21DDT_jmrNomVal *jmstau21DDTNomVal  *jet_msdcorr_raw)
                jets_msdcorr_tau21DDT_jmrUp  .append(jet_pt_jerNomVal *jet_msdcorr_tau21DDT_jmrUpVal  *jmstau21DDTNomVal  *jet_msdcorr_raw)
                jets_msdcorr_tau21DDT_jmrDown.append(jet_pt_jerNomVal *jet_msdcorr_tau21DDT_jmrDownVal*jmstau21DDTNomVal  *jet_msdcorr_raw)
                jets_msdcorr_tau21DDT_jmsUp  .append(jet_pt_jerNomVal *jet_msdcorr_tau21DDT_jmrNomVal *jmstau21DDTUpVal   *jet_msdcorr_raw)
                jets_msdcorr_tau21DDT_jmsDown.append(jet_pt_jerNomVal *jet_msdcorr_tau21DDT_jmrNomVal *jmstau21DDTDownVal *jet_msdcorr_raw)

                #Restore original jmr_vals in jetSmearer
                self.jetSmearer.jmr_vals = self.jmrVals
            
            for jesUncertainty in self.jesUncertainties:
                # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties )
                self.jesUncertainty[jesUncertainty].setJetPt(jet_pt_nom)
                self.jesUncertainty[jesUncertainty].setJetEta(jet.eta)
                delta = self.jesUncertainty[jesUncertainty].getUncertainty(True)
                jet_pt_jesUp[jesUncertainty]   = jet_pt_nom*(1. + delta)
                jet_pt_jesDown[jesUncertainty] = jet_pt_nom*(1. - delta)
                jets_pt_jesUp[jesUncertainty].append(jet_pt_jesUp[jesUncertainty])
                jets_pt_jesDown[jesUncertainty].append(jet_pt_jesDown[jesUncertainty])
                jet_mass_jesUp   [jesUncertainty] = jet_mass_nom*(1. + delta)
                jet_mass_jesDown [jesUncertainty] = jet_mass_nom*(1. - delta)
                jets_mass_jesUp  [jesUncertainty].append(jet_mass_jesUp[jesUncertainty])
                jets_mass_jesDown[jesUncertainty].append(jet_mass_jesDown[jesUncertainty])
                if self.doGroomed :
                    jet_msdcorr_jesUp   [jesUncertainty] = jet_msdcorr_nom*(1. + delta)
                    jet_msdcorr_jesDown [jesUncertainty] = jet_msdcorr_nom*(1. - delta)
                    jets_msdcorr_jesUp  [jesUncertainty].append(jet_msdcorr_jesUp[jesUncertainty])
                    jets_msdcorr_jesDown[jesUncertainty].append(jet_msdcorr_jesDown[jesUncertainty])


            # propagate JER and JES corrections and uncertainties to MET
            if self.corrMET and jet_pt_nom > self.unclEnThreshold:
                jet_cosPhi = math.cos(jet.phi)
                jet_sinPhi = math.sin(jet.phi)
                met_px_nom = met_px_nom - (jet_pt_nom - jet_pt)*jet_cosPhi
                met_py_nom = met_py_nom - (jet_pt_nom - jet_pt)*jet_sinPhi
                met_px_jerUp   = met_px_jerUp   - (jet_pt_jerUp   - jet_pt_nom)*jet_cosPhi
                met_py_jerUp   = met_py_jerUp   - (jet_pt_jerUp   - jet_pt_nom)*jet_sinPhi
                met_px_jerDown = met_px_jerDown - (jet_pt_jerDown - jet_pt_nom)*jet_cosPhi
                met_py_jerDown = met_py_jerDown - (jet_pt_jerDown - jet_pt_nom)*jet_sinPhi
                for jesUncertainty in self.jesUncertainties:
                    met_px_jesUp[jesUncertainty]   = met_px_jesUp[jesUncertainty]   - (jet_pt_jesUp[jesUncertainty]   - jet_pt_nom)*jet_cosPhi
                    met_py_jesUp[jesUncertainty]   = met_py_jesUp[jesUncertainty]   - (jet_pt_jesUp[jesUncertainty]   - jet_pt_nom)*jet_sinPhi
                    met_px_jesDown[jesUncertainty] = met_px_jesDown[jesUncertainty] - (jet_pt_jesDown[jesUncertainty] - jet_pt_nom)*jet_cosPhi
                    met_py_jesDown[jesUncertainty] = met_py_jesDown[jesUncertainty] - (jet_pt_jesDown[jesUncertainty] - jet_pt_nom)*jet_sinPhi

        # propagate "unclustered energy" uncertainty to MET
        if self.corrMET :
            ( met_px_unclEnUp,   met_py_unclEnUp   ) = ( met_px, met_py )
            ( met_px_unclEnDown, met_py_unclEnDown ) = ( met_px, met_py )
            met_deltaPx_unclEn = getattr(event, self.metBranchName + "_MetUnclustEnUpDeltaX")
            met_deltaPy_unclEn = getattr(event, self.metBranchName + "_MetUnclustEnUpDeltaY")
            met_px_unclEnUp    = met_px_unclEnUp   + met_deltaPx_unclEn
            met_py_unclEnUp    = met_py_unclEnUp   + met_deltaPy_unclEn
            met_px_unclEnDown  = met_px_unclEnDown - met_deltaPx_unclEn
            met_py_unclEnDown  = met_py_unclEnDown - met_deltaPy_unclEn

            # propagate effect of jet energy smearing to MET           
            met_px_jerUp   = met_px_jerUp   + (met_px_nom - met_px)
            met_py_jerUp   = met_py_jerUp   + (met_py_nom - met_py)
            met_px_jerDown = met_px_jerDown + (met_px_nom - met_px)
            met_py_jerDown = met_py_jerDown + (met_py_nom - met_py)
            for jesUncertainty in self.jesUncertainties:
                met_px_jesUp[jesUncertainty]   = met_px_jesUp[jesUncertainty]   + (met_px_nom - met_px)
                met_py_jesUp[jesUncertainty]   = met_py_jesUp[jesUncertainty]   + (met_py_nom - met_py)
                met_px_jesDown[jesUncertainty] = met_px_jesDown[jesUncertainty] + (met_px_nom - met_px)
                met_py_jesDown[jesUncertainty] = met_py_jesDown[jesUncertainty] + (met_py_nom - met_py)
            met_px_unclEnUp    = met_px_unclEnUp   + (met_px_nom - met_px)
            met_py_unclEnUp    = met_py_unclEnUp   + (met_py_nom - met_py)
            met_px_unclEnDown  = met_px_unclEnDown + (met_px_nom - met_px)
            met_py_unclEnDown  = met_py_unclEnDown + (met_py_nom - met_py)

        self.out.fillBranch("%s_pt_raw" % self.jetBranchName, jets_pt_raw)
        self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom)
        self.out.fillBranch("%s_corr_JEC" % self.jetBranchName, jets_corr_JEC)
        self.out.fillBranch("%s_corr_JER" % self.jetBranchName, jets_corr_JER)
        self.out.fillBranch("%s_pt_jerUp" % self.jetBranchName, jets_pt_jerUp)
        self.out.fillBranch("%s_pt_jerDown" % self.jetBranchName, jets_pt_jerDown)
        self.out.fillBranch("%s_mass_raw" % self.jetBranchName, jets_mass_raw)
        self.out.fillBranch("%s_mass_nom" % self.jetBranchName, jets_mass_nom)
        self.out.fillBranch("%s_corr_JMS" % self.jetBranchName, jets_corr_JMS)
        self.out.fillBranch("%s_corr_JMR" % self.jetBranchName, jets_corr_JMR)
        self.out.fillBranch("%s_mass_jerUp" % self.jetBranchName, jets_mass_jerUp)
        self.out.fillBranch("%s_mass_jerDown" % self.jetBranchName, jets_mass_jerDown)
        self.out.fillBranch("%s_mass_jmrUp" % self.jetBranchName, jets_mass_jmrUp)
        self.out.fillBranch("%s_mass_jmrDown" % self.jetBranchName, jets_mass_jmrDown)
        self.out.fillBranch("%s_mass_jmsUp" % self.jetBranchName, jets_mass_jmsUp)
        self.out.fillBranch("%s_mass_jmsDown" % self.jetBranchName, jets_mass_jmsDown)

        self.out.fillBranch("%s_L1" % self.jetBranchName, jet_L1)
        self.out.fillBranch("%s_L2L3" % self.jetBranchName, jet_L2L3)
        self.out.fillBranch("%s_LRes" % self.jetBranchName, jet_LRes)

        
        if self.doGroomed :
            self.out.fillBranch("%s_msoftdrop_raw" % self.jetBranchName, jets_msdcorr_raw)
            self.out.fillBranch("%s_msoftdrop_nom" % self.jetBranchName, jets_msdcorr_nom)
            self.out.fillBranch("%s_msoftdrop_corr_JMS" % self.jetBranchName, jets_msdcorr_corr_JMS)
            self.out.fillBranch("%s_msoftdrop_corr_JMR" % self.jetBranchName, jets_msdcorr_corr_JMR)
            self.out.fillBranch("%s_msoftdrop_jerUp" % self.jetBranchName, jets_msdcorr_jerUp)
            self.out.fillBranch("%s_msoftdrop_jerDown" % self.jetBranchName, jets_msdcorr_jerDown)
            self.out.fillBranch("%s_msoftdrop_corr_PUPPI" % self.jetBranchName, jets_msdcorr_corr_PUPPI)
            self.out.fillBranch("%s_msoftdrop_jmrUp" % self.jetBranchName, jets_msdcorr_jmrUp)
            self.out.fillBranch("%s_msoftdrop_jmrDown" % self.jetBranchName, jets_msdcorr_jmrDown)
            self.out.fillBranch("%s_msoftdrop_jmsUp" % self.jetBranchName, jets_msdcorr_jmsUp)
            self.out.fillBranch("%s_msoftdrop_jmsDown" % self.jetBranchName, jets_msdcorr_jmsDown)
            self.out.fillBranch("%s_msoftdrop_tau21DDT_nom" % self.jetBranchName, jets_msdcorr_tau21DDT_nom)
            self.out.fillBranch("%s_msoftdrop_tau21DDT_jerUp" % self.jetBranchName, jets_msdcorr_tau21DDT_jerUp)
            self.out.fillBranch("%s_msoftdrop_tau21DDT_jerDown" % self.jetBranchName, jets_msdcorr_tau21DDT_jerDown)
            self.out.fillBranch("%s_msoftdrop_tau21DDT_jmrUp" % self.jetBranchName, jets_msdcorr_tau21DDT_jmrUp)
            self.out.fillBranch("%s_msoftdrop_tau21DDT_jmrDown" % self.jetBranchName, jets_msdcorr_tau21DDT_jmrDown)
            self.out.fillBranch("%s_msoftdrop_tau21DDT_jmsUp" % self.jetBranchName, jets_msdcorr_tau21DDT_jmsUp)
            self.out.fillBranch("%s_msoftdrop_tau21DDT_jmsDown" % self.jetBranchName, jets_msdcorr_tau21DDT_jmsDown)

            
        if self.corrMET :
            self.out.fillBranch("%s_pt_nom" % self.metBranchName, math.sqrt(met_px_nom**2 + met_py_nom**2))
            self.out.fillBranch("%s_phi_nom" % self.metBranchName, math.atan2(met_py_nom, met_px_nom))        
            self.out.fillBranch("%s_pt_jerUp" % self.metBranchName, math.sqrt(met_px_jerUp**2 + met_py_jerUp**2))
            self.out.fillBranch("%s_phi_jerUp" % self.metBranchName, math.atan2(met_py_jerUp, met_px_jerUp))        
            self.out.fillBranch("%s_pt_jerDown" % self.metBranchName, math.sqrt(met_px_jerDown**2 + met_py_jerDown**2))
            self.out.fillBranch("%s_phi_jerDown" % self.metBranchName, math.atan2(met_py_jerDown, met_px_jerDown))
            
        for jesUncertainty in self.jesUncertainties:
            self.out.fillBranch("%s_pt_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_pt_jesUp[jesUncertainty])
            self.out.fillBranch("%s_pt_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_pt_jesDown[jesUncertainty])
            self.out.fillBranch("%s_mass_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_mass_jesUp[jesUncertainty])
            self.out.fillBranch("%s_mass_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_mass_jesDown[jesUncertainty])
            
            if self.doGroomed : 
                self.out.fillBranch("%s_msoftdrop_jes%sUp" % (self.jetBranchName, jesUncertainty), jets_msdcorr_jesUp[jesUncertainty])
                self.out.fillBranch("%s_msoftdrop_jes%sDown" % (self.jetBranchName, jesUncertainty), jets_msdcorr_jesDown[jesUncertainty])
                
            
            if self.corrMET:
                self.out.fillBranch("%s_pt_jes%sUp" % (self.metBranchName, jesUncertainty), math.sqrt(met_px_jesUp[jesUncertainty]**2 + met_py_jesUp[jesUncertainty]**2))
                self.out.fillBranch("%s_phi_jes%sUp" % (self.metBranchName, jesUncertainty), math.atan2(met_py_jesUp[jesUncertainty], met_px_jesUp[jesUncertainty]))
                self.out.fillBranch("%s_pt_jes%sDown" % (self.metBranchName, jesUncertainty), math.sqrt(met_px_jesDown[jesUncertainty]**2 + met_py_jesDown[jesUncertainty]**2))
                self.out.fillBranch("%s_phi_jes%sDown" % (self.metBranchName, jesUncertainty), math.atan2(met_py_jesDown[jesUncertainty], met_px_jesDown[jesUncertainty]))
        if self.corrMET:
            self.out.fillBranch("%s_pt_unclustEnUp" % self.metBranchName, math.sqrt(met_px_unclEnUp**2 + met_py_unclEnUp**2))
            self.out.fillBranch("%s_phi_unclustEnUp" % self.metBranchName, math.atan2(met_py_unclEnUp, met_px_unclEnUp))
            self.out.fillBranch("%s_pt_unclustEnDown" % self.metBranchName, math.sqrt(met_px_unclEnDown**2 + met_py_unclEnDown**2))
            self.out.fillBranch("%s_phi_unclustEnDown" % self.metBranchName, math.atan2(met_py_unclEnDown, met_px_unclEnDown))

        return True
Exemple #7
0
class jetRecalib(Module):
    def __init__(self, globalTag, jetType="AK4PFchs"):

        if "AK4" in jetType:
            self.jetBranchName = "Jet"
        elif "AK8" in jetType:
            self.jetBranchName = "FatJet"
            self.subJetBranchName = "SubJet"
        else:
            raise ValueError("ERROR: Invalid jet type = '%s'!" % jetType)
        self.rhoBranchName = "fixedGridRhoFastjetAll"
        self.lenVar = "n" + self.jetBranchName
        # To do : change to real values
        self.jmsVals = [1.00, 0.99, 1.01]

        self.jesInputFilePath = os.environ[
            'CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/"

        self.jetReCalibrator = JetReCalibrator(
            globalTag,
            jetType,
            True,
            self.jesInputFilePath,
            calculateSeparateCorrections=False,
            calculateType1METCorrection=False)

        # load libraries for accessing JES scale factors and uncertainties from txt files
        for library in [
                "libCondFormatsJetMETObjects", "libPhysicsToolsNanoAODTools"
        ]:
            if library not in ROOT.gSystem.GetLibraries():
                print("Load Library '%s'" % library.replace("lib", ""))
                ROOT.gSystem.Load(library)

    def beginJob(self):
        pass

    def endJob(self):
        pass

    def beginFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        self.out = wrappedOutputTree
        self.out.branch("%s_pt_nom" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("MET_pt_nom", "F")
        self.out.branch("MET_phi_nom", "F")

    def endFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        pass

    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        jets = Collection(event, self.jetBranchName)
        met = Object(event, "MET")

        jets_pt_nom = []
        (met_px, met_py) = (met.pt * math.cos(met.phi),
                            met.pt * math.sin(met.phi))
        (met_px_nom, met_py_nom) = (met_px, met_py)
        met_px_nom = met_px
        met_py_nom = met_py

        rho = getattr(event, self.rhoBranchName)

        for jet in jets:
            jet_pt = jet.pt
            jet_pt = self.jetReCalibrator.correct(jet, rho)
            jet_pt_nom = jet_pt  # don't smear resolution in data
            if jet_pt_nom < 0.0:
                jet_pt_nom *= -1.0
            jets_pt_nom.append(jet_pt_nom)
            if jet_pt_nom > 15.:
                jet_cosPhi = math.cos(jet.phi)
                jet_sinPhi = math.sin(jet.phi)
                met_px_nom = met_px_nom - (jet_pt_nom - jet.pt) * jet_cosPhi
                met_py_nom = met_py_nom - (jet_pt_nom - jet.pt) * jet_sinPhi
        self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom)
        self.out.fillBranch("MET_pt_nom",
                            math.sqrt(met_px_nom**2 + met_py_nom**2))
        self.out.fillBranch("MET_phi_nom", math.atan2(met_py_nom, met_px_nom))

        return True
Exemple #8
0
class jetRecalib(Module):
    # Module based on https://github.com/cms-nanoAOD/nanoAOD-tools/blob/master/python/postprocessing/modules/jme/jetRecalib.py
    def __init__(self,
                 globalTag,
                 jetCollections=["CleanJet"],
                 metCollections=["MET"],
                 jetType="AK4PFchs"):

        if "AK4" in jetType:
            self.jetBranchName = "Jet"
        elif "AK8" in jetType:
            self.jetBranchName = "FatJet"
            self.subJetBranchName = "SubJet"
        else:
            raise ValueError("ERROR: Invalid jet type = '%s'!" % jetType)
        self.otherJetBranches = jetCollections  # Any jet collections based on full Jet-collection
        self.metCollections = metCollections
        self.rhoBranchName = "fixedGridRhoFastjetAll"
        # To do : change to real values
        self.jmsVals = [1.00, 0.99, 1.01]

        self.jesInputFilePath = os.environ[
            'CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/"

        self.jetReCalibrator = JetReCalibrator(
            globalTag,
            jetType,
            True,
            self.jesInputFilePath,
            calculateSeparateCorrections=False,
            calculateType1METCorrection=False)

        # load libraries for accessing JES scale factors and uncertainties from txt files
        for library in [
                "libCondFormatsJetMETObjects", "libPhysicsToolsNanoAODTools"
        ]:
            if library not in ROOT.gSystem.GetLibraries():
                print("Load Library '%s'" % library.replace("lib", ""))
                ROOT.gSystem.Load(library)

    def beginJob(self):
        pass

    def endJob(self):
        pass

    def beginFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        self.out = wrappedOutputTree
        self.out.branch("%s_pt" % self.jetBranchName,
                        "F",
                        lenVar="n" + self.jetBranchName)
        self.out.branch("%s_rawFactor" % self.jetBranchName,
                        "F",
                        lenVar="n" + self.jetBranchName)
        for jname in self.otherJetBranches:
            self.out.branch("%s_pt" % jname, "F", lenVar="n" + jname)
        for met in self.metCollections:
            self.out.branch("%s_pt" % met, "F")
            self.out.branch("%s_phi" % met, "F")

    def endFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        pass

    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        jets = Collection(event, self.jetBranchName)
        mets = []
        met_px = []
        met_py = []
        for mid, met in enumerate(self.metCollections):
            mets.append(Object(event, met))
            met_px.append(mets[mid].pt * math.cos(mets[mid].phi))
            met_py.append(mets[mid].pt * math.sin(mets[mid].phi))

        jets_pt_newlist = []
        rawFactor_newlist = []

        otherjets = []
        otherjets_pt_newlist = []
        for jname in self.otherJetBranches:
            otherjets.append(Collection(event, jname))
            otherjets_pt_newlist.append([])

        rho = getattr(event, self.rhoBranchName)

        for jid, jet in enumerate(jets):
            # Apply new correction (this includes undoing previous correction first)
            newjet_pt = self.jetReCalibrator.correct(jet, rho)[0]
            # Rewrite new correction factor
            rawFactor_newlist.append(1. - ((jet.pt *
                                            (1. - jet.rawFactor)) / newjet_pt))

            if newjet_pt < 0.0: newjet_pt *= -1.0
            jets_pt_newlist.append(newjet_pt)

            if newjet_pt > 15.:
                jet_cosPhi = math.cos(jet.phi)
                jet_sinPhi = math.sin(jet.phi)
                for mid, met in enumerate(self.metCollections):
                    met_px[mid] = met_px[mid] - (newjet_pt -
                                                 jet.pt) * jet_cosPhi
                    met_py[mid] = met_py[mid] - (newjet_pt -
                                                 jet.pt) * jet_sinPhi

            for oj, jname in enumerate(self.otherJetBranches):
                for ojet in otherjets[oj]:
                    if jid == ojet.jetIdx:
                        otherjets_pt_newlist[oj].append(newjet_pt)

        self.out.fillBranch("%s_pt" % self.jetBranchName, jets_pt_newlist)
        self.out.fillBranch("%s_rawFactor" % self.jetBranchName,
                            rawFactor_newlist)
        for oj, jname in enumerate(self.otherJetBranches):
            self.out.fillBranch("%s_pt" % jname, otherjets_pt_newlist[oj])
        for mid, met in enumerate(self.metCollections):
            self.out.fillBranch("%s_pt" % met,
                                math.sqrt(met_px[mid]**2 + met_py[mid]**2))
            self.out.fillBranch("%s_phi" % met,
                                math.atan2(met_py[mid], met_px[mid]))

        return True
Exemple #9
0
class jetRecalib(Module):
    def __init__(self, globalTag, archive, jetType="AK4PFchs", redoJEC=False):

        self.redoJEC = redoJEC

        if "AK4" in jetType:
            self.jetBranchName = "Jet"
        elif "AK8" in jetType:
            self.jetBranchName = "FatJet"
            self.subJetBranchName = "SubJet"
        else:
            raise ValueError("ERROR: Invalid jet type = '%s'!" % jetType)
        self.rhoBranchName = "fixedGridRhoFastjetAll"
        self.lenVar = "n" + self.jetBranchName

        self.jesInputArchivePath = os.environ[
            'CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/"
        # Text files are now tarred so must extract first into temporary directory (gets deleted during python memory management at script exit)
        self.jesArchive = tarfile.open(
            self.jesInputArchivePath + archive + ".tar.gz", "r:gz")
        self.jesInputFilePath = tempfile.mkdtemp()
        self.jesArchive.extractall(self.jesInputFilePath)
        print("Loading jet energy scale (JES) from file '%s'" %
              os.path.join(self.jesInputArchivePath + archive + ".tar.gz"))

        self.jetReCalibrator = JetReCalibrator(
            globalTag,
            jetType,
            True,
            self.jesInputFilePath,
            calculateSeparateCorrections=False,
            calculateType1METCorrection=False)

        # load libraries for accessing JES scale factors and uncertainties from txt files
        for library in [
                "libCondFormatsJetMETObjects", "libPhysicsToolsNanoAODTools"
        ]:
            if library not in ROOT.gSystem.GetLibraries():
                print("Load Library '%s'" % library.replace("lib", ""))
                ROOT.gSystem.Load(library)

    def beginJob(self):
        pass

    def endJob(self):
        pass

    def beginFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        self.out = wrappedOutputTree
        self.out.branch("%s_pt_raw" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_pt_nom" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_mass_raw" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_mass_nom" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("MET_pt_nom", "F")
        self.out.branch("MET_phi_nom", "F")
        self.out.branch("%s_corr_JEC" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)

    def endFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        pass

    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        jets = Collection(event, self.jetBranchName)
        met = Object(event, "MET")

        jets_pt_raw = []
        jets_pt_nom = []
        jets_mass_raw = []
        jets_mass_nom = []
        jets_corr_JEC = []
        (met_px, met_py) = (met.pt * math.cos(met.phi),
                            met.pt * math.sin(met.phi))
        (met_px_nom, met_py_nom) = (met_px, met_py)
        met_px_nom = met_px
        met_py_nom = met_py

        rho = getattr(event, self.rhoBranchName)

        for jet in jets:
            #jet pt and mass corrections
            jet_pt = jet.pt
            jet_mass = jet.mass

            #redo JECs if desired
            if hasattr(jet, "rawFactor"):
                jet_rawpt = jet_pt * (1 - jet.rawFactor)
                jet_rawmass = jet_mass * (1 - jet.rawFactor)
            else:
                jet_rawpt = -1.0 * jet_pt  #If factor not present factor will be saved as -1
                jet_rawmass = -1.0 * jet_mass  #If factor not present factor will be saved as -1
            if self.redoJEC:
                (jet_pt, jet_mass) = self.jetReCalibrator.correct(jet, rho)
            jets_pt_raw.append(jet_rawpt)
            jets_mass_raw.append(jet_rawmass)
            jets_corr_JEC.append(jet_pt / jet_rawpt)

            jet_pt_nom = jet_pt  # don't smear resolution in data
            if jet_pt_nom < 0.0:
                jet_pt_nom *= -1.0
            jets_pt_nom.append(jet_pt_nom)

            jet_mass_nom = jet_mass
            if jet_mass_nom < 0.0:
                jet_mass_nom *= -1.0
            jets_mass_nom.append(jet_mass_nom)

            if jet_pt_nom > 15.:
                jet_cosPhi = math.cos(jet.phi)
                jet_sinPhi = math.sin(jet.phi)
                met_px_nom = met_px_nom - (jet_pt_nom - jet.pt) * jet_cosPhi
                met_py_nom = met_py_nom - (jet_pt_nom - jet.pt) * jet_sinPhi
        self.out.fillBranch("%s_pt_raw" % self.jetBranchName, jets_pt_raw)
        self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom)
        self.out.fillBranch("%s_mass_raw" % self.jetBranchName, jets_mass_raw)
        self.out.fillBranch("%s_mass_nom" % self.jetBranchName, jets_mass_nom)
        self.out.fillBranch("MET_pt_nom",
                            math.sqrt(met_px_nom**2 + met_py_nom**2))
        self.out.fillBranch("MET_phi_nom", math.atan2(met_py_nom, met_px_nom))
        self.out.fillBranch("%s_corr_JEC" % self.jetBranchName, jets_corr_JEC)

        return True
Exemple #10
0
class jetRecalib(Module):
    # Module based on https://github.com/cms-nanoAOD/nanoAOD-tools/blob/master/python/postprocessing/modules/jme/jetRecalib.py
    def __init__(self,  globalTag, jetCollections = ["CleanJet"], metCollections = ["MET"], jetType = "AK4PFchs"):

        if "AK4" in jetType : 
            self.jetBranchName = "Jet"
        elif "AK8" in jetType :
            self.jetBranchName = "FatJet"
            self.subJetBranchName = "SubJet"
        else:
            raise ValueError("ERROR: Invalid jet type = '%s'!" % jetType)
        self.otherJetBranches = jetCollections # Any jet collections based on full Jet-collection
        self.metCollections = metCollections
        self.rhoBranchName = "fixedGridRhoFastjetAll"
        # To do : change to real values
        self.jmsVals = [1.00, 0.99, 1.01]
        

        self.jesInputFilePath = os.environ['CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/"

        self.jetReCalibrator = JetReCalibrator(globalTag, jetType , True, self.jesInputFilePath, calculateSeparateCorrections = False, calculateType1METCorrection  = False)
	
        # load libraries for accessing JES scale factors and uncertainties from txt files
        for library in [ "libCondFormatsJetMETObjects", "libPhysicsToolsNanoAODTools" ]:
            if library not in ROOT.gSystem.GetLibraries():
                print("Load Library '%s'" % library.replace("lib", ""))
                ROOT.gSystem.Load(library)

    def beginJob(self):
	pass

    def endJob(self):
	pass

    def beginFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        self.out = wrappedOutputTree
        self.out.branch("%s_pt" % self.jetBranchName, "F", lenVar="n"+self.jetBranchName)
        self.out.branch("%s_rawFactor" % self.jetBranchName, "F", lenVar="n"+self.jetBranchName)
        for jname in self.otherJetBranches:
            self.out.branch("%s_pt" % jname, "F", lenVar="n"+jname)
        for met in self.metCollections:
            self.out.branch("%s_pt" % met, "F")
            self.out.branch("%s_phi" % met, "F")
            
                        
    def endFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        pass
    
    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        jets = Collection(event, self.jetBranchName )
        mets = []
        met_px = []
        met_py = []
        for mid,met in enumerate(self.metCollections):
            mets.append(Object(event, met))
            met_px.append(mets[mid].pt*math.cos(mets[mid].phi))
            met_py.append(mets[mid].pt*math.sin(mets[mid].phi))

        jets_pt_newlist = []
        rawFactor_newlist = []

        otherjets = []
        otherjets_pt_newlist = []
        for jname in self.otherJetBranches:
            otherjets.append(Collection(event, jname ))
            otherjets_pt_newlist.append([])
        
        rho = getattr(event, self.rhoBranchName)
        
        for jid,jet in enumerate(jets):
            # Apply new correction (this includes undoing previous correction first)
	    newjet_pt = self.jetReCalibrator.correct(jet,rho)
            # Rewrite new correction factor
            rawFactor_newlist.append(1. - ((jet.pt * (1. - jet.rawFactor))/newjet_pt))

            if newjet_pt < 0.0: newjet_pt *= -1.0
            jets_pt_newlist.append(newjet_pt)

            if newjet_pt > 15.:
                jet_cosPhi = math.cos(jet.phi)
                jet_sinPhi = math.sin(jet.phi)
                for mid,met in enumerate(self.metCollections):
                    met_px[mid] = met_px[mid] - (newjet_pt - jet.pt)*jet_cosPhi
                    met_py[mid] = met_py[mid] - (newjet_pt - jet.pt)*jet_sinPhi

            for oj,jname in enumerate(self.otherJetBranches):
                for ojet in otherjets[oj]:
                    if jid == ojet.jetIdx:
                        otherjets_pt_newlist[oj].append(newjet_pt)

        self.out.fillBranch("%s_pt" % self.jetBranchName, jets_pt_newlist)
        self.out.fillBranch("%s_rawFactor" % self.jetBranchName, rawFactor_newlist)
        for oj,jname in enumerate(self.otherJetBranches):
            self.out.fillBranch("%s_pt" % jname, otherjets_pt_newlist[oj])
        for mid,met in enumerate(self.metCollections):
            self.out.fillBranch("%s_pt" % met, math.sqrt(met_px[mid]**2 + met_py[mid]**2))
            self.out.fillBranch("%s_phi" % met, math.atan2(met_py[mid], met_px[mid]))   

        return True
Exemple #11
0
class jetmetUncertaintiesProducer(Module):
    def __init__(self,
                 era,
                 globalTag,
                 jesUncertainties=["Total"],
                 jetType="AK4PFchs",
                 redoJEC=False,
                 noGroom=False,
                 reducedJECsystematics=False):

        self.era = era
        self.redoJEC = redoJEC
        self.noGroom = noGroom
        #--------------------------------------------------------------------------------------------
        # CV: globalTag and jetType not yet used in the jet smearer, as there is no consistent set of
        #     txt files for JES uncertainties and JER scale factors and uncertainties yet
        #--------------------------------------------------------------------------------------------

        self.jesUncertainties = jesUncertainties

        # smear jet pT to account for measured difference in JER between data and simulation.
        if era == "2016":
            self.jerInputFileName = "Summer16_25nsV1b_MC/Summer16_25nsV1b_MC_PtResolution_" + jetType + ".txt"
            self.jerUncertaintyInputFileName = "Summer16_25nsV1b_MC/Summer16_25nsV1b_MC_SF_" + jetType + ".txt"
        elif era == "2017":  # use Fall17 as temporary placeholder until post-Moriond 2019 JERs are out
            self.jerInputFileName = "Fall17_V3b_MC/Fall17_V3b_MC_PtResolution_" + jetType + ".txt"
            self.jerUncertaintyInputFileName = "Fall17_V3b_MC/Fall17_V3b_MC_SF_" + jetType + ".txt"
        elif era == "2018":  ## (see https://hypernews.cern.ch/HyperNews/CMS/get/JetMET/1994.html)
            self.jerInputFileName = "Autumn18_V7b_MC/Autumn18_V7b_MC_PtResolution_" + jetType + ".txt"
            self.jerUncertaintyInputFileName = "Autumn18_V7b_MC/Autumn18_V7b_MC_SF_" + jetType + ".txt"

        #jet mass resolution: https://twiki.cern.ch/twiki/bin/view/CMS/JetWtagging
        if self.era == "2016" or self.era == "2018":  #update when 2018 values available
            self.jmrVals = [1.0, 1.2, 0.8]  #nominal, up, down
        else:
            self.jmrVals = [1.09, 1.14, 1.04]

        self.jetSmearer = jetSmearer(globalTag, jetType, self.jerInputFileName,
                                     self.jerUncertaintyInputFileName,
                                     self.jmrVals)

        if "AK4" in jetType:
            self.jetBranchName = "Jet"
            self.genJetBranchName = "GenJet"
            self.genSubJetBranchName = None
            self.doGroomed = False
            self.corrMET = True
        elif "AK8" in jetType:
            self.jetBranchName = "FatJet"
            self.subJetBranchName = "SubJet"
            self.genJetBranchName = "GenJetAK8"
            self.genSubJetBranchName = "SubGenJetAK8"
            if not self.noGroom:
                self.doGroomed = True
            else:
                self.doGroomed = False
            self.corrMET = False
        else:
            raise ValueError("ERROR: Invalid jet type = '%s'!" % jetType)
        self.metBranchName = "MET"
        self.rhoBranchName = "fixedGridRhoFastjetAll"
        self.lenVar = "n" + self.jetBranchName

        #jet mass scale
        #W-tagging PUPPI softdrop JMS values: https://twiki.cern.ch/twiki/bin/view/CMS/JetWtagging
        #2016 values - use for 2018 until new values available
        self.jmsVals = [1.00, 0.9906, 1.0094]  #nominal, down, up
        if self.era == "2017":
            self.jmsVals = [0.982, 0.978, 0.986]

        # read jet energy scale (JES) uncertainties
        # (downloaded from https://twiki.cern.ch/twiki/bin/view/CMS/JECDataMC )
        self.jesInputArchivePath = os.environ[
            'CMSSW_BASE'] + "/src/PhysicsTools/NanoAODTools/data/jme/"
        # Text files are now tarred so must extract first into temporary directory (gets deleted during python memory management at script exit)
        self.jesArchive = tarfile.open(
            self.jesInputArchivePath + globalTag + ".tgz", "r:gz")
        self.jesInputFilePath = tempfile.mkdtemp()
        self.jesArchive.extractall(self.jesInputFilePath)

        if len(jesUncertainties) == 1 and jesUncertainties[0] == "Total":
            if self.era == "2016":
                self.jesUncertaintyInputFileName = "Summer16_07Aug2017_V11_MC_Uncertainty_" + jetType + ".txt"
            elif self.era == "2017":
                self.jesUncertaintyInputFileName = "Fall17_17Nov2017_V32_MC_Uncertainty_" + jetType + ".txt"
            elif self.era == "2018":
                self.jesUncertaintyInputFileName = "Autumn18_V19_MC_Uncertainty_" + jetType + ".txt"
            else:
                raise ValueError("ERROR: Invalid era = '%s'!" % self.era)
        else:
            if self.era == "2016":
                self.jesUncertaintyInputFileName = "Summer16_07Aug2017_V11_MC_UncertaintySources_" + jetType + ".txt"
            elif self.era == "2017":
                self.jesUncertaintyInputFileName = "Fall17_17Nov2017_V32_MC_UncertaintySources_" + jetType + ".txt"
            elif self.era == "2018":
                self.jesUncertaintyInputFileName = "Autumn18_V19_MC_UncertaintySources_" + jetType + ".txt"
            else:
                raise ValueError("ERROR: Invalid era = '%s'!" % self.era)
            if reducedJECsystematics:
                ## Use https://twiki.cern.ch/twiki/bin/viewauth/CMS/JECUncertaintySources#Run_2_reduced_set_of_uncertainty ##
                self.jesUncertaintyInputFileName = "Regrouped_" + self.jesUncertaintyInputFileName

        # read all uncertainty source names from the loaded file
        if jesUncertainties[0] == "All":
            with open(self.jesInputFilePath + '/' +
                      self.jesUncertaintyInputFileName) as f:
                lines = f.read().split("\n")
                sources = filter(
                    lambda x: x.startswith("[") and x.endswith("]"), lines)
                sources = map(lambda x: x[1:-1], sources)
                self.jesUncertainties = sources

        if self.redoJEC:
            self.jetReCalibrator = JetReCalibrator(
                globalTag,
                jetType,
                True,
                self.jesInputFilePath,
                calculateSeparateCorrections=False,
                calculateType1METCorrection=False)

        # define energy threshold below which jets are considered as "unclustered energy"
        # (cf. JetMETCorrections/Type1MET/python/correctionTermsPfMetType1Type2_cff.py )
        self.unclEnThreshold = 15.

        # load libraries for accessing JES scale factors and uncertainties from txt files
        for library in [
                "libCondFormatsJetMETObjects", "libPhysicsToolsNanoAODTools"
        ]:
            if library not in ROOT.gSystem.GetLibraries():
                print("Load Library '%s'" % library.replace("lib", ""))
                ROOT.gSystem.Load(library)

    def beginJob(self):

        print("Loading jet energy scale (JES) uncertainties from file '%s'" %
              os.path.join(self.jesInputFilePath,
                           self.jesUncertaintyInputFileName))
        #self.jesUncertainty = ROOT.JetCorrectionUncertainty(os.path.join(self.jesInputFilePath, self.jesUncertaintyInputFileName))

        self.jesUncertainty = {}
        # implementation didn't seem to work for factorized JEC, try again another way
        for jesUncertainty in self.jesUncertainties:
            jesUncertainty_label = jesUncertainty
            if jesUncertainty == 'Total' and len(self.jesUncertainties) == 1:
                jesUncertainty_label = ''
            pars = ROOT.JetCorrectorParameters(
                os.path.join(self.jesInputFilePath,
                             self.jesUncertaintyInputFileName),
                jesUncertainty_label)
            self.jesUncertainty[
                jesUncertainty] = ROOT.JetCorrectionUncertainty(pars)

        self.jetSmearer.beginJob()

    def endJob(self):
        self.jetSmearer.endJob()

    def beginFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        self.out = wrappedOutputTree
        self.out.branch("%s_pt_raw" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_pt_nom" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_pt_newJEC" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_mass_raw" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_mass_nom" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_corr_JEC" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_corr_JER" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_corr_JMS" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)
        self.out.branch("%s_corr_JMR" % self.jetBranchName,
                        "F",
                        lenVar=self.lenVar)

        if self.doGroomed:
            self.out.branch("%s_msoftdrop_raw" % self.jetBranchName,
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_nom" % self.jetBranchName,
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_corr_JMR" % self.jetBranchName,
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_msoftdrop_corr_JMS" % self.jetBranchName,
                            "F",
                            lenVar=self.lenVar)

        if self.corrMET:
            self.out.branch("%s_pt_nom" % self.metBranchName, "F")
            self.out.branch("%s_phi_nom" % self.metBranchName, "F")

        for shift in ["Up", "Down"]:
            self.out.branch("%s_pt_jer%s" % (self.jetBranchName, shift),
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_mass_jer%s" % (self.jetBranchName, shift),
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_mass_jmr%s" % (self.jetBranchName, shift),
                            "F",
                            lenVar=self.lenVar)
            self.out.branch("%s_mass_jms%s" % (self.jetBranchName, shift),
                            "F",
                            lenVar=self.lenVar)

            if self.doGroomed:
                self.out.branch("%s_msoftdrop_jer%s" %
                                (self.jetBranchName, shift),
                                "F",
                                lenVar=self.lenVar)
                self.out.branch("%s_msoftdrop_jmr%s" %
                                (self.jetBranchName, shift),
                                "F",
                                lenVar=self.lenVar)
                self.out.branch("%s_msoftdrop_jms%s" %
                                (self.jetBranchName, shift),
                                "F",
                                lenVar=self.lenVar)

            if self.corrMET:
                self.out.branch("%s_pt_jer%s" % (self.metBranchName, shift),
                                "F")
                self.out.branch("%s_phi_jer%s" % (self.metBranchName, shift),
                                "F")
            for jesUncertainty in self.jesUncertainties:
                self.out.branch("%s_pt_jes%s%s" %
                                (self.jetBranchName, jesUncertainty, shift),
                                "F",
                                lenVar=self.lenVar)
                self.out.branch("%s_mass_jes%s%s" %
                                (self.jetBranchName, jesUncertainty, shift),
                                "F",
                                lenVar=self.lenVar)
                if self.doGroomed:
                    self.out.branch(
                        "%s_msoftdrop_jes%s%s" %
                        (self.jetBranchName, jesUncertainty, shift),
                        "F",
                        lenVar=self.lenVar)
                if self.corrMET:
                    self.out.branch(
                        "%s_pt_jes%s%s" %
                        (self.metBranchName, jesUncertainty, shift), "F")
                    self.out.branch(
                        "%s_phi_jes%s%s" %
                        (self.metBranchName, jesUncertainty, shift), "F")
            if self.corrMET:
                self.out.branch(
                    "%s_pt_unclustEn%s" % (self.metBranchName, shift), "F")
                self.out.branch(
                    "%s_phi_unclustEn%s" % (self.metBranchName, shift), "F")

    def endFile(self, inputFile, outputFile, inputTree, wrappedOutputTree):
        pass

    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        jets = Collection(event, self.jetBranchName)
        genJets = Collection(event, self.genJetBranchName)

        if self.doGroomed:
            subJets = Collection(event, self.subJetBranchName)
            genSubJets = Collection(event, self.genSubJetBranchName)
            genSubJetMatcher = matchObjectCollectionMultiple(genJets,
                                                             genSubJets,
                                                             dRmax=0.8)

        jets_pt_newJEC = []
        jets_pt_raw = []
        jets_pt_nom = []
        jets_mass_raw = []
        jets_mass_nom = []

        jets_corr_JEC = []
        jets_corr_JER = []
        jets_corr_JMS = []
        jets_corr_JMR = []

        jets_pt_jerUp = []
        jets_pt_jerDown = []
        jets_pt_jesUp = {}
        jets_pt_jesDown = {}

        jets_mass_jerUp = []
        jets_mass_jerDown = []
        jets_mass_jmrUp = []
        jets_mass_jmrDown = []
        jets_mass_jesUp = {}
        jets_mass_jesDown = {}
        jets_mass_jmsUp = []
        jets_mass_jmsDown = []

        for jesUncertainty in self.jesUncertainties:
            jets_pt_jesUp[jesUncertainty] = []
            jets_pt_jesDown[jesUncertainty] = []
            jets_mass_jesUp[jesUncertainty] = []
            jets_mass_jesDown[jesUncertainty] = []

        if self.corrMET:
            met = Object(event, self.metBranchName)
            (met_px, met_py) = (met.pt * math.cos(met.phi),
                                met.pt * math.sin(met.phi))
            (met_px_nom, met_py_nom) = (met_px, met_py)
            (met_px_jerUp, met_py_jerUp) = (met_px, met_py)
            (met_px_jerDown, met_py_jerDown) = (met_px, met_py)
            (met_px_jesUp, met_py_jesUp) = ({}, {})
            (met_px_jesDown, met_py_jesDown) = ({}, {})
            for jesUncertainty in self.jesUncertainties:
                met_px_jesUp[jesUncertainty] = met_px
                met_py_jesUp[jesUncertainty] = met_py
                met_px_jesDown[jesUncertainty] = met_px
                met_py_jesDown[jesUncertainty] = met_py

        if self.doGroomed:
            jets_msdcorr_raw = []
            jets_msdcorr_nom = []
            jets_msdcorr_corr_JMR = []
            jets_msdcorr_corr_JMS = []
            jets_msdcorr_jerUp = []
            jets_msdcorr_jerDown = []
            jets_msdcorr_jmrUp = []
            jets_msdcorr_jmrDown = []
            jets_msdcorr_jesUp = {}
            jets_msdcorr_jesDown = {}
            jets_msdcorr_jmsUp = []
            jets_msdcorr_jmsDown = []
            for jesUncertainty in self.jesUncertainties:
                jets_msdcorr_jesUp[jesUncertainty] = []
                jets_msdcorr_jesDown[jesUncertainty] = []

        rho = getattr(event, self.rhoBranchName)

        # match reconstructed jets to generator level ones
        # (needed to evaluate JER scale factors and uncertainties)
        pairs = matchObjectCollection(jets, genJets)

        for jet in jets:
            genJet = pairs[jet]
            if self.doGroomed:
                genGroomedSubJets = genSubJetMatcher[
                    genJet] if genJet != None else None
                genGroomedJet = genGroomedSubJets[0].p4() + genGroomedSubJets[
                    1].p4() if genGroomedSubJets != None and len(
                        genGroomedSubJets) >= 2 else None
                if jet.subJetIdx1 >= 0 and jet.subJetIdx2 >= 0:
                    groomedP4 = subJets[jet.subJetIdx1].p4() + subJets[
                        jet.subJetIdx2].p4()  #check subjet jecs
                else:
                    groomedP4 = None

            #jet pt and mass corrections
            jet_pt = jet.pt
            jet_mass = jet.mass

            #redo JECs if desired
            if hasattr(jet, "rawFactor"):
                jet_rawpt = jet_pt * (1 - jet.rawFactor)
                jet_rawmass = jet_mass * (1 - jet.rawFactor)
            else:
                jet_rawpt = -1.0 * jet_pt  #If factor not present factor will be saved as -1
                jet_rawmass = -1.0 * jet_mass  #If factor not present factor will be saved as -1
            if self.redoJEC:
                (jet_pt, jet_mass) = self.jetReCalibrator.correct(jet, rho)
                jet.pt = jet_pt
                jet.mass = jet_mass
            jets_pt_raw.append(jet_rawpt)
            jets_mass_raw.append(jet_rawmass)
            jets_corr_JEC.append(jet_pt / jet_rawpt)
            jets_pt_newJEC.append(jet_pt)

            # evaluate JER scale factors and uncertainties
            # (cf. https://twiki.cern.ch/twiki/bin/view/CMS/JetResolution and https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyResolution )
            (jet_pt_jerNomVal, jet_pt_jerUpVal,
             jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt(
                 jet, genJet, rho)
            jets_corr_JER.append(jet_pt_jerNomVal)

            #if jet_pt_jerNomVal > 2 : print "jet_pt_jerNomVal  ", jet_pt_jerNomVal

            jet_pt_nom = jet_pt_jerNomVal * jet_pt
            if jet_pt_nom < 0.0:
                jet_pt_nom *= -1.0
            jet_pt_jerUp = jet_pt_jerUpVal * jet_pt
            jet_pt_jerDown = jet_pt_jerDownVal * jet_pt
            jets_pt_nom.append(jet_pt_nom)
            jets_pt_jerUp.append(jet_pt_jerUpVal * jet_pt)
            jets_pt_jerDown.append(jet_pt_jerDownVal * jet_pt)

            # evaluate JES uncertainties
            jet_pt_jesUp = {}
            jet_pt_jesDown = {}
            jet_mass_jesUp = {}
            jet_mass_jesDown = {}
            jet_mass_jmsUp = []
            jet_mass_jmsDown = []

            # Evaluate JMS and JMR scale factors and uncertainties
            jmsNomVal = self.jmsVals[0]
            jmsDownVal = self.jmsVals[1]
            jmsUpVal = self.jmsVals[2]
            (jet_mass_jmrNomVal, jet_mass_jmrUpVal,
             jet_mass_jmrDownVal) = self.jetSmearer.getSmearValsM(jet, genJet)
            jets_corr_JMS.append(jmsNomVal)
            jets_corr_JMR.append(jet_mass_jmrNomVal)

            jet_mass_nom = jet_pt_jerNomVal * jet_mass_jmrNomVal * jmsNomVal * jet_mass
            if jet_mass_nom < 0.0:
                jet_mass_nom *= -1.0
            jets_mass_nom.append(jet_mass_nom)
            jets_mass_jerUp.append(jet_pt_jerUpVal * jet_mass_jmrNomVal *
                                   jmsNomVal * jet_mass)
            jets_mass_jerDown.append(jet_pt_jerDownVal * jet_mass_jmrNomVal *
                                     jmsNomVal * jet_mass)
            jets_mass_jmrUp.append(jet_pt_jerNomVal * jet_mass_jmrUpVal *
                                   jmsNomVal * jet_mass)
            jets_mass_jmrDown.append(jet_pt_jerNomVal * jet_mass_jmrDownVal *
                                     jmsNomVal * jet_mass)
            jets_mass_jmsUp.append(jet_pt_jerNomVal * jet_mass_jmrNomVal *
                                   jmsUpVal * jet_mass)
            jets_mass_jmsDown.append(jet_pt_jerNomVal * jet_mass_jmrNomVal *
                                     jmsDownVal * jet_mass)

            if self.doGroomed:
                # evaluate JES uncertainties
                jet_msdcorr_jesUp = {}
                jet_msdcorr_jesDown = {}

                # Evaluate JMS and JMR scale factors and uncertainties
                (jet_msdcorr_jmrNomVal, jet_msdcorr_jmrUpVal,
                 jet_msdcorr_jmrDownVal) = self.jetSmearer.getSmearValsM(
                     groomedP4, genGroomedJet
                 ) if groomedP4 != None and genGroomedJet != None else (0., 0.,
                                                                        0.)
                jet_msdcorr_raw = groomedP4.M() if groomedP4 != None else 0.0
                jets_msdcorr_corr_JMS.append(jmsNomVal)
                jets_msdcorr_corr_JMR.append(jet_msdcorr_jmrNomVal)

                if jet_msdcorr_raw < 0.0:
                    jet_msdcorr_raw *= -1.0
                jet_msdcorr_nom = jet_pt_jerNomVal * jet_msdcorr_jmrNomVal * jmsNomVal * jet_msdcorr_raw
                jets_msdcorr_raw.append(
                    jet_msdcorr_raw)  #fix later so jec's not applied
                jets_msdcorr_nom.append(jet_msdcorr_nom)
                jets_msdcorr_jerUp.append(jet_pt_jerUpVal *
                                          jet_msdcorr_jmrNomVal * jmsNomVal *
                                          jet_msdcorr_raw)
                jets_msdcorr_jerDown.append(jet_pt_jerDownVal *
                                            jet_msdcorr_jmrNomVal * jmsNomVal *
                                            jet_msdcorr_raw)
                jets_msdcorr_jmrUp.append(jet_pt_jerNomVal *
                                          jet_msdcorr_jmrUpVal * jmsNomVal *
                                          jet_msdcorr_raw)
                jets_msdcorr_jmrDown.append(
                    jet_pt_jerNomVal * jet_msdcorr_jmrDownVal * jmsNomVal *
                    jet_msdcorr_raw)
                jets_msdcorr_jmsUp.append(jet_pt_jerNomVal *
                                          jet_msdcorr_jmrNomVal * jmsUpVal *
                                          jet_msdcorr_raw)
                jets_msdcorr_jmsDown.append(
                    jet_pt_jerNomVal * jet_msdcorr_jmrNomVal * jmsDownVal *
                    jet_msdcorr_raw)

            for jesUncertainty in self.jesUncertainties:
                # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties )
                self.jesUncertainty[jesUncertainty].setJetPt(jet_pt_nom)
                self.jesUncertainty[jesUncertainty].setJetEta(jet.eta)
                delta = self.jesUncertainty[jesUncertainty].getUncertainty(
                    True)
                jet_pt_jesUp[jesUncertainty] = jet_pt_nom * (1. + delta)
                jet_pt_jesDown[jesUncertainty] = jet_pt_nom * (1. - delta)
                jets_pt_jesUp[jesUncertainty].append(
                    jet_pt_jesUp[jesUncertainty])
                jets_pt_jesDown[jesUncertainty].append(
                    jet_pt_jesDown[jesUncertainty])
                jet_mass_jesUp[jesUncertainty] = jet_mass_nom * (1. + delta)
                jet_mass_jesDown[jesUncertainty] = jet_mass_nom * (1. - delta)
                jets_mass_jesUp[jesUncertainty].append(
                    jet_mass_jesUp[jesUncertainty])
                jets_mass_jesDown[jesUncertainty].append(
                    jet_mass_jesDown[jesUncertainty])
                if self.doGroomed:
                    jet_msdcorr_jesUp[jesUncertainty] = jet_msdcorr_nom * (
                        1. + delta)
                    jet_msdcorr_jesDown[jesUncertainty] = jet_msdcorr_nom * (
                        1. - delta)
                    jets_msdcorr_jesUp[jesUncertainty].append(
                        jet_msdcorr_jesUp[jesUncertainty])
                    jets_msdcorr_jesDown[jesUncertainty].append(
                        jet_msdcorr_jesDown[jesUncertainty])

            # propagate JER and JES corrections and uncertainties to MET
            if self.corrMET and jet_pt_nom > self.unclEnThreshold:
                jet_cosPhi = math.cos(jet.phi)
                jet_sinPhi = math.sin(jet.phi)
                met_px_nom = met_px_nom - (jet_pt_nom - jet_pt) * jet_cosPhi
                met_py_nom = met_py_nom - (jet_pt_nom - jet_pt) * jet_sinPhi
                met_px_jerUp = met_px_jerUp - (jet_pt_jerUp -
                                               jet_pt_nom) * jet_cosPhi
                met_py_jerUp = met_py_jerUp - (jet_pt_jerUp -
                                               jet_pt_nom) * jet_sinPhi
                met_px_jerDown = met_px_jerDown - (jet_pt_jerDown -
                                                   jet_pt_nom) * jet_cosPhi
                met_py_jerDown = met_py_jerDown - (jet_pt_jerDown -
                                                   jet_pt_nom) * jet_sinPhi
                for jesUncertainty in self.jesUncertainties:
                    met_px_jesUp[jesUncertainty] = met_px_jesUp[
                        jesUncertainty] - (jet_pt_jesUp[jesUncertainty] -
                                           jet_pt_nom) * jet_cosPhi
                    met_py_jesUp[jesUncertainty] = met_py_jesUp[
                        jesUncertainty] - (jet_pt_jesUp[jesUncertainty] -
                                           jet_pt_nom) * jet_sinPhi
                    met_px_jesDown[jesUncertainty] = met_px_jesDown[
                        jesUncertainty] - (jet_pt_jesDown[jesUncertainty] -
                                           jet_pt_nom) * jet_cosPhi
                    met_py_jesDown[jesUncertainty] = met_py_jesDown[
                        jesUncertainty] - (jet_pt_jesDown[jesUncertainty] -
                                           jet_pt_nom) * jet_sinPhi

        # propagate "unclustered energy" uncertainty to MET
        if self.corrMET:
            (met_px_unclEnUp, met_py_unclEnUp) = (met_px, met_py)
            (met_px_unclEnDown, met_py_unclEnDown) = (met_px, met_py)
            met_deltaPx_unclEn = getattr(
                event, self.metBranchName + "_MetUnclustEnUpDeltaX")
            met_deltaPy_unclEn = getattr(
                event, self.metBranchName + "_MetUnclustEnUpDeltaY")
            met_px_unclEnUp = met_px_unclEnUp + met_deltaPx_unclEn
            met_py_unclEnUp = met_py_unclEnUp + met_deltaPy_unclEn
            met_px_unclEnDown = met_px_unclEnDown - met_deltaPx_unclEn
            met_py_unclEnDown = met_py_unclEnDown - met_deltaPy_unclEn

            # propagate effect of jet energy smearing to MET
            met_px_jerUp = met_px_jerUp + (met_px_nom - met_px)
            met_py_jerUp = met_py_jerUp + (met_py_nom - met_py)
            met_px_jerDown = met_px_jerDown + (met_px_nom - met_px)
            met_py_jerDown = met_py_jerDown + (met_py_nom - met_py)
            for jesUncertainty in self.jesUncertainties:
                met_px_jesUp[jesUncertainty] = met_px_jesUp[jesUncertainty] + (
                    met_px_nom - met_px)
                met_py_jesUp[jesUncertainty] = met_py_jesUp[jesUncertainty] + (
                    met_py_nom - met_py)
                met_px_jesDown[jesUncertainty] = met_px_jesDown[
                    jesUncertainty] + (met_px_nom - met_px)
                met_py_jesDown[jesUncertainty] = met_py_jesDown[
                    jesUncertainty] + (met_py_nom - met_py)
            met_px_unclEnUp = met_px_unclEnUp + (met_px_nom - met_px)
            met_py_unclEnUp = met_py_unclEnUp + (met_py_nom - met_py)
            met_px_unclEnDown = met_px_unclEnDown + (met_px_nom - met_px)
            met_py_unclEnDown = met_py_unclEnDown + (met_py_nom - met_py)

        self.out.fillBranch("%s_pt_raw" % self.jetBranchName, jets_pt_raw)
        self.out.fillBranch("%s_pt_nom" % self.jetBranchName, jets_pt_nom)
        self.out.fillBranch("%s_pt_newJEC" % self.jetBranchName,
                            jets_pt_newJEC)
        self.out.fillBranch("%s_corr_JEC" % self.jetBranchName, jets_corr_JEC)
        self.out.fillBranch("%s_corr_JER" % self.jetBranchName, jets_corr_JER)
        self.out.fillBranch("%s_pt_jerUp" % self.jetBranchName, jets_pt_jerUp)
        self.out.fillBranch("%s_pt_jerDown" % self.jetBranchName,
                            jets_pt_jerDown)
        self.out.fillBranch("%s_mass_raw" % self.jetBranchName, jets_mass_raw)
        self.out.fillBranch("%s_mass_nom" % self.jetBranchName, jets_mass_nom)
        self.out.fillBranch("%s_corr_JMS" % self.jetBranchName, jets_corr_JMS)
        self.out.fillBranch("%s_corr_JMR" % self.jetBranchName, jets_corr_JMR)
        self.out.fillBranch("%s_mass_jerUp" % self.jetBranchName,
                            jets_mass_jerUp)
        self.out.fillBranch("%s_mass_jerDown" % self.jetBranchName,
                            jets_mass_jerDown)
        self.out.fillBranch("%s_mass_jmrUp" % self.jetBranchName,
                            jets_mass_jmrUp)
        self.out.fillBranch("%s_mass_jmrDown" % self.jetBranchName,
                            jets_mass_jmrDown)
        self.out.fillBranch("%s_mass_jmsUp" % self.jetBranchName,
                            jets_mass_jmsUp)
        self.out.fillBranch("%s_mass_jmsDown" % self.jetBranchName,
                            jets_mass_jmsDown)

        if self.doGroomed:
            self.out.fillBranch("%s_msoftdrop_raw" % self.jetBranchName,
                                jets_msdcorr_raw)
            self.out.fillBranch("%s_msoftdrop_nom" % self.jetBranchName,
                                jets_msdcorr_nom)
            self.out.fillBranch("%s_msoftdrop_corr_JMS" % self.jetBranchName,
                                jets_msdcorr_corr_JMS)
            self.out.fillBranch("%s_msoftdrop_corr_JMR" % self.jetBranchName,
                                jets_msdcorr_corr_JMR)
            self.out.fillBranch("%s_msoftdrop_jerUp" % self.jetBranchName,
                                jets_msdcorr_jerUp)
            self.out.fillBranch("%s_msoftdrop_jerDown" % self.jetBranchName,
                                jets_msdcorr_jerDown)
            self.out.fillBranch("%s_msoftdrop_jmrUp" % self.jetBranchName,
                                jets_msdcorr_jmrUp)
            self.out.fillBranch("%s_msoftdrop_jmrDown" % self.jetBranchName,
                                jets_msdcorr_jmrDown)
            self.out.fillBranch("%s_msoftdrop_jmsUp" % self.jetBranchName,
                                jets_msdcorr_jmsUp)
            self.out.fillBranch("%s_msoftdrop_jmsDown" % self.jetBranchName,
                                jets_msdcorr_jmsDown)

        if self.corrMET:
            self.out.fillBranch("%s_pt_nom" % self.metBranchName,
                                math.sqrt(met_px_nom**2 + met_py_nom**2))
            self.out.fillBranch("%s_phi_nom" % self.metBranchName,
                                math.atan2(met_py_nom, met_px_nom))
            self.out.fillBranch("%s_pt_jerUp" % self.metBranchName,
                                math.sqrt(met_px_jerUp**2 + met_py_jerUp**2))
            self.out.fillBranch("%s_phi_jerUp" % self.metBranchName,
                                math.atan2(met_py_jerUp, met_px_jerUp))
            self.out.fillBranch(
                "%s_pt_jerDown" % self.metBranchName,
                math.sqrt(met_px_jerDown**2 + met_py_jerDown**2))
            self.out.fillBranch("%s_phi_jerDown" % self.metBranchName,
                                math.atan2(met_py_jerDown, met_px_jerDown))

        for jesUncertainty in self.jesUncertainties:
            self.out.fillBranch(
                "%s_pt_jes%sUp" % (self.jetBranchName, jesUncertainty),
                jets_pt_jesUp[jesUncertainty])
            self.out.fillBranch(
                "%s_pt_jes%sDown" % (self.jetBranchName, jesUncertainty),
                jets_pt_jesDown[jesUncertainty])
            self.out.fillBranch(
                "%s_mass_jes%sUp" % (self.jetBranchName, jesUncertainty),
                jets_mass_jesUp[jesUncertainty])
            self.out.fillBranch(
                "%s_mass_jes%sDown" % (self.jetBranchName, jesUncertainty),
                jets_mass_jesDown[jesUncertainty])

            if self.doGroomed:
                self.out.fillBranch(
                    "%s_msoftdrop_jes%sUp" %
                    (self.jetBranchName, jesUncertainty),
                    jets_msdcorr_jesUp[jesUncertainty])
                self.out.fillBranch(
                    "%s_msoftdrop_jes%sDown" %
                    (self.jetBranchName, jesUncertainty),
                    jets_msdcorr_jesDown[jesUncertainty])

            if self.corrMET:
                self.out.fillBranch(
                    "%s_pt_jes%sUp" % (self.metBranchName, jesUncertainty),
                    math.sqrt(met_px_jesUp[jesUncertainty]**2 +
                              met_py_jesUp[jesUncertainty]**2))
                self.out.fillBranch(
                    "%s_phi_jes%sUp" % (self.metBranchName, jesUncertainty),
                    math.atan2(met_py_jesUp[jesUncertainty],
                               met_px_jesUp[jesUncertainty]))
                self.out.fillBranch(
                    "%s_pt_jes%sDown" % (self.metBranchName, jesUncertainty),
                    math.sqrt(met_px_jesDown[jesUncertainty]**2 +
                              met_py_jesDown[jesUncertainty]**2))
                self.out.fillBranch(
                    "%s_phi_jes%sDown" % (self.metBranchName, jesUncertainty),
                    math.atan2(met_py_jesDown[jesUncertainty],
                               met_px_jesDown[jesUncertainty]))
        if self.corrMET:
            self.out.fillBranch(
                "%s_pt_unclustEnUp" % self.metBranchName,
                math.sqrt(met_px_unclEnUp**2 + met_py_unclEnUp**2))
            self.out.fillBranch("%s_phi_unclustEnUp" % self.metBranchName,
                                math.atan2(met_py_unclEnUp, met_px_unclEnUp))
            self.out.fillBranch(
                "%s_pt_unclustEnDown" % self.metBranchName,
                math.sqrt(met_px_unclEnDown**2 + met_py_unclEnDown**2))
            self.out.fillBranch(
                "%s_phi_unclustEnDown" % self.metBranchName,
                math.atan2(met_py_unclEnDown, met_px_unclEnDown))

        return True