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
Пример #2
0
    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
Пример #3
0
    def correctJetMET_MC(self, event):
        """Process event, apply corrections."""
        ###print ">>> %8s "%event.event + '-'*80

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

        jets_pt_nom = []
        ###jets_mass_nom     = [ ]
        if self.doSystematics:
            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 uncertainty in self.jesUncertainties:
                jets_pt_jesUp[uncertainty] = []
                jets_pt_jesDown[uncertainty] = []
                ###jets_mass_jesUp[uncertainty]   = [ ]
                ###jets_mass_jesDown[uncertainty] = [ ]

        if self.corrMET:
            met = Object(event, self.metBranchName)
            met_px, met_py = met.pt * cos(met.phi), met.pt * 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 uncertainty in self.jesUncertainties:
                met_px_jesUp[uncertainty] = met_px
                met_py_jesUp[uncertainty] = met_py
                met_px_jesDown[uncertainty] = met_px
                met_py_jesDown[uncertainty] = met_py

        ###if self.doGroomed:
        ###    jets_msdcorr_nom = [ ]
        ###    if self.doSystematics:
        ###        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 uncertainty in self.jesUncertainties:
        ###            jets_msdcorr_jesUp[uncertainty]   = [ ]
        ###            jets_msdcorr_jesDown[uncertainty] = [ ]

        # MATCH reconstructed jets to generator level ones
        # (needed to evaluate JER scale factors and uncertainties)
        jets = Collection(event, self.jetBranchName)
        genJets = Collection(event, self.genJetBranchName)
        rho = getattr(event, self.rhoBranchName)
        pairs = matchObjectCollection(jets, genJets)
        # APPLY JEC per jet
        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

            # RAW VALUES
            jet_pt0 = jet.pt
            ###jet_mass0 = jet.mass
            if hasattr(jet, 'rawFactor'):
                jet_pt_raw = jet_pt0 * (1 - jet.rawFactor)
                ###jet_mass_raw = jet.mass * (1 - jet.rawFactor)
            else:
                jet_pt_raw = -1.0 * jet_pt0  # if factor not present factor will be saved as -1
                ###jet_mass_raw = -1.0 * jet.mass

            # CALIBRATE - apply JES corrections
            if self.redoJEC:
                jet_pt, jet_mass = self.jetReCalibrator.correct(jet, rho)
                jet.pt = jet_pt
                jet.mass = jet_mass
            else:
                jet_pt = jet.pt
                jet_mass = jet.mass

            # SMEAR - apply JER SF
            if self.doSystematics:
                smear_jer, smear_jerUp, smear_jerDown = self.jetSmearer.smearPt(
                    jet, genJet, rho)
            else:
                smear_jer = self.jetSmearer.smearPt(jet, genJet, rho)[0]
            jet_pt_nom = smear_jer * jet_pt
            if jet_pt_nom < 0.0:
                jet_pt_nom *= -1.0
            jets_pt_nom.append(jet_pt_nom)
            ###print "%8.4f %8.4f %8.4f %8.4f %8.4f %8.4f"%(jet_pt_raw, jet_pt0, jet_pt, jet_pt_nom, jet.rawFactor, smear_jer)

            #### SMEAR JMS and JMR scale factors
            ###jmsNomVal  = self.jmsVals[0]
            ###jmsDownVal = self.jmsVals[1]
            ###jmsUpVal   = self.jmsVals[2]
            ###smear_jmr, smear_jmrUp, smear_jmrDown = self.jetSmearer.smearMass(jet, genJet)
            ###jet_mass_nom           = smear_jer*smear_jmr*jmsNomVal*jet.mass
            ###if jet_mass_nom < 0.0:
            ###    jet_mass_nom *= -1.0
            ###jets_mass_nom    .append(jet_mass_nom)

            #### CORRECT GROOMED JETS
            ###if self.doGroomed:
            ###    ( 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           = smear_jer*jet_msdcorr_jmrNomVal*jet_msdcorr_raw
            ###    jets_msdcorr_nom    .append(jet_msdcorr_nom)

            #### UPDATE JET in event (unreliable)
            ###if self.updateEvent:
            ###  getattr(event,self.jetBranchName+'_pt')[jet._index] = jet_pt_nom
            ###  ###getattr(event,self.jetBranchName+'_mass')[jet._index] = jet_mass_nom

            # EVALUATE JEC uncertainties
            if self.doSystematics:

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

                # EVALUATE JER uncertainties
                jet_pt_jerUp = smear_jerUp * jet_pt
                jet_pt_jerDown = smear_jerDown * jet_pt
                jets_pt_jerUp.append(jet_pt_jerUp)
                jets_pt_jerDown.append(jet_pt_jerDown)

                #### EVALUATE JMS and JMR uncertainties
                ###jet_mass_jesUp   = { }
                ###jet_mass_jesDown = { }
                ###jet_mass_jmsUp   = [ ]
                ###jet_mass_jmsDown = [ ]
                ###jets_mass_jerUp  .append(smear_jerUp  *smear_jmr *jmsNomVal *jet.mass)
                ###jets_mass_jerDown.append(smear_jerDown*smear_jmr *jmsNomVal *jet.mass)
                ###jets_mass_jmrUp  .append(smear_jer *smear_jmrUp  *jmsNomVal *jet.mass)
                ###jets_mass_jmrDown.append(smear_jer *smear_jmrDown*jmsNomVal *jet.mass)
                ###jets_mass_jmsUp  .append(smear_jer *smear_jmr    *jmsUpVal  *jet.mass)
                ###jets_mass_jmsDown.append(smear_jer *smear_jmr    *jmsDownVal*jet.mass)

                ###if self.doGroomed:
                ###    jet_msdcorr_jmsUp   = [ ]
                ###    jet_msdcorr_jmsDown = [ ]
                ###    jet_msdcorr_jesUp   = { }
                ###    jet_msdcorr_jesDown = { }
                ###    jets_msdcorr_jerUp  .append(smear_jerUp  *jet_msdcorr_jmrNomVal *jmsNomVal  *jet_msdcorr_raw)
                ###    jets_msdcorr_jerDown.append(smear_jerDown*jet_msdcorr_jmrNomVal *jmsNomVal  *jet_msdcorr_raw)
                ###    jets_msdcorr_jmrUp  .append(smear_jer *jet_msdcorr_jmrUpVal  *jmsNomVal  *jet_msdcorr_raw)
                ###    jets_msdcorr_jmrDown.append(smear_jer *jet_msdcorr_jmrDownVal*jmsNomVal  *jet_msdcorr_raw)
                ###    jets_msdcorr_jmsUp  .append(smear_jer *jet_msdcorr_jmrNomVal *jmsUpVal   *jet_msdcorr_raw)
                ###    jets_msdcorr_jmsDown.append(smear_jer *jet_msdcorr_jmrNomVal *jmsDownVal *jet_msdcorr_raw)

            # PROPAGATE JER and JES corrections and uncertainties to MET
            if self.corrMET and jet_pt_nom > self.unclEnThreshold:
                jet_cosPhi = cos(jet.phi)
                jet_sinPhi = sin(jet.phi)
                ###print "%8.4f - met_px_nom = met_px_nom - (jet_pt_nom - jet_pt0)*jet_cosPhi = %8.4f - (%8.4f - %8.4f)*%8.4f = %8.4f"%(jet.phi,met_px_nom,jet_pt_nom,jet_pt0,jet_cosPhi,met_px_nom-(jet_pt_nom-jet_pt0)*jet_cosPhi)
                met_px_nom = met_px_nom - (jet_pt_nom - jet_pt0) * jet_cosPhi
                ###print "%8.4f - met_py_nom = met_py_nom - (jet_pt_nom - jet_pt0)*jet_sinPhi = %8.4f - (%8.4f - %8.4f)*%8.4f = %8.4f"%(jet.phi,met_py_nom,jet_pt_nom,jet_pt0,jet_sinPhi,met_py_nom-(jet_pt_nom-jet_pt0)*jet_sinPhi)
                met_py_nom = met_py_nom - (jet_pt_nom - jet_pt0) * jet_sinPhi
                if self.doSystematics:
                    met_px_jerUp = met_px_jerUp - (jet_pt_jerUp -
                                                   jet_pt0) * jet_cosPhi
                    met_py_jerUp = met_py_jerUp - (jet_pt_jerUp -
                                                   jet_pt0) * jet_sinPhi
                    met_px_jerDown = met_px_jerDown - (jet_pt_jerDown -
                                                       jet_pt0) * jet_cosPhi
                    met_py_jerDown = met_py_jerDown - (jet_pt_jerDown -
                                                       jet_pt0) * jet_sinPhi
                    for uncertainty in self.jesUncertainties:
                        met_px_jesUp[uncertainty] = met_px_jesUp[
                            uncertainty] - (jet_pt_jesUp[uncertainty] -
                                            jet_pt0) * jet_cosPhi
                        met_py_jesUp[uncertainty] = met_py_jesUp[
                            uncertainty] - (jet_pt_jesUp[uncertainty] -
                                            jet_pt0) * jet_sinPhi
                        met_px_jesDown[uncertainty] = met_px_jesDown[
                            uncertainty] - (jet_pt_jesDown[uncertainty] -
                                            jet_pt0) * jet_cosPhi
                        met_py_jesDown[uncertainty] = met_py_jesDown[
                            uncertainty] - (jet_pt_jesDown[uncertainty] -
                                            jet_pt0) * jet_sinPhi

            #### CHECKS
            ###print ">>> %2d: jet.pt, jet_pt, corr_factor, smear_factor = %8.3f, %8.3f, %8.4f, %8.4f"%(jet._index,jet.pt,jet_pt,jet_pt/jet_pt_raw,smear_factor)
            ###print ">>> %2s  jet_pt_jerUp, jet_pt_nom, jet_pt_jerDown = %8.3f, %8.3f, %8.3f"%("",jet_pt_jerUp,jet_pt_nom,jet_pt_jerDown)
            ###print ">>> %2s  jet_pt_jesUp, jet_pt_nom, jet_pt_jesDown = %8.3f, %8.3f, %8.3f"%("",jet_pt_jesUp['Total'],jet_pt_nom,jet_pt_jesDown['Total'])

        # PREPARE JET PT variations for return; save 'Total' as just jesUp/jesDown
        if self.doSystematics:
            jetpt_vars = {
                'nom': jets_pt_nom,
                'jerUp': jets_pt_jerUp,
                'jerDown': jets_pt_jerDown
            }
            for uncertainty in self.jesUncertainties:
                jetpt_vars["jes%sUp" % uncertainty.replace(
                    'Total', '')] = jets_pt_jesUp[uncertainty]
                jetpt_vars["jes%sDown" % uncertainty.replace(
                    'Total', '')] = jets_pt_jesDown[uncertainty]
        else:
            jetpt_vars = {
                'nom': jets_pt_nom,
            }

        if self.corrMET:

            # PREPARE MET for return
            ###print "met_px_nom = %8.4f"%(met_px_nom)
            ###print "met_py_nom = %8.4f"%(met_py_nom)
            met_vars = {
                'nom':
                TLorentzVector(met_px_nom, met_py_nom, 0,
                               sqrt(met_px_nom**2 + met_py_nom**2))
            }

            #### UPDATE MET in event
            ###if self.updateEvent:
            ###  setattr(event,self.metBranchName+'_pt',  met_vars['nom'].Pt())
            ###  setattr(event,self.metBranchName+'_phi', met_vars['nom'].Phi())

            if self.doSystematics:

                # EVALUATE UNCLUSTERED ENERGY uncertainties
                met_deltaPx_unclEn = getattr(
                    event, self.metBranchName + "_MetUnclustEnUpDeltaX")
                met_deltaPy_unclEn = getattr(
                    event, self.metBranchName + "_MetUnclustEnUpDeltaY")
                met_px_unclEnUp = met_px_nom + met_deltaPx_unclEn
                met_py_unclEnUp = met_py_nom + met_deltaPy_unclEn
                met_px_unclEnDown = met_px_nom - met_deltaPx_unclEn
                met_py_unclEnDown = met_py_nom - met_deltaPy_unclEn

                # PREPARE MET variations for return
                met_vars['jesUp'] = {}
                met_vars['jesDown'] = {}
                met_vars['jerUp'] = TLorentzVector(
                    met_px_jerUp, met_py_jerUp, 0,
                    sqrt(met_px_jerUp**2 + met_py_jerUp**2))
                met_vars['jerDown'] = TLorentzVector(
                    met_px_jerDown, met_py_jerDown, 0,
                    sqrt(met_px_jerDown**2 + met_py_jerDown**2))
                met_vars['unclEnUp'] = TLorentzVector(
                    met_px_unclEnUp, met_py_unclEnUp, 0,
                    sqrt(met_px_unclEnUp**2 + met_py_unclEnUp**2))
                met_vars['unclEnDown'] = TLorentzVector(
                    met_px_unclEnDown, met_py_unclEnDown, 0,
                    sqrt(met_px_unclEnDown**2 + met_py_unclEnDown**2))
                for uncertainty in self.jesUncertainties:
                    met_vars["jes%sUp" % uncertainty.replace(
                        'Total', '')] = TLorentzVector(
                            met_px_jesUp[uncertainty],
                            met_py_jesUp[uncertainty], 0,
                            sqrt(met_px_jesUp[uncertainty]**2 +
                                 met_py_jesUp[uncertainty]**2))
                    met_vars["jes%sDown" % uncertainty.replace(
                        'Total', '')] = TLorentzVector(
                            met_px_jesDown[uncertainty],
                            met_py_jesDown[uncertainty], 0,
                            sqrt(met_px_jesDown[uncertainty]**2 +
                                 met_py_jesDown[uncertainty]**2))

            return jetpt_vars, met_vars

        return jetpt_vars
Пример #4
0
    def analyze(self, event):
        met = self.metInput(event)
        rho = self.rhoInput(event)
        jets = self.jetCollection(event)
        lowPtJets = self.lowPtJetCollection(event)
        genJets = self.genJetCollection(event)
        muons = self.muonCollection(event)
        electrons = self.electronCollection(event)

        for lowPtJet in lowPtJets:
            lowPtJet.pt = lowPtJet.rawPt
            #dummy values
            lowPtJet.rawFactor = 0
            lowPtJet.mass = 0
            lowPtJet.neEmEF = 0
            lowPtJet.chEmEF = 0

        def genjet_resolution_matching(jet, genjet):
            resolution = self.jerUncertaintyCalculator.getResolution(jet, rho)
            return abs(jet.pt - genjet.pt) < (3 * resolution * jet.pt)

        genjet_match = matchObjectCollection(jets,
                                             genJets,
                                             dRmax=0.2,
                                             presel=genjet_resolution_matching)
        genjet_lowpt_match = matchObjectCollection(
            lowPtJets, genJets, dRmax=0.2, presel=genjet_resolution_matching)
        genjet_match.update(genjet_lowpt_match)

        def metP4(obj):
            p4 = ROOT.TLorentzVector()
            p4.SetPtEtaPhiM(obj.pt, 0, obj.phi, 0)
            return p4

        met.uncertainty_p4 = {
            'nominal': metP4(met),
            'jerUp': metP4(met),
            'jerDown': metP4(met)
        }

        self.jerUncertaintyCalculator.setSeed(event)

        for ijet, jet in enumerate(itertools.chain(jets, lowPtJets)):
            jet.uncertainty_p4 = {}

            genJet = genjet_match[jet]

            jerFactor = self.jerUncertaintyCalculator.getFactor(
                jet, genJet, rho)
            jet.uncertainty_p4['nominal'] = jet.p4() * jerFactor['nominal']
            jet.uncertainty_p4['jerUp'] = jet.p4() * jerFactor['up']
            jet.uncertainty_p4['jerDown'] = jet.p4() * jerFactor['down']

            if self.propagateJER:
                leptonP4 = ROOT.TLorentzVector(0, 0, 0, 0)

                for muon in muons:
                    if deltaR(muon, jet) < 0.4:
                        leptonP4 += muon.p4()

                for electron in electrons:
                    if deltaR(electron, jet) < 0.4:
                        leptonP4 += electron.p4()

                if (jet.uncertainty_p4['nominal'] - leptonP4).Pt(
                ) > self.unclEnThreshold and (jet.neEmEF + jet.chEmEF) < 0.9:
                    met.uncertainty_p4['nominal'] -= jet.p4() * (
                        jerFactor['nominal'] - 1.)

                if (jet.uncertainty_p4['jerUp'] - leptonP4).Pt(
                ) > self.unclEnThreshold and (jet.neEmEF + jet.chEmEF) < 0.9:
                    met.uncertainty_p4['jerUp'] -= jet.p4() * (
                        jerFactor['up'] - 1.)

                if (jet.uncertainty_p4['jerDown'] - leptonP4).Pt(
                ) > self.unclEnThreshold and (jet.neEmEF + jet.chEmEF) < 0.9:
                    met.uncertainty_p4['jerDown'] -= jet.p4() * (
                        jerFactor['down'] - 1.)

            for jesUncertaintyName in self.jesUncertaintyNames:
                jecDelta = self.jesUncertaintyCaculators[
                    jesUncertaintyName].getDelta(jet.uncertainty_p4['nominal'])
                jet.uncertainty_p4[
                    'jes' + jesUncertaintyName +
                    "Up"] = jet.uncertainty_p4['nominal'] * (1. + jecDelta)
                jet.uncertainty_p4[
                    'jes' + jesUncertaintyName +
                    "Down"] = jet.uncertainty_p4['nominal'] * (1. - jecDelta)

        for jesUncertaintyName in self.jesUncertaintyNames:
            for mode in ["Up", "Down"]:
                if self.propagateJER:
                    met.uncertainty_p4['jes' + jesUncertaintyName +
                                       mode] = met.uncertainty_p4['nominal']
                else:
                    met.uncertainty_p4['jes' + jesUncertaintyName +
                                       mode] = metP4(met)

                for jet in jets:
                    if jet.uncertainty_p4[
                            'jes' + jesUncertaintyName +
                            mode].Pt() > self.unclEnThreshold and (
                                jet.neEmEF + jet.chEmEF) < 0.9:
                        met.uncertainty_p4[
                            'jes' + jesUncertaintyName +
                            mode] -= jet.uncertainty_p4[
                                'jes' + jesUncertaintyName +
                                mode] - jet.uncertainty_p4['nominal']

        unclMetDelta = ROOT.TLorentzVector()
        unclMetDelta.SetXYZM(met.MetUnclustEnUpDeltaX,
                             met.MetUnclustEnUpDeltaY, 0, 0)
        met.uncertainty_p4[
            'unclEnUp'] = met.uncertainty_p4['nominal'] + unclMetDelta
        met.uncertainty_p4[
            'unclEnDown'] = met.uncertainty_p4['nominal'] - unclMetDelta

        setattr(event, self.outputJetPrefix + "nominal",
                self.makeNewJetCollection(jets, "nominal"))
        setattr(event, self.outputMetPrefix + "nominal",
                self.makeNewMetObject(met, "nominal"))

        for jesUncertaintyName in self.jesUncertaintyNames:
            for mode in ["Up", "Down"]:
                setattr(
                    event,
                    self.outputJetPrefix + "jes" + jesUncertaintyName + mode,
                    self.makeNewJetCollection(
                        jets, "jes" + jesUncertaintyName + mode))
                setattr(
                    event,
                    self.outputMetPrefix + "jes" + jesUncertaintyName + mode,
                    self.makeNewMetObject(met,
                                          "jes" + jesUncertaintyName + mode))

        for mode in ["Up", "Down"]:
            setattr(event, self.outputJetPrefix + "jer" + mode,
                    self.makeNewJetCollection(jets, "jer" + mode))
            setattr(event, self.outputMetPrefix + "jer" + mode,
                    self.makeNewMetObject(met, "jer" + mode))
            setattr(event, self.outputMetPrefix + "unclEn" + mode,
                    self.makeNewMetObject(met, "unclEn" + mode))

        return True
Пример #5
0
    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
Пример #6
0
    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
    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)

        jets_pt_smeared = []
        jets_pt_jerUp = []
        jets_pt_jerDown = []
        jets_pt_jesUp = {}
        jets_pt_jesDown = {}
        for jesUncertainty in self.jesUncertainties:
            jets_pt_jesUp[jesUncertainty] = []
            jets_pt_jesDown[jesUncertainty] = []

        met = Object(event, self.metBranchName)
        (met_px, met_py) = (met.pt * math.cos(met.phi),
                            met.pt * math.sin(met.phi))
        (met_px_smeared, met_py_smeared) = (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

        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]
            # 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_smeared, jet_pt_jerUp,
             jet_pt_jerDown) = self.jetSmearer.getSmearedJetPt(
                 jet, genJet, rho)
            jet_pt_ref = None
            if self.applyJERCorr:
                jet_pt_ref = jet_pt_smeared
            else:
                jet_pt_ref = jet.pt
                jet_pt_jerUp = jet_pt_jerUp * jet.pt / jet_pt_smeared
                jet_pt_jerDown = jet_pt_jerDown * jet.pt / jet_pt_smeared
            jets_pt_smeared.append(jet_pt_smeared)
            jets_pt_jerUp.append(jet_pt_jerUp)
            jets_pt_jerDown.append(jet_pt_jerDown)

            # evaluate JES uncertainties
            jet_pt_jesUp = {}
            jet_pt_jesDown = {}
            for jesUncertainty in self.jesUncertainties:
                # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties )
                self.jesUncertainty[jesUncertainty].setJetPt(jet_pt_ref)
                self.jesUncertainty[jesUncertainty].setJetEta(jet.eta)
                delta = self.jesUncertainty[jesUncertainty].getUncertainty(
                    True)
                jet_pt_jesUp[jesUncertainty] = jet_pt_ref * (1. + delta)
                jet_pt_jesDown[jesUncertainty] = jet_pt_ref * (1. - delta)
                jets_pt_jesUp[jesUncertainty].append(
                    jet_pt_jesUp[jesUncertainty])
                jets_pt_jesDown[jesUncertainty].append(
                    jet_pt_jesDown[jesUncertainty])

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

        # propagate "unclustered energy" uncertainty to MET
        (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
        if self.applyJERCorr:
            met_px_jerUp = met_px_jerUp + (met_px_smeared - met_px)
            met_py_jerUp = met_py_jerUp + (met_py_smeared - met_py)
            met_px_jerDown = met_px_jerDown + (met_px_smeared - met_px)
            met_py_jerDown = met_py_jerDown + (met_py_smeared - met_py)
            for jesUncertainty in self.jesUncertainties:
                met_px_jesUp[jesUncertainty] = met_px_jesUp[jesUncertainty] + (
                    met_px_smeared - met_px)
                met_py_jesUp[jesUncertainty] = met_py_jesUp[jesUncertainty] + (
                    met_py_smeared - met_py)
                met_px_jesDown[jesUncertainty] = met_px_jesDown[
                    jesUncertainty] + (met_px_smeared - met_px)
                met_py_jesDown[jesUncertainty] = met_py_jesDown[
                    jesUncertainty] + (met_py_smeared - met_py)
            met_px_unclEnUp = met_px_unclEnUp + (met_px_smeared - met_px)
            met_py_unclEnUp = met_py_unclEnUp + (met_py_smeared - met_py)
            met_px_unclEnDown = met_px_unclEnDown + (met_px_smeared - met_px)
            met_py_unclEnDown = met_py_unclEnDown + (met_py_smeared - met_py)

        self.out.fillBranch("%s_pt_smeared" % self.jetBranchName,
                            jets_pt_smeared)
        self.out.fillBranch("%s_pt_smeared" % self.metBranchName,
                            math.sqrt(met_px_smeared**2 + met_py_smeared**2))
        self.out.fillBranch("%s_phi_smeared" % self.metBranchName,
                            math.atan2(met_py_smeared, met_px_smeared))
        self.out.fillBranch("%s_pt_jerUp" % self.jetBranchName, jets_pt_jerUp)
        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.jetBranchName,
                            jets_pt_jerDown)
        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%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.jetBranchName, jesUncertainty),
                jets_pt_jesDown[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_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
Пример #8
0
    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
Пример #9
0
    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)
        rho = getattr(event, self.rhoBranchName)
        if not self.hasMass:
            backupJets = Collection(event, self.backupColl)

        def isResMatching(jet, genJet):
            params = ROOT.PyJetParametersWrapper()
            params.setJetEta(jet.eta)
            params.setJetPt(jet.pt)
            params.setRho(rho)

            resolution = self.jer.getResolution(params)  #super

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

        pairs = matchObjectCollection(jets,
                                      genJets,
                                      dRmax=0.2,
                                      presel=isResMatching)

        #randomize smearer
        self.setSeed(event)

        jets_pt_nom = []
        jets_mass_nom = []
        jets_corr_JER = []
        jets_pt_JERUp = []
        jets_pt_JERDown = []
        jets_mass_JERUp = []
        jets_mass_JERDown = []
        for iJet, jet in enumerate(jets):
            genJet = pairs[jet]
            if not self.hasMass:
                jet.mass = backupJets[jet.jetIdx].mass

            if self.era == "2016" and jet.pt < 50 and abs(jet.eta) > 2.5:
                # Special treatment in 2016: We observed that jet horns arise in MC when applying JER to all jets in 2016 (causing data/MC disagreement)
                # Recipe agreed on with JetMET: Don't apply 2016 JER on low pT jets in the forward region
                (jet_pt_jerNomVal, jet_pt_jerUpVal,
                 jet_pt_jerDownVal) = (1.0, 1.0, 1.0)
            else:
                #evaluate JER SF for central and up/down variations
                (jet_pt_jerNomVal, jet_pt_jerUpVal,
                 jet_pt_jerDownVal) = self.getSmearValsPt(jet, genJet,
                                                          rho)  #super
            jet_pt_nom = jet.pt * jet_pt_jerNomVal
            jet_pt_JERUp = jet.pt * jet_pt_jerUpVal
            jet_pt_JERDown = jet.pt * jet_pt_jerDownVal
            if not self.hasMass:
                jet_mass_nom = backupJets[jet.jetIdx].mass * jet_pt_jerNomVal
                jet_mass_JERUp = backupJets[jet.jetIdx].mass * jet_pt_jerUpVal
                jet_mass_JERDown = backupJets[
                    jet.jetIdx].mass * jet_pt_jerDownVal
            else:
                jet_mass_nom = jet.mass * jet_pt_jerNomVal
                jet_mass_JERUp = jet.mass * jet_pt_jerUpVal
                jet_mass_JERDown = jet.mass * jet_pt_jerDownVal
            jets_pt_nom.append(jet_pt_nom)
            jets_mass_nom.append(jet_mass_nom)
            jets_corr_JER.append(jet_pt_jerNomVal)
            jets_pt_JERUp.append(jet_pt_JERUp)
            jets_pt_JERDown.append(jet_pt_JERDown)
            jets_mass_JERUp.append(jet_mass_JERUp)
            jets_mass_JERDown.append(jet_mass_JERDown)

        # Reorder
        #
        # e.g. if pt is         [ 26, 24, 27 ]
        #      you get: order = [ 2, 0, 1]
        #
        order = sorted(range(len(jets_pt_nom)),
                       key=jets_pt_nom.__getitem__,
                       reverse=True)

        #Save to updated branches to jet collection
        for typ in self.collBr:
            for bname in self.collBr[typ]:
                if '_pt' in bname:
                    temp_v = [jets_pt_nom[idx] for idx in order]
                    self.out.fillBranch(bname, temp_v)
                elif '_mass' in bname:
                    temp_v = [jets_mass_nom[idx] for idx in order]
                    self.out.fillBranch(bname, temp_v)
                else:
                    temp_b = bname.replace(self.jetBranchName + '_', '')
                    temp_v = [jets[idx][temp_b] for idx in order]
                    self.out.fillBranch(bname, temp_v)

        #Save new branches to jet collection
        self.out.fillBranch("%s_corr_JER" % self.jetBranchName,
                            [jets_corr_JER[idx] for idx in order])
        self.out.fillBranch("%s_pt_JERUp" % self.jetBranchName,
                            [jets_pt_JERUp[idx] for idx in order])
        self.out.fillBranch("%s_pt_JERDown" % self.jetBranchName,
                            [jets_pt_JERDown[idx] for idx in order])
        self.out.fillBranch("%s_mass_JERUp" % self.jetBranchName,
                            [jets_mass_JERUp[idx] for idx in order])
        self.out.fillBranch("%s_mass_JERDown" % self.jetBranchName,
                            [jets_mass_JERDown[idx] for idx in order])

        return True
Пример #10
0
    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)
        rho = getattr(event, self.rhoBranchName)
        if not self.hasMass:
            backupJets = Collection(event, self.backupColl)

        def isResMatching(jet, genJet):
            params = ROOT.PyJetParametersWrapper()
            params.setJetEta(jet.eta)
            params.setJetPt(jet.pt)
            params.setRho(rho)

            resolution = self.jer.getResolution(params)  #super

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

        pairs = matchObjectCollection(jets,
                                      genJets,
                                      dRmax=0.2,
                                      presel=isResMatching)

        #randomize smearer
        self.setSeed(event)

        jets_pt_nom = []
        jets_mass_nom = []
        jets_corr_JER = []
        jets_pt_JERUp = []
        jets_pt_JERDown = []
        jets_mass_JERUp = []
        jets_mass_JERDown = []
        for iJet, jet in enumerate(jets):
            genJet = pairs[jet]
            if not self.hasMass:
                jet.mass = backupJets[jet.jetIdx].mass

            #evaluate JER SF for central and up/down variations
            (jet_pt_jerNomVal, jet_pt_jerUpVal,
             jet_pt_jerDownVal) = self.getSmearValsPt(jet, genJet, rho)  #super
            jet_pt_nom = jet.pt * jet_pt_jerNomVal
            jet_pt_JERUp = jet.pt * jet_pt_jerUpVal
            jet_pt_JERDown = jet.pt * jet_pt_jerDownVal
            if not self.hasMass:
                jet_mass_nom = backupJets[jet.jetIdx].mass * jet_pt_jerNomVal
                jet_mass_JERUp = backupJets[jet.jetIdx].mass * jet_pt_jerUpVal
                jet_mass_JERDown = backupJets[
                    jet.jetIdx].mass * jet_pt_jerDownVal
            else:
                jet_mass_nom = jet.mass * jet_pt_jerNomVal
                jet_mass_JERUp = jet.mass * jet_pt_jerUpVal
                jet_mass_JERDown = jet.mass * jet_pt_jerDownVal
            jets_pt_nom.append(jet_pt_nom)
            jets_mass_nom.append(jet_mass_nom)
            jets_corr_JER.append(jet_pt_jerNomVal)
            jets_pt_JERUp.append(jet_pt_JERUp)
            jets_pt_JERDown.append(jet_pt_JERDown)
            jets_mass_JERUp.append(jet_mass_JERUp)
            jets_mass_JERDown.append(jet_mass_JERDown)

        #Reorder
        order = []
        for idx1, pt1 in enumerate(jets_pt_nom):
            pt_idx = 0
            for idx2, pt2 in enumerate(jets_pt_nom):
                if pt1 < pt2 or (pt1 == pt2 and idx1 > idx2): pt_idx += 1
            order.append(pt_idx)

        #Save to updated branches to jet collection
        for typ in self.collBr:
            for bname in self.collBr[typ]:
                if '_pt' in bname:
                    temp_v = [jets_pt_nom[idx] for idx in order]
                    self.out.fillBranch(bname, temp_v)
                elif '_mass' in bname:
                    temp_v = [jets_mass_nom[idx] for idx in order]
                    self.out.fillBranch(bname, temp_v)
                else:
                    temp_b = bname.replace(self.jetBranchName + '_', '')
                    temp_v = [jets[idx][temp_b] for idx in order]
                    self.out.fillBranch(bname, temp_v)

        #Save new branches to jet collection
        self.out.fillBranch("%s_corr_JER" % self.jetBranchName,
                            [jets_corr_JER[idx] for idx in order])
        self.out.fillBranch("%s_pt_JERUp" % self.jetBranchName,
                            [jets_pt_JERUp[idx] for idx in order])
        self.out.fillBranch("%s_pt_JERDown" % self.jetBranchName,
                            [jets_pt_JERDown[idx] for idx in order])
        self.out.fillBranch("%s_mass_JERUp" % self.jetBranchName,
                            [jets_mass_JERUp[idx] for idx in order])
        self.out.fillBranch("%s_mass_JERDown" % self.jetBranchName,
                            [jets_mass_JERDown[idx] for idx in order])

        return True
Пример #11
0
    def analyze(self, event):
        jets = Collection(event, self.jetBranchName)
        genJets = Collection(event, self.genJetBranchName)
        self.corrMET = True

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

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

        if self.corrMET:
            met = Object(event, self.metBranchName)
            met.px = met.pt * math.cos(met.phi)
            met.py = met.pt * math.sin(met.phi)

            met.px_jerNominal, met.py_jerNominal = 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.py_jesUp[
                    jesUncertainty] = met.px, met.py
                met.px_jesDown[jesUncertainty], met.py_jesDown[
                    jesUncertainty] = met.px, met.py

        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_jes = PhysicsObject(jet)
            #print jet_jes.p4().Pt()
            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 )
            #these are the smear factors => use for energy instead of pT!!!
            (jet_pt_jerNomVal, jet_pt_jerUpVal,
             jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt(
                 jet, genJet, rho)

            #if self.redoJEC:
            #   jet.pt = self.jetReCalibrator.correct(jet,rho)

            jet.pt_jerNominal = jet_pt_jerNomVal * jet.pt
            if jet.pt_jerNominal < 0.0:
                jet.pt_jerNominal *= -1.0

            jet.pt_jerUp = jet_pt_jerUpVal * jet.pt
            jet.pt_jerDown = jet_pt_jerDownVal * jet.pt

            jet.pt_jesUp = {}
            jet.pt_jesDown = {}

            for jesUncertainty in self.jesUncertainties:
                # (cf. https://twiki.cern.ch/twiki/bin/view/CMSPublic/WorkBookJetEnergyCorrections#JetCorUncertainties )
                self.jesUncertainty[jesUncertainty].setJetPt(jet.pt_jerNominal)
                self.jesUncertainty[jesUncertainty].setJetEta(jet.eta)
                delta = self.jesUncertainty[jesUncertainty].getUncertainty(
                    True)
                jet.pt_jesUp[jesUncertainty] = jet.pt_jerNominal * (1. + delta)
                jet.pt_jesDown[jesUncertainty] = jet.pt_jerNominal * (1. -
                                                                      delta)

            # progate JER and JES corrections and uncertainties to MET
            if self.corrMET and jet.pt_jerNominal > self.unclEnThreshold:
                jet_cosPhi = math.cos(jet.phi)
                jet_sinPhi = math.sin(jet.phi)

                #propagate nominal jet energy smearing
                met.px_jerNominal = met.px - (jet.pt_jerNominal -
                                              jet.pt) * jet_cosPhi
                met.py_jerNominal = met.py - (jet.pt_jerNominal -
                                              jet.pt) * jet_sinPhi

                met.px_jerUp = met.px_jerUp - (jet.pt_jerUp -
                                               jet.pt_jerNominal) * jet_cosPhi
                met.py_jerUp = met.py_jerUp - (jet.pt_jerUp -
                                               jet.pt_jerNominal) * jet_sinPhi
                met.px_jerDown = met.px_jerDown - (
                    jet.pt_jerDown - jet.pt_jerNominal) * jet_cosPhi
                met.py_jerDown = met.py_jerDown - (
                    jet.pt_jerDown - jet.pt_jerNominal) * jet_sinPhi
                for jesUncertainty in self.jesUncertainties:
                    met.px_jesUp[jesUncertainty] = met.px_jesUp[
                        jesUncertainty] - (jet.pt_jesUp[jesUncertainty] -
                                           jet.pt_jerNominal) * jet_cosPhi
                    met.py_jesUp[jesUncertainty] = met.py_jesUp[
                        jesUncertainty] - (jet.pt_jesUp[jesUncertainty] -
                                           jet.pt_jerNominal) * jet_sinPhi
                    met.px_jesDown[jesUncertainty] = met.px_jesDown[
                        jesUncertainty] - (jet.pt_jesDown[jesUncertainty] -
                                           jet.pt_jerNominal) * jet_cosPhi
                    met.py_jesDown[jesUncertainty] = met.py_jesDown[
                        jesUncertainty] - (jet.pt_jesDown[jesUncertainty] -
                                           jet.pt_jerNominal) * 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_jerNominal - met.px)
            met.py_jerUp = met.py_jerUp + (met.py_jerNominal - met.py)
            met.px_jerDown = met.px_jerDown + (met.px_jerNominal - met.px)
            met.py_jerDown = met.py_jerDown + (met.py_jerNominal - met.py)
            for jesUncertainty in self.jesUncertainties:
                met.px_jesUp[jesUncertainty] = met.px_jesUp[jesUncertainty] + (
                    met.px_jerNominal - met.px)
                met.py_jesUp[jesUncertainty] = met.py_jesUp[jesUncertainty] + (
                    met.py_jerNominal - met.py)
                met.px_jesDown[jesUncertainty] = met.px_jesDown[
                    jesUncertainty] + (met.px_jerNominal - met.px)
                met.py_jesDown[jesUncertainty] = met.py_jesDown[
                    jesUncertainty] + (met.py_jerNominal - met.py)
            met.px_unclEnUp = met.px_unclEnUp + (met.px_jerNominal - met.px)
            met.py_unclEnUp = met.py_unclEnUp + (met.py_jerNominal - met.py)
            met.px_unclEnDown = met.px_unclEnDown + (met.px_jerNominal -
                                                     met.px)
            met.py_unclEnDown = met.py_unclEnDown + (met.py_jerNominal -
                                                     met.py)

        def getJetsSyst(systName="nominal", variation=0):
            if variation not in [0, -1, 1]:
                print "Error - variation needs to be either [0,-1,1]!"
                sys.exit(1)
            systJets = []
            for jet in jets:
                systJet = PhysicsObject(jet,
                                        pt=jet.pt,
                                        eta=jet.eta,
                                        phi=jet.phi,
                                        mass=jet.mass,
                                        nConstituents=jet.nConstituents,
                                        keys=[
                                            "jetId", "hadronFlavour",
                                            "partonFlavour", "genJetIdx",
                                            "puId"
                                        ])
                if systName == "nominal":
                    systJet.pt = jet.pt_jerNominal
                elif systName == "jer":
                    if variation == 1:
                        systJet.pt = jet.pt_jerUp
                    elif variation == -1:
                        systJet.pt = jet.pt_jerDown
                    else:
                        print "Error - 'jer' variation needs to be either [-1,1]!"
                        sys.exit(1)
                elif systName.startswith("jes"):
                    subvariation = "Total"
                    if systName.find(':') > 0:
                        subvariation = systName.split(':', 1)[1]
                    if subvariation not in self.jesUncertainties:
                        print "Error - 'jes' subvariation with name '" + subvariation + "' has not been calculated"
                        sys.exit(1)
                    if variation == 1:
                        systJet.pt = jet.pt_jesUp[subvariation]
                    elif variation == -1:
                        systJet.pt = jet.pt_jesDown[subvariation]
                    else:
                        print "Error - 'jer' variation needs to be either [-1,1]!"
                        sys.exit(1)
                else:
                    print "Error - unknown systematic '" + str(systName) + "'"
                    sys.exit(1)

                systJets.append(systJet)

            #sort decreasing in pt
            systJets = sorted(systJets, key=lambda jet: -jet.pt)

            return systJets

        def getMetSyst(systName="nominal", variation=0):
            if variation not in [0, -1, 1]:
                print "Error - variation needs to be either [0,-1,1]!"
                sys.exit(1)
            systMet = PhysicsObject(met, pt=met.pt, phi=met.phi)
            if systName == "nominal":
                systMet.px = met.px_jerNominal
                systMet.py = met.py_jerNominal
            elif systName == "jer":
                if variation == 1:
                    systMet.px = met.px_jerUp
                    systMet.py = met.py_jerUp
#print "sys met px var +1  is : ", systMet.px , "  sys met py var + 1 is : ", systMet.py
                elif variation == -1:
                    systMet.px = met.px_jerDown
                    systMet.py = met.py_jerDown
#print "sys met px  var -1 is : ", systMet.px , "  sys met py var -1 is : ", systMet.py
                else:
                    print "Error - 'jer' variation needs to be either [-1,1]!"
                    sys.exit(1)
            elif systName.startswith("jes"):
                subvariation = "Total"
                if systName.find(':') > 0:
                    subvariation = systName.split(':', 1)[1]
                if variation == 1:
                    systMet.px = met.px_jesUp[subvariation]
                    systMet.py = met.py_jesUp[subvariation]
                elif variation == -1:
                    systMet.px = met.px_jesDown[subvariation]
                    systMet.py = met.py_jesDown[subvariation]
                else:
                    print "Error - 'jer' variation needs to be either [-1,1]!"
                    sys.exit(1)
            elif systName == "unclEn":
                if variation == 1:
                    systMet.px = met.px_unclEnUp
                    systMet.py = met.py_unclEnUp
                elif variation == -1:
                    systMet.px = met.px_unclEnDown
                    systMet.py = met.py_unclEnDown
                else:
                    print "Error - 'jer' variation needs to be either [-1,1]!"
                    sys.exit(1)
            else:
                print "Error - unknown systematic '" + str(systName) + "'"
                sys.exit(1)

            systMet.phi = math.atan2(systMet.py, systMet.px)
            systMet.pt = math.sqrt(systMet.px**2 + systMet.py**2)

            return systMet

        event.jets_nominal = getJetsSyst("nominal", 0)

        event.met_nominal = getMetSyst("nominal", 0)

        #print map(lambda j: j.pt, jets),met.pt
        #print map(lambda j: j.pt, event.jets_nominal),event.met_nominal.pt
        #print
        event.jets_jerUp = getJetsSyst("jer", 1)
        event.met_jerUp = getMetSyst("jer", 1)
        event.jets_jerDown = getJetsSyst("jer", -1)
        event.met_jerDown = getMetSyst("jer", -1)

        event.jets_jesUp = {}
        event.met_jesUp = {}
        event.jets_jesDown = {}
        event.met_jesDown = {}
        for jesUncertainty in self.jesUncertainties:
            event.jets_jesUp[jesUncertainty] = getJetsSyst(
                "jes:" + jesUncertainty, 1)
            event.met_jesUp[jesUncertainty] = getMetSyst(
                "jes:" + jesUncertainty, 1)
            event.jets_jesDown[jesUncertainty] = getJetsSyst(
                "jes:" + jesUncertainty, -1)
            event.met_jesDown[jesUncertainty] = getMetSyst(
                "jes:" + jesUncertainty, -1)

        event.met_unclEnUp = getMetSyst("unclEn", 1)
        event.met_unclEnDown = getMetSyst("unclEn", -1)

        return True
	def analyze(self, event):
		"""process event, return True (go to next module) or False (fail, go to next event)"""
		# Leptons
		leptonSel(event)
		nLooseLepton = len(event.selectedLeptons)
		#Select good leptons (stricter than medium but not as strict as tight)
		selectedGoodLeptons = []
		selectedVetoLeptons = []
		antiIsolatedGoodLeptons = []
		for lepton in event.selectedLeptons:
			leptonEta = abs(lepton.eta)
			# Pt cut
			if lepton.pt < 10: continue

			# Iso cut -- to be compatible with the trigger
			if lepton.miniPFRelIso_all > self.cut.trig_miniIsoCut: continue
			# MUONS
			if(abs(lepton.pdgId) == 13):
				if leptonEta > self.cut.muonEta: continue
				#passId = False
				passId = lepton.mediumId
				passIso = lepton.miniPFRelIso_all < self.cut.muo_miniIsoCut
				passIP = lepton.sip3d < self.cut.goodMu_sip3d

				# selected muons
				if passId and passIP and passIso:
					selectedGoodLeptons.append(lepton)
				else:
					selectedVetoLeptons.append(lepton)
				if not passIso:
					antiIsolatedGoodLeptons.append(lepton)

			# ELECTRONS
			elif(abs(lepton.pdgId) == 11):

				if leptonEta > self.cut.electronEta: continue

				passIso = False
				passGoodID = lepton.cutBased == 4
				passMediumID = lepton.cutBased >= 3
				passVetoID = lepton.cutBased >= 1
				# selected
				if passGoodID:
					passIso = lepton.miniPFRelIso_all < self.cut.ele_miniIsoCut
					if passIso:
						selectedGoodLeptons.append(lepton)
					else:
						selectedVetoLeptons.append(lepton)

				# anti-selected
				elif not passMediumID:
					# all anti leptons are veto for selected
					selectedVetoLeptons.append(lepton)

					# Iso check
					passIso = lepton.miniPFRelIso_all < self.cut.Lep_miniIsoCut
					# other checks
					passOther = False
					if hasattr(lepton, "hoe"):
						passOther = lepton.hoe > 0.01

					# fill
					if passIso and passOther:
						antiIsolatedGoodLeptons.append(lepton)
				# Veto leptons
				elif passVetoID:
					selectedVetoLeptons.append(lepton)

		for lepton in event.otherLeptons:
			# check acceptance
			leptonEta = abs(lepton.eta)
			if leptonEta > self.cut.electronEta: continue
			# Pt cut
			if lepton.pt < self.cut.minLeptonPt: continue
			# Iso cut -- to be compatible with the trigger
			if lepton.miniPFRelIso_all > self.cut.trig_miniIsoCut: continue

			# Muons
			if(abs(lepton.pdgId) == 13):
				passIso = lepton.miniPFRelIso_all > self.cut.muo_miniIsoCut
				if passIso:
					antiIsolatedGoodLeptons.append(lepton)

			# Electrons
			elif(abs(lepton.pdgId) == 11):
				if leptonEta > self.cut.electronEta: continue
				if lepton.miniPFRelIso_all > self.cut.Lep_miniIsoCut: continue

				passMediumID = lepton.cutBased >= 3
				passVetoID = lepton.cutBased >= 1
				if not passMediumID:
					passOther = False
					if hasattr(lepton, "hoe"):
						passOther = lepton.hoe > 0.01
					if passOther:
						antiIsolatedGoodLeptons.append(lepton)
		#selectedGoodLeptons, selectedVetoLeptons, antiIsolatedGoodLeptons = self.selectGoodLeptons(event.selectedLeptons, event.otherLeptons)
		nGoodLepton = len(selectedGoodLeptons)
		nVetoLepton = len(selectedVetoLeptons)
		nAntiIsolatedGoodLepton = len(antiIsolatedGoodLeptons)
		self.out.fillBranch("nGoodLepton", nGoodLepton)
		self.out.fillBranch("nVetoLepton", nVetoLepton)
		self.out.fillBranch("nAntiIsolatedGoodLepton", nAntiIsolatedGoodLepton)
		if nGoodLepton > 0:
			self.out.fillBranch("leadingLeptonSelected", 1)
			if nGoodLepton > 1:
				self.out.fillBranch("secondLeptonSelected", 1)
			else:
				self.out.fillBranch("secondLeptonSelected", 0)
		elif nAntiIsolatedGoodLepton == 0:
			self.out.fillBranch("leadingLeptonSelected", 0)
		else:
			self.out.fillBranch("leadingLeptonSelected", -1)

		goodElectron = [lep for lep in selectedGoodLeptons if abs(lep.pdgId) == 11]
		vetoElectron = [lep for lep in selectedVetoLeptons if abs(lep.pdgId) == 11]
		goodMuon = [lep for lep in selectedGoodLeptons if abs(lep.pdgId) == 13]
		vetoMuon = [lep for lep in selectedVetoLeptons if abs(lep.pdgId) == 13]
		nGoodElectron = len(goodElectron)
		nVetoElectron = len(vetoElectron)
		nGoodMuon = len(goodMuon)
		nVetoMuon = len(vetoMuon)
		self.out.fillBranch("nGoodElectron", nGoodElectron)
		self.out.fillBranch("nVetoElectron", nVetoElectron)
		self.out.fillBranch("nGoodMuon", nGoodMuon)
		self.out.fillBranch("nVetoMuon", nVetoMuon)
		""" TODO investigate electron energy calibration """
		for electron in goodElectron:
			self.out.fillBranch("goodElectronECorr", electron.eCorr)
		for electron in vetoElectron:
			self.out.fillBranch("vetoElectronECorr", electron.eCorr)

		if nGoodLepton > 0:
			self.out.fillBranch("leptonPt", selectedGoodLeptons[0].pt)
			self.out.fillBranch("leptonEta", selectedGoodLeptons[0].eta)
			self.out.fillBranch("leptonPhi", selectedGoodLeptons[0].phi)
			self.out.fillBranch("leptonPdgId", selectedGoodLeptons[0].pdgId)

			self.out.fillBranch("leptonRelIso", selectedGoodLeptons[0].pfRelIso03_all)
			self.out.fillBranch("leptonMiniIso", selectedGoodLeptons[0].miniPFRelIso_all)
			if hasattr(selectedGoodLeptons[0], "hoe"):
				self.out.fillBranch("leptonHOverE", selectedGoodLeptons[0].hoe)
			if self.isMC:
				for lepton in selectedGoodLeptons:
					if abs(lepton.pdgId) == 13:
						muonScaleFactor = self.workerMuon.getSF(lepton.pdgId, lepton.pt, lepton.eta)
						self.out.fillBranch("leptonSF", muonScaleFactor)
						self.out.fillBranch("MuonEffSF", muonScaleFactor)
					elif abs(lepton.pdgId) == 11:
						electronScaleFactor = self.workerElectron.getSF(lepton.pdgId, lepton.pt, lepton.eta)
						self.out.fillBranch("leptonSF", electronScaleFactor)
						self.out.fillBranch("ElectronEffSF", electronScaleFactor)
					else:
						self.out.fillBranch("MuonEffSF", 1.0)
						self.out.fillBranch("ElectronEffSF", 1.0)
						self.out.fillBranch("leptonSF", 1.0)
			else:
				self.out.fillBranch("MuonEffSF", 1.0)
				self.out.fillBranch("ElectronEffSF", 1.0)
				self.out.fillBranch("leptonSF", 1.0)

		if len(selectedGoodLeptons) > 1:
			self.out.fillBranch("secondLeptonPt", selectedGoodLeptons[1].pt)

		# Jets
		Jets = Collection(event, "Jet")
		jets = [j for j in Jets if j.pt > 20 and abs(j.eta) < 2.4]

		centralJets30 = []
		centralJets40 = []
		cleanJets25 = []
		cleanJets = []
		# fill this flag but defaults to 1 and then change it after the proper selection
		self.out.fillBranch("Flag_fastSimCorridorJetCleaning", 1)

		for index, jet in enumerate(jets):
			jet.pt = event.Jet_pt_nom[index]
			if self.isSignal: #only check for signals (see condition check above)
				self.out.fillBranch("isDPhiSignal",1)
				genJets = Collection(event, "GenJet" )
				pairs = matchObjectCollection(Jets, genJets)
				genJet = pairs[jet]
				if genJet is not None :
					if jet.pt > 20 and abs(jet.eta) < self.cut.jetEta and (genJet.pt == 0) and jet.chHEF < 0.1:
						self.out.fillBranch("Flag_fastSimCorridorJetCleaning", 0 )
			if jet.pt > 25 :
				cleanJets25.append(jet)
			if jet.pt  >  30 and abs(jet.eta) < self.cut.centralEta:
				centralJets30.append(jet)
			if jet.pt > 40 and abs(jet.eta) < self.cut.centralEta:
				centralJets40.append(jet)

		nJet = len(jets)
		nCentralJets30 = len(centralJets30)
		nCentralJets40 = len(centralJets40)
		self.out.fillBranch("nJet", nJet)
		self.out.fillBranch("nJet30", nCentralJets30)
		self.out.fillBranch("nJet40", nCentralJets40)

		##############################
		## Local cleaning from leptons
		##############################
		dRminCut = 0.4 #TODO susy cutter

		# Do cleaning a la CMG: clean max 1 jet for each lepton (the nearest)
		cleanJets30 = centralJets30
		if len(selectedGoodLeptons) > 0:
			tightLeptons = selectedGoodLeptons
		elif len(antiIsolatedGoodLeptons) > 0:
			tightLeptons = antiIsolatedGoodLeptons
		else:
			tightLeptons = []
		for lepton in tightLeptons:
			closestJet = None
			dRmin = 99
			for jet in centralJets30:
				dR = jet.p4().DeltaR(lepton.p4())
				if dR < dRmin:
					closestJet = jet
					dRmin = dR
			if dRmin < dRminCut:
				cleanJets30.remove(closestJet)
			dR = 99 #TODO think if this makes sense, maybe I just remove ones that are closer thant he closest
			for jet25 in cleanJets25:
				dR = jet25.p4().DeltaR(lepton.p4())
				if dR < dRmin:
					cleanJets.append(jet25)
		# cleaned jets
		nCleanJet30 = len(cleanJets30)

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

		if nCleanJet30 > 0:
			self.out.fillBranch("jetPt", cleanJets30[0].pt)
			self.out.fillBranch("jetEta", cleanJets30[0].eta)
		if nCleanJet30 > 1:
			self.out.fillBranch("jetPt_2", cleanJets30[1].pt)
			self.out.fillBranch("jetEta_2", cleanJets30[1].eta)

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

		self.out.fillBranch("HT", sum([j.pt for j in cleanJets30]))
		self.out.fillBranch("cleanJetHt30", sum([j.pt for j in cleanJets30]))
		self.out.fillBranch("jetHt30", sum([j.pt for j in jets if j.pt>30]))
		#centralJetHt40 = sum([jet.pt for jet in centralJets40])
		self.out.fillBranch("centralJetHt40", sum([j.pt for j in centralJets40]))
		#self.out.fillBranch("centralJetHt40", centralJetHt40)

		## 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
		#TODO define in init function, possibly use susyCutter
		btagWP = self.cut.btagMediumWP
		btagDeepMediumWP = self.cut.btagDeepMediumWP
		btagLooseWP = self.cut.btagLooseWP

		BJetMedium30 = []
		BJetMedium40 = []

		nBJetDeep = 0

		for jet in cleanJets30:
			if jet.btagCSVV2 > btagWP:
				BJetMedium30.append(jet)
			if jet.btagDeepB > btagDeepMediumWP:
				nBJetDeep += 1

		for jet in centralJets40:
			if jet.btagCSVV2 > btagWP:
				BJetMedium40.append(jet)

		# 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))
		#TODO store btag maybe?

		# High Level Variables
		dPhiLeptonW = -999
		GendPhiLeptonW = -999
		LT = -999
		GenLT = -999
		Lp = -999
		MT = -999
		metP4 = ROOT.TLorentzVector(0,0,0,0)
		metP4.SetPtEtaPhiM(event.MET_pt_nom, 0., event.MET_phi_nom, 0)

		if len(tightLeptons) > 0:
			#GenrecoWp4 =  tightLeptons[0].p4() + GenmetP4 #this does not make sense, use genmet of leptons
			#GendPhiLeptonW = tightLeptons[0].p4().DeltaPhi(GenrecoWp4)
			#GenLT = tightLeptons[0].pt + GenmetP4.Pt()
			recoWp4 =  tightLeptons[0].p4() + metP4
			dPhiLeptonW = tightLeptons[0].p4().DeltaPhi(recoWp4)
			LT = tightLeptons[0].pt + metP4.Pt()
			Lp = tightLeptons[0].pt / recoWp4.Pt() * ROOT.TMath.Cos(dPhiLeptonW)
			MT = ROOT.TMath.Sqrt(2*metP4.Pt()*tightLeptons[0].pt * (1-ROOT.TMath.Cos(dPhiLeptonW)))

		dPhi = abs(dPhiLeptonW)
		self.out.fillBranch("DeltaPhiLepW", dPhiLeptonW)
		self.out.fillBranch("dPhi", dPhi)
		#self.out.fillBranch("ST", LT) #ST? What?
		self.out.fillBranch("LT", LT)
		self.out.fillBranch("Lp", Lp)
		self.out.fillBranch("MT", MT)
		#self.out.fillBranch("GendPhi", abs(GendPhiLeptonW))
		#self.out.fillBranch("GenLT", GenLT)
		#self.out.fillBranch("GenMET", GenmetP4.Pt())

		# SIGNAL REGION FLAG
		# isSignalRegion SR vs CR flag
		isSignalRegion = 0

		# 0-B SRs -- simplified dPhi
		if len(BJetMedium30) == 0:# check the no. of Bjets
			if LT < 250:   isSignalRegion = 0
			elif LT > 250: isSignalRegion = dPhi > 0.75
			# BLIND data
			if (not self.isMC)  and nCleanJet30 >= 5:
				isSignalRegion = - isSignalRegion
		# Multi-B SRs
		elif nCleanJet30 < 99:
			if LT < 250:   isSignalRegion = 0
			elif LT < 350: isSignalRegion = dPhi > 1.0
			elif LT < 600: isSignalRegion = dPhi > 0.75
			elif LT > 600: isSignalRegion = dPhi > 0.5
			# BLIND data
			if (not self.isMC) and nCleanJet30 >= 6:
				isSignalRegion = - isSignalRegion

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

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

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

		if len(tightLeptons) > 1:

			leadingLepton = tightLeptons[0]
			id1 = leadingLepton.pdgId

			for trailingLepton in event.selectedLeptons[1:]:
				# TODO check if this could be tgrue for more than one pair of leptons
				if trailingLepton.pdgId + leadingLepton.pdgId == 0:
					dilepP4 = leadingLepton.p4() + trailingLepton.p4()
					dileptonMass = dilepP4.M()

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

		# RA2 proposed filter
		# TODO Learn what this is
		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(ROOT.TMath.ACos(ROOT.TMath.Cos(j.phi-metP4.Phi()))) > (ROOT.TMath.pi - 0.4):
		#		self.out.fillBranch("RA2_muJetFilter", False)


		## MET FILTERS for data looks like the met filters are applied already for nanoAOD #TODO check how this is done, in which module
		# Top Tagging
		lightJets = [ j for j in cleanJets if not j.btagCSVV2 == btagWP ]
		bjetsLoose  = [ j for j in cleanJets if j.btagCSVV2== self.cut.btagLooseWP]
		minMWjj   = -999
		minMWjjPt = -999
		bestMWjj   = -999
		bestMWjjPt = -999
		bestMTopHad   = -999
		bestMTopHadPt = -999
		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) #probably do not fill in here
					#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)

		self.out.fillBranch("minMWjj", minMWjj)
		self.out.fillBranch("minMWjjPt", minMWjjPt)
		self.out.fillBranch("bestMWjj", bestMWjj)
		self.out.fillBranch("bestMWjjPt", bestMWjjPt)
		self.out.fillBranch("bestMTopHad", bestMTopHad)
		self.out.fillBranch("bestMTopHadPt", bestMTopHadPt)
		# isolated tracks after basic selection (((pt>5 && (abs(pdgId) == 11 || abs(pdgId) == 13)) || pt > 10) && (abs(pdgId) < 15 || abs(eta) < self.cut.jetEta) && 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"):
			tracks = [j for j in Collection(event, "IsoTrack", "nIsoTrack")]
			trackp4 = 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(tightLeptons) > 0) and len(tracks) > 0:
				#for i, t in enumerate(tracks):
				for track in tracks:
					# looking for opposite charged tracks
					#if tightLeptons[0].charge == track.charge: continue # not track charge is founded replace with the next copule of lines
					if track.isHighPurityTrack == False : continue
					#print track.miniPFRelIso_chg
					# not track mass is founded
					trackp4.SetPtEtaPhiM(track.pt, track.eta, track.phi,0.)
					if trackp4.DeltaR(tightLeptons[0].p4()) < minDR:
						p1 = tightLeptons[0].p4()
						p2 = trackp4
						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()])
						self.mt2obj.set_momenta(a, b, c)
						self.mt2obj.set_mn(0)
						self.out.fillBranch("iso_MT2", self.mt2obj.get_mt2())
						self.out.fillBranch("iso_pt", p2.Pt())
					# cuts on MT2 as defined above
					if abs(track.pdgId)>10 and abs(track.pdgId)<14:
						self.out.fillBranch("iso_had", 0)  #leptonic
						cut = self.cut.lepMT2cut
					else:
						self.out.fillBranch("iso_had", 1)  #hadronic track
						cut = self.cut.hadMT2cut
					if self.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_SingleElectron", True)
		else:
			self.out.fillBranch("PD_SingleElectron", False)
		if 'SingleMu' in self.filename:
			self.out.fillBranch("PD_SingleMuon", True)
		else:
			self.out.fillBranch("PD_SingleMuon", False)
		if 'MET' in self.filename:
			self.out.fillBranch("PD_MET", True)
		else:
			self.out.fillBranch("PD_MET", False)
		return True
Пример #13
0
    def analyze(self, event):
        """process event, return True (go to next module) or False (fail, go to next event)"""
        allelectrons = Collection(event, "Electron")
        allmuons = Collection(event, "Muon")
        Jets = Collection(event, "Jet")
        met = Object(event, "MET")
        genmet = Object(event, "GenMET")
        # for all leptons (veto or tight)

        ### inclusive leptons = all leptons that could be considered somewhere in the analysis, with minimal requirements (used e.g. to match to MC)
        event.inclusiveLeptons = []
        ### selected leptons = subset of inclusive leptons passing some basic id definition and pt requirement
        ### other    leptons = subset of inclusive leptons failing some basic id definition and pt requirement
        event.selectedLeptons = []
        event.selectedMuons = []
        event.selectedElectrons = []
        event.otherLeptons = []
        inclusiveMuons = []
        inclusiveElectrons = []
        for mu in allmuons:
            if (mu.pt > 10 and abs(mu.eta) < 2.4 and abs(mu.dxy) < 0.5
                    and abs(mu.dz) < 1.):
                inclusiveMuons.append(mu)
        for ele in allelectrons:
            if (
                    ele.cutBased >= 1 and ele.pt > 10 and abs(ele.eta) < 2.4
            ):  # and abs(ele.dxy)<0.5 and abs(ele.dz)<1. and ele.lostHits <=1.0):
                inclusiveElectrons.append(ele)
        event.inclusiveLeptons = inclusiveMuons + inclusiveElectrons

        # make loose leptons (basic selection)
        for mu in inclusiveMuons:
            if (mu.pt > 10 and abs(mu.eta) < 2.4 and mu.miniPFRelIso_all < 0.4
                    and mu.isPFcand and abs(mu.dxy) < 0.05
                    and abs(mu.dz) < 0.5):
                event.selectedLeptons.append(mu)
                event.selectedMuons.append(mu)
            else:
                event.otherLeptons.append(mu)
        looseMuons = event.selectedLeptons[:]
        for ele in inclusiveElectrons:
            ele.looseIdOnly = ele.cutBased >= 1
            if (ele.looseIdOnly and ele.pt > 10 and abs(ele.eta) < 2.4
                    and ele.miniPFRelIso_all < 0.4 and ele.isPFcand
                    and ele.convVeto
                    and  # and abs(ele.dxy)<0.05 and abs(ele.dz)<0.5  and ele.lostHits <=1.0 and 
                (bestMatch(ele, looseMuons)[1] > (0.05**2))):
                event.selectedLeptons.append(ele)
                event.selectedElectrons.append(ele)
            else:
                event.otherLeptons.append(ele)
        event.otherLeptons.sort(key=lambda l: l.pt, reverse=True)
        event.selectedLeptons.sort(key=lambda l: l.pt, reverse=True)
        event.selectedMuons.sort(key=lambda l: l.pt, reverse=True)
        event.selectedElectrons.sort(key=lambda l: l.pt, reverse=True)
        event.inclusiveLeptons.sort(key=lambda l: l.pt, reverse=True)

        goodLep = [l for l in event.selectedLeptons]
        LepOther = [l for l in event.otherLeptons]
        #LepOther = goodLep
        leps = goodLep
        nlep = len(leps)
        ### LEPTONS

        # 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
                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 lep.convVeto)
                    passMediumID = (eidCB >= 3)  # and lep.convVeto)
                    #passLooseID = (eidCB >= 2)
                    passVetoID = (eidCB >= 1)  #and lep.convVeto)

                elif eleID == 'MVA':
                    # ELE MVA ID
                    # check MVA WPs
                    passTightID = checkEleMVA(lep, 'Tight')
                    passLooseID = checkEleMVA(lep, 'VLoose')
                # 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
                    if eleID == 'MVA':
                        if lep.lostHits <= goodEl_lostHits and lep.convVeto and lep.sip3d < goodEl_sip3d:
                            passConv = True
                    elif eleID == 'CB':
                        passConv = True  # cuts already included in POG_Cuts_ID_SPRING15_25ns_v1_ConvVetoDxyDz_X

                    passPostICHEPHLTHOverE = True  # comment out again if (lep.hOverE < 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]
        #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:
                #passID = lep.mediumMuonId == 1
                passIso = lep.miniPFRelIso_all > muo_miniIsoCut
                # cuts like for the LepGood muons
                #passIP = abs(lep.dxy) < 0.05 and abs(lep.dz) < 0.1

                #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)
                    passVetoID = (eidCB >= 1 and lep.convVeto)
                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)

        # choose common lepton collection: select selected or anti lepton
        if len(selectedTightLeps) > 0:
            tightLeps = selectedTightLeps
            tightLepsIdx = selectedTightLepsIdx
            vetoLeps = selectedVetoLeps

    #############
    #############
        # retrive and fill branches
        #############
        # choose common lepton collection: select selected or anti lepton
        if len(selectedTightLeps) > 0:
            tightLeps = selectedTightLeps
            tightLepsIdx = selectedTightLepsIdx

            vetoLeps = selectedVetoLeps

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

            vetoLeps = antiVetoLeps

        else:
            tightLeps = []
            tightLepsIdx = []

            vetoLeps = []
        nTightLeps = len(tightLeps)
        '''# Met 
		metp4 = ROOT.TLorentzVector(0,0,0,0)
		if hasattr(event, 'metMuEGClean_pt'):
			metp4.SetPtEtaPhiM(event.metMuEGClean_pt,event.metMuEGClean_eta,event.metMuEGClean_phi,event.metMuEGClean_mass)
		else:
			metp4.SetPtEtaPhiM(met.pt,0,met.phi,0)
		if hasattr(event, 'metMuEGClean_pt'):
			pmiss  =array.array('d',[event.metMuEGClean_pt * math.cos(event.metMuEGClean_phi), event.metMuEGClean_pt * math.sin(event.metMuEGClean_phi)] )
		else:
			pmiss  =array.array('d',[met.pt * math.cos(met.phi), met.pt * math.sin(met.phi)] )'''

        #####################################################################
        #####################################################################
        #################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)
        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:
            rho = getattr(event, "fixedGridRhoFastjetAll")
            genJets = Collection(event, "GenJet")
            pairs = matchObjectCollection(Jets, genJets)
            for jet in jets:
                genJet = pairs[jet]
                if smearJER == True:
                    (jet_pt_jerNomVal, jet_pt_jerUpVal,
                     jet_pt_jerDownVal) = self.jetSmearer.getSmearValsPt(
                         jet, genJet, rho)
                    jet_pt_nom = jet_pt_jerNomVal * jet.pt
                    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
                    jet.pt = jet_pt_nom
        metp4.SetPtEtaPhiM(
            met.pt, 0., met.phi,
            0.)  # only use met vector to derive transverse quantities)

        centralJet30 = []
        centralJet30idx = []
        centralJet40 = []
        cleanJets25 = []
        cleanJets25idx = []
        cleanJets = []
        cleanJetsidx = []
        # fill this flage but defults to 1 and then change it after the proper selection
        for i, j in enumerate(jets):
            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)
        nCentralJet30 = len(centralJet30)

        btagWP = btag_MediumWP

        BJetMedium30 = []
        BJetMedium30idx = []

        BJetMedium40 = []

        nBJetDeep = 0

        cJet30Clean = []
        dRminCut = 0.4

        # Do cleaning a la CMG: clean max 1 jet for each lepton (the nearest)
        cJet30Clean = centralJet30
        cleanJets30 = centralJet30

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

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

        nBJetMedium30 = len(BJetMedium30)
        ##################################################################
        # The following variables need to be double-checked for validity #
        ##################################################################

        ## B tagging WPs for CSVv2 (CSV-IVF)
        ## L: 0.423, M: 0.814, T: 0.941
        ## from: https://twiki.cern.ch/twiki/bin/view/CMSPublic/SWGuideBTagging#Preliminary_working_or_operating

        bTagWP = 0.814  # MediumWP for CSVv2
        #bTagWP = 0.732 # MediumWP for CMVA

        # min deltaPhi between a b-jet and MET; needs to be double-checked
        minDPhiBMET = 100
        idxMinDPhiBMET = -999
        for i, jet in enumerate(centralJet30):
            if jet.btagCSVV2 > bTagWP:
                dPhiBMET = abs(jet.p4().DeltaPhi(metp4))
                if dPhiBMET < minDPhiBMET:
                    minDPhiBMET = dPhiBMET
                    idxMinDPhiBMET = i

        self.out.fillBranch("idxMinDPhiBMET", idxMinDPhiBMET)
        self.out.fillBranch("minDPhiBMET", minDPhiBMET)

        # min deltaPhi between a jet (first three jets) and MET; needs to be double-checked
        minDPhiJMET = 100
        for i, jet in enumerate(centralJet30[:3]):
            dPhiJMET = abs(jet.p4().DeltaPhi(metp4))
            if dPhiJMET < minDPhiJMET:
                minDPhiJMET = dPhiJMET

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

        # transverse mass of (closest (to MET) BJet, MET), (closest (to MET) BJet, lepton),
        # mass of (closest (to MET) BJet, lepton); need to be double-checked
        mTBJetMET = -999
        mTLepMET = -999
        mLepBJet = -999
        if (idxMinDPhiBMET >= 0):
            SumMetClosestBJet = jets[idxMinDPhiBMET].p4() + metp4
            self.out.fillBranch("mTClBPlusMET", SumMetClosestBJet.Mt())
            mTBJetMET = mt_2(centralJet30[idxMinDPhiBMET].p4(), metp4)
            if nTightLeps >= 1:
                mLepBJet = (centralJet30[idxMinDPhiBMET].p4() +
                            tightLeps[0].p4()).M()
                mTLepMET = mt_2(tightLeps[0].p4(), metp4)
        else:
            self.out.fillBranch("mTClBPlusMET", -999)

        self.out.fillBranch("mTBJetMET", mTBJetMET)
        self.out.fillBranch("mTLepMET", mTLepMET)
        self.out.fillBranch("mLepBJet", mLepBJet)

        # projection of MET along (MET + lepton + (closest (to MET) BJet)) sum; needs to be double-checked...
        MetZ1 = -9999
        MetZ2 = -9999
        MTW = -9999
        MW1 = -9999
        MW2 = -9999
        neutrino1 = ROOT.TLorentzVector(0, 0, 0, 0)
        neutrino2 = ROOT.TLorentzVector(0, 0, 0, 0)
        if (nTightLeps == 1):
            NeutrZList = GetZfromM(tightLeps[0].p4(), metp4, 81)
            MTW = NeutrZList[0]
            MetZ1 = NeutrZList[1]
            MetZ2 = NeutrZList[2]
            neutrino1.SetXYZM(metp4.Px(), metp4.Py(), MetZ1, 0)
            neutrino2.SetXYZM(metp4.Px(), metp4.Py(), MetZ2, 0)
            MW1 = (neutrino1 + tightLeps[0].p4()).M()
            MW2 = (neutrino2 + tightLeps[0].p4()).M()
        self.out.fillBranch("MTW", MTW)
        self.out.fillBranch("MW1", MW1)
        self.out.fillBranch("MW2", MW2)
        # some extra plots

        MTbnu = []
        LepBMass = []
        MTtop = []
        Mtop = []
        METovTop = []
        METTopPhi = []
        MtopDecor = []

        TopEt = []
        TopPt = []

        if (nTightLeps == 1):
            for i, jet in enumerate(
                    centralJet30):  #testing all jets as b-jet in top-reco
                if hasattr(event, 'metMuEGClean_pt'):
                    ThisMTnub = math.sqrt(
                        2 * event.metMuEGClean_pt * jet.pt *
                        (1 - math.cos(metp4.DeltaPhi(jet.p4()))))
                else:
                    ThisMTnub = math.sqrt(
                        2 * met.pt * jet.pt *
                        (1 - math.cos(metp4.DeltaPhi(jet.p4()))))
                MTbnu.append(ThisMTnub)

                # lep + jet vector
                lepJp4 = tightLeps[0].p4() + jet.p4()

                ThislepBMass = lepJp4.M()
                LepBMass.append(ThislepBMass)

                # top vector: MET + lep + jet
                topP4 = metp4 + lepJp4
                TopEt.append(topP4.Et())
                TopPt.append(topP4.Pt())

                ThisMTtop = math.sqrt(81. * 81. + ThislepBMass * ThislepBMass +
                                      ThisMTnub * ThisMTnub)
                MTtop.append(ThisMTtop)

                if hasattr(event, 'metMuEGClean_pt'):
                    ThisMetovTop = event.metMuEGClean_pt / topP4.Pt()
                else:
                    ThisMetovTop = met.pt / topP4.Pt()
                METovTop.append(ThisMetovTop)

                ThisMetTop = metp4.DeltaPhi(metp4 + lepJp4)
                METTopPhi.append(ThisMetTop)

                TopMass1 = (neutrino1 + lepJp4).M()
                TopMass2 = (neutrino2 + lepJp4).M()

                #take smaller mtop of the two nu pz-solutions
                if TopMass1 > TopMass2:
                    Mtop.append(TopMass2)
                else:
                    Mtop.append(TopMass1)

                ThisMtopDecor1 = math.sqrt(lepJp4.M() * lepJp4.M() +
                                           (neutrino1 + jet.p4()).M() *
                                           (neutrino1 + jet.p4()).M() +
                                           81 * 81)
                ThisMtopDecor2 = math.sqrt(lepJp4.M() * lepJp4.M() +
                                           (neutrino2 + jet.p4()).M() *
                                           (neutrino2 + jet.p4()).M() +
                                           81 * 81)

                if ThisMtopDecor1 > ThisMtopDecor2:
                    MtopDecor.append(ThisMtopDecor2)
                else:
                    MtopDecor.append(ThisMtopDecor1)

        # fill them
        self.out.fillBranch("MTbnu", MTbnu)
        self.out.fillBranch("LepBMass", LepBMass)
        self.out.fillBranch("MTtop", MTtop)
        self.out.fillBranch("Mtop", Mtop)
        self.out.fillBranch("METovTop", METovTop)
        self.out.fillBranch("METTopPhi", METTopPhi)
        self.out.fillBranch("MtopDecor", MtopDecor)

        self.out.fillBranch("TopPt", TopPt)
        self.out.fillBranch("TopEt", TopEt)

        # nearest b jet to lead lepton
        minDphiLepB = 100
        minDphiLepBidx = -1

        if nTightLeps == 1:
            for i, jet in enumerate(centralJet30):
                if jet.btagCSVV2 > bTagWP:
                    dPhiLepB = abs(jet.p4().DeltaPhi(tightLeps[0].p4()))
                    if dPhiLepB < minDphiLepB:
                        minDphiLepB = dPhiLepB
                        minDphiLepBidx = i

        self.out.fillBranch("minDphiLepB", minDphiLepB)
        self.out.fillBranch("minDphiLepBidx", minDphiLepBidx)

        #        TopVarsJetIdx = []
        TopVarsMTbnuMin = []
        TopVarsLepBMassMin = []
        TopVarsMTtopMin = []
        TopVarsMtopMin = []
        TopVarsMETovTopMin = []
        TopVarsMtopDecorMin = []

        TopVarsTopPtMin = []
        TopVarsTopEtMin = []

        iBTagDict = {
            i: jets[idx].btagCSVV2
            for i, idx in enumerate(centralJet30idx)
        }
        sortIdsByBTag = sorted(iBTagDict.items(),
                               key=operator.itemgetter(1),
                               reverse=True)
        bTaggedJetsSorted = sortIdsByBTag[:nBJetMedium30]
        #        print bTaggedJetsSorted
        bTaggedJetsPPSorted = sortIdsByBTag[:nBJetMedium30 + 1]
        #        print bTaggedJetsPPSorted
        ThreeBestBTags = sortIdsByBTag[:3]
        #        print ThreeBestBTags
        #        print sortIdsByBTag

        if nTightLeps == 1 and nCentralJet30 > 0:
            #0: minimum of b-tagged jets
            TopVarsMTbnuMin.append(
                minValueForIdxList(MTbnu,
                                   [ids[0] for ids in bTaggedJetsSorted]))
            TopVarsLepBMassMin.append(
                minValueForIdxList(LepBMass,
                                   [ids[0] for ids in bTaggedJetsSorted]))
            TopVarsMTtopMin.append(
                minValueForIdxList(MTtop,
                                   [ids[0] for ids in bTaggedJetsSorted]))
            TopVarsMtopMin.append(
                minValueForIdxList(Mtop,
                                   [ids[0] for ids in bTaggedJetsSorted]))
            TopVarsMETovTopMin.append(
                minValueForIdxList(METovTop,
                                   [ids[0] for ids in bTaggedJetsSorted]))
            TopVarsMtopDecorMin.append(
                minValueForIdxList(MtopDecor,
                                   [ids[0] for ids in bTaggedJetsSorted]))
            TopVarsTopPtMin.append(
                minValueForIdxList(TopPt,
                                   [ids[0] for ids in bTaggedJetsSorted]))
            TopVarsTopEtMin.append(
                minValueForIdxList(TopEt,
                                   [ids[0] for ids in bTaggedJetsSorted]))

            #1: minimum of b-tagged jets (+ adding next-best b-disc. jet)
            TopVarsMTbnuMin.append(
                minValueForIdxList(MTbnu,
                                   [ids[0] for ids in bTaggedJetsPPSorted]))
            TopVarsLepBMassMin.append(
                minValueForIdxList(LepBMass,
                                   [ids[0] for ids in bTaggedJetsPPSorted]))
            TopVarsMTtopMin.append(
                minValueForIdxList(MTtop,
                                   [ids[0] for ids in bTaggedJetsPPSorted]))
            TopVarsMtopMin.append(
                minValueForIdxList(Mtop,
                                   [ids[0] for ids in bTaggedJetsPPSorted]))
            TopVarsMETovTopMin.append(
                minValueForIdxList(METovTop,
                                   [ids[0] for ids in bTaggedJetsPPSorted]))
            TopVarsMtopDecorMin.append(
                minValueForIdxList(MtopDecor,
                                   [ids[0] for ids in bTaggedJetsPPSorted]))
            TopVarsTopPtMin.append(
                minValueForIdxList(TopPt,
                                   [ids[0] for ids in bTaggedJetsPPSorted]))
            TopVarsTopEtMin.append(
                minValueForIdxList(TopEt,
                                   [ids[0] for ids in bTaggedJetsPPSorted]))

            #2: always consider the three jets with the best b-tag values (no pass of any working-point required)
            TopVarsMTbnuMin.append(
                minValueForIdxList(MTbnu, [ids[0] for ids in ThreeBestBTags]))
            TopVarsLepBMassMin.append(
                minValueForIdxList(LepBMass,
                                   [ids[0] for ids in ThreeBestBTags]))
            TopVarsMTtopMin.append(
                minValueForIdxList(MTtop, [ids[0] for ids in ThreeBestBTags]))
            TopVarsMtopMin.append(
                minValueForIdxList(Mtop, [ids[0] for ids in ThreeBestBTags]))
            TopVarsMETovTopMin.append(
                minValueForIdxList(METovTop,
                                   [ids[0] for ids in ThreeBestBTags]))
            TopVarsMtopDecorMin.append(
                minValueForIdxList(MtopDecor,
                                   [ids[0] for ids in ThreeBestBTags]))
            TopVarsTopPtMin.append(
                minValueForIdxList(TopPt, [ids[0] for ids in ThreeBestBTags]))
            TopVarsTopEtMin.append(
                minValueForIdxList(TopEt, [ids[0] for ids in ThreeBestBTags]))
            if hasattr(tightLeps[0], 'genPartIdx'):
                mcMatchIdLep = tightLeps[0].genPartIdx
                iCorrectJet = -999
                correctJetBTagged = False
                if abs(mcMatchIdLep) == 6:
                    for i, jet in enumerate(centralJet30):
                        if abs(jet.partonFlavour
                               ) == 5 and jet.genJetIdx == mcMatchIdLep:
                            iCorrectJet = i
                            if jet.btagCSVV2 > bTagWP: correctJetBTagged = True

            #3: value for the correct b-jet (i.e. the one matching the lepton)
                TopVarsMTbnuMin.append(
                    MTbnu[iCorrectJet] if iCorrectJet > -999 else -999)
                TopVarsLepBMassMin.append(
                    LepBMass[iCorrectJet] if iCorrectJet > -999 else -999)
                TopVarsMTtopMin.append(
                    MTtop[iCorrectJet] if iCorrectJet > -999 else -999)
                TopVarsMtopMin.append(
                    Mtop[iCorrectJet] if iCorrectJet > -999 else -999)
                TopVarsMETovTopMin.append(
                    METovTop[iCorrectJet] if iCorrectJet > -999 else -999)
                TopVarsMtopDecorMin.append(
                    MtopDecor[iCorrectJet] if iCorrectJet > -999 else -999)
                TopVarsTopPtMin.append(
                    TopPt[iCorrectJet] if iCorrectJet > -999 else -999)
                TopVarsTopEtMin.append(
                    TopEt[iCorrectJet] if iCorrectJet > -999 else -999)

                foundCorrectBJetAndIsTagged = iCorrectJet > -999 and correctJetBTagged

                #4: value for the correct b-jet (if actually identified as b-jet (tagged))
                TopVarsMTbnuMin.append(MTbnu[iCorrectJet] if
                                       foundCorrectBJetAndIsTagged else -999)
                TopVarsLepBMassMin.append(
                    LepBMass[iCorrectJet]
                    if foundCorrectBJetAndIsTagged else -999)
                TopVarsMTtopMin.append(MTtop[iCorrectJet] if
                                       foundCorrectBJetAndIsTagged else -999)
                TopVarsMtopMin.append(
                    Mtop[iCorrectJet] if foundCorrectBJetAndIsTagged else -999)
                TopVarsMETovTopMin.append(
                    METovTop[iCorrectJet]
                    if foundCorrectBJetAndIsTagged else -999)
                TopVarsMtopDecorMin.append(
                    MtopDecor[iCorrectJet]
                    if foundCorrectBJetAndIsTagged else -999)
                TopVarsTopPtMin.append(TopPt[iCorrectJet] if
                                       foundCorrectBJetAndIsTagged else -999)
                TopVarsTopEtMin.append(TopEt[iCorrectJet] if
                                       foundCorrectBJetAndIsTagged else -999)

                #5: consider the jet closest in dphi to MET
                TopVarsMTbnuMin.append(
                    MTbnu[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999)
                TopVarsLepBMassMin.append(LepBMass[idxMinDPhiBMET]
                                          if idxMinDPhiBMET != -999 else -999)
                TopVarsMTtopMin.append(
                    MTtop[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999)
                TopVarsMtopMin.append(
                    Mtop[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999)
                TopVarsMETovTopMin.append(METovTop[idxMinDPhiBMET]
                                          if idxMinDPhiBMET != -999 else -999)
                TopVarsMtopDecorMin.append(MtopDecor[idxMinDPhiBMET]
                                           if idxMinDPhiBMET != -999 else -999)
                TopVarsTopPtMin.append(
                    TopPt[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999)
                TopVarsTopEtMin.append(
                    TopEt[idxMinDPhiBMET] if idxMinDPhiBMET != -999 else -999)

                #6: nearest to lepton b jet
                TopVarsMTbnuMin.append(
                    MTbnu[minDphiLepBidx] if minDphiLepBidx > -1 else -999)
                TopVarsLepBMassMin.append(
                    LepBMass[minDphiLepBidx] if minDphiLepBidx > -1 else -999)
                TopVarsMTtopMin.append(
                    MTtop[minDphiLepBidx] if minDphiLepBidx > -1 else -999)
                TopVarsMtopMin.append(
                    Mtop[minDphiLepBidx] if minDphiLepBidx > -1 else -999)
                TopVarsMETovTopMin.append(
                    METovTop[minDphiLepBidx] if minDphiLepBidx > -1 else -999)
                TopVarsMtopDecorMin.append(
                    MtopDecor[minDphiLepBidx] if minDphiLepBidx > -1 else -999)
                TopVarsTopPtMin.append(
                    TopPt[minDphiLepBidx] if minDphiLepBidx > -1 else -999)
                TopVarsTopEtMin.append(
                    TopEt[minDphiLepBidx] if minDphiLepBidx > -1 else -999)

        else:
            for i in range(7):
                TopVarsMTbnuMin.append(-999)
                TopVarsLepBMassMin.append(-999)
                TopVarsMTtopMin.append(-999)
                TopVarsMtopMin.append(-999)
                TopVarsMETovTopMin.append(-999)
                TopVarsMtopDecorMin.append(-999)
                TopVarsTopPtMin.append(-999)
                TopVarsTopEtMin.append(-999)

        self.out.fillBranch("nBMinVariantsTopVars", 7)
        self.out.fillBranch("TopVarsMTbnuMin", TopVarsMTbnuMin)
        self.out.fillBranch("TopVarsLepBMassMin", TopVarsLepBMassMin)
        self.out.fillBranch("TopVarsMTtopMin", TopVarsMTtopMin)
        self.out.fillBranch("TopVarsMtopMin", TopVarsMtopMin)
        self.out.fillBranch("TopVarsMETovTopMin", TopVarsMETovTopMin)
        self.out.fillBranch("TopVarsMtopDecorMin", TopVarsMtopDecorMin)
        self.out.fillBranch("TopVarsTopPtMin", TopVarsTopPtMin)
        self.out.fillBranch("TopVarsTopEtMin", TopVarsTopEtMin)

        return True