Exemple #1
0
    def analyze(self, event):
        """
        process event, return True (go to next module)
        or False (fail, go to next event)
        """
        electrons = list(Collection(event, "Electron"))
        muons = list(Collection(event, "Muon"))
        jets = list(Collection(event, "Jet"))
        taus = list(Collection(event, "Tau"))
        flag = Object(event, "Flag")
        met = Object(event, "MET")

        # in case of systematic take the shifted values are default
        # For the central values, need to include jetMetTool all the time
        # Jet systematics
        if self.syst_var == "":
            syst_var = "nom"
        else:
            syst_var = self.syst_var

        ##############################
        ## corrections and MET
        ##############################
        
        try:
            var_jet_pts = getattr(event,  "Jet_pt_{}".format(syst_var), None)
            if var_jet_pts:
                for i,jet in enumerate(jets):
                    jet.pt = var_jet_pts[i]
            else:
                print 'WARNING: jet pts with variation {}'
                'not available, using the nominal value'.format(syst_var)
        except:
            var_jet_pts = getattr(event,  "Jet_pt_nom", None)
            for i,jet in enumerate(jets):
                jet.pt = var_jet_pts[i]

        try:
            var_met_pt  = getattr(event,  "MET_pt_{}".format(syst_var), None)
            var_met_phi = getattr(event, "MET_phi_{}".format(syst_var), None)
            if var_met_pt:
                met.pt = var_met_pt
            else:
                print 'WARNING: MET pt with variation '
                '{} not available, using the nominal value'.format(syst_var)
            if var_met_phi:
                met.phi = var_met_phi
            else:
                print 'WARNING: MET phi with variation {}'
                'not available, using the nominal value'.format(syst_var)
        except:
            var_met_pt  = getattr(event,  "MET_pt_nom", None)
            var_met_phi = getattr(event, "MET_phi_nom", None)
            if var_met_pt:
                met.pt = var_met_pt
            if var_met_phi:
                met.phi = var_met_phi

        met_p4 = ROOT.TLorentzVector()
        met_p4.SetPtEtaPhiM(met.pt,0.0,met.phi, 0.0)

        # Electrons Energy
        if "ElectronEn" in self.syst_var:
            (met_px, met_py) = ( met.pt*np.cos(met.phi), met.pt*np.sin(met.phi) )
            if "Up" in self.syst_var:
                for i, elec in enumerate(electrons):
                    met_px = met_px + (elec.energyErr)*np.cos(elec.phi)/math.cosh(elec.eta)
                    met_py = met_py + (elec.energyErr)*np.sin(elec.phi)/math.cosh(elec.eta)
                    elec.pt = elec.pt + elec.energyErr/math.cosh(elec.eta)
            else:
                for i, elec in enumerate(electrons):
                    met_px = met_px - (elec.energyErr)*np.cos(elec.phi)/math.cosh(elec.eta)
                    met_py = met_py - (elec.energyErr)*np.sin(elec.phi)/math.cosh(elec.eta)
                    elec.pt = elec.pt - elec.energyErr/math.cosh(elec.eta)
            met.pt  = math.sqrt(met_px**2 + met_py**2)
            met.phi = math.atan2(met_py, met_px)

        # Muons Energy
        if self.isMC:
            muons_pts = getattr(event, "Muon_corrected_pt")
            for i, muon in enumerate(muons):
                muon.pt = muons_pts[i]

        if "MuonEn" in self.syst_var:
            (met_px, met_py) = ( met.pt*np.cos(met.phi), met.pt*np.sin(met.phi) )
            if "Up" in self.syst_var:
                muons_pts = getattr(event, "Muon_correctedUp_pt")
                for i, muon in enumerate(muons):
                    met_px = met_px - (muons_pts[i] - muon.pt)*np.cos(muon.phi)
                    met_py = met_py - (muons_pts[i] - muon.pt)*np.sin(muon.phi)
                    muon.pt = muons_pts[i]
            else:
                muons_pts = getattr(event, "Muon_correctedDown_pt")
                for i, muon in enumerate(muons):
                    met_px =met_px - (muons_pts[i] - muon.pt)*np.cos(muon.phi)
                    met_py =met_py - (muons_pts[i] - muon.pt)*np.sin(muon.phi)
                    muon.pt = muons_pts[i]
            met.pt  = math.sqrt(met_px**2 + met_py**2)
            met.phi = math.atan2(met_py, met_px)
            
        pass_met_filter = self.met_filter(flag, True)

        # filling and contructing the event categorisation
        self.out.fillBranch("met_pt{}".format(self.syst_suffix), met.pt)
        self.out.fillBranch("met_phi{}".format(self.syst_suffix), met.phi)
        self.out.fillBranch("met_filter{}".format(self.syst_suffix), pass_met_filter)

        ##############################
        ## process leptons 
        ##############################

        muons.sort(key=lambda muon: muon.pt, reverse=True)
        electrons.sort(key=lambda el: el.pt, reverse=True)

        # Choose tight-quality e/mu for event categorization
        good_muons = []
        for idx,mu in enumerate(muons):
            isoLep   = mu.pfRelIso04_all
            pass_ips = abs(mu.dxy) < 0.02 and abs(mu.dz) < 0.1
            pass_fid = abs(mu.eta) < 2.4 and mu.pt >= (25 if idx==0 else 20)
            pass_ids = mu.tightId and isoLep <= 0.15
            if pass_fid and pass_ids and pass_ips:
                good_muons.append(mu)
                
        good_electrons = []
        for idy,el in enumerate(electrons):
            id_CB = el.cutBased
            # changing to MVA based ID :
            if el.pt >= (25 if idy==0 else 20) and abs(el.eta) <= 2.5 and self.electron_id(el, "90"):
                good_electrons.append(el)

        # let sort the muons in pt
        good_muons.sort(key=lambda x: x.pt, reverse=True)
        good_electrons.sort(key=lambda x: x.pt, reverse=True)

        # Find any remaining e/mu that pass looser selection
        extra_leptons = []
        for mu in muons:
            isoLep   = mu.pfRelIso04_all
            pass_ids = mu.softId and isoLep <= 0.25
            pass_fid = abs(mu.eta) < 2.4 and mu.pt >= 7
            if tk.closest(mu, good_muons)[1] < 0.01:
                continue
            if pass_fid and pass_ids:
                extra_leptons.append(mu)

        for el in electrons:
            pass_fid = abs(el.eta) < 2.5 and el.pt >= 7
            if tk.closest(el, good_electrons)[1] < 0.01:
                continue
            if pass_fid and self.electron_id(el, "WPL"):
                extra_leptons.append(el)

        good_leptons = good_electrons + good_muons
        good_leptons.sort(key=lambda x: x.pt, reverse=True)
        extra_leptons.sort(key=lambda x: x.pt, reverse=True)

        ngood_leptons = len(good_leptons)
        nextra_leptons = len(extra_leptons)
        
        _leading_lep_flavor = 0
        if len(good_muons) and len(good_electrons): 
            if good_muons[0].pt > good_electrons[0].pt: _leading_lep_flavor = 1

        _leading_lep_pt = good_leptons[0].pt if ngood_leptons else 0.0
        _leading_lep_eta = good_leptons[0].eta if ngood_leptons else -99.
        _leading_lep_phi = good_leptons[0].phi if ngood_leptons else -99.
        _trailing_lep_pt = good_leptons[1].pt if ngood_leptons >= 2 else 0.0
        _trailing_lep_eta = good_leptons[1].eta if ngood_leptons >= 2 else -99.
        _trailing_lep_phi = good_leptons[1].phi if ngood_leptons >= 2 else -99.

        self.out.fillBranch("ngood_leptons{}".format(self.syst_suffix), ngood_leptons)
        self.out.fillBranch("nextra_leptons{}".format(self.syst_suffix), nextra_leptons)
        self.out.fillBranch("leading_lep_flavor{}".format(self.syst_suffix), _leading_lep_flavor)
        self.out.fillBranch("leading_lep_pt{}".format(self.syst_suffix), _leading_lep_pt)
        self.out.fillBranch("leading_lep_eta{}".format(self.syst_suffix), _leading_lep_eta)
        self.out.fillBranch("leading_lep_phi{}".format(self.syst_suffix), _leading_lep_phi)
        self.out.fillBranch("trailing_lep_pt{}".format(self.syst_suffix), _trailing_lep_pt)
        self.out.fillBranch("trailing_lep_eta{}".format(self.syst_suffix), _trailing_lep_eta)
        self.out.fillBranch("trailing_lep_phi{}".format(self.syst_suffix), _trailing_lep_phi)

        if False:
            print "number of leptons [all, good, extra]: ", ngood_leptons, " : ", nextra_leptons
            print "        CBId electrons : ", [e.cutBased for e in good_electrons]
            print "        WP90 electrons : ", [e.mvaFall17Iso_WP90 for e in good_electrons]
            print "             muons     : ", [e.tightId for e in good_muons]
            print "        lepton pts     : ", [e.pt for e in good_leptons]

        # Leptons efficiency/Trigger/Isolation Scale factors
        # These are applied only of the first 2 leading leptons
        if self.isMC:
            w_muon_SF     = w_electron_SF     = 1.0
            w_muon_SFUp   = w_electron_SFUp   = 1.0
            w_muon_SFDown = w_electron_SFDown = 1.0

            if ngood_leptons >= 2:
                if abs(good_leptons[0].pdgId) == 11:
                    w_electron_SF     *=  good_leptons[0].SF
                    w_electron_SFUp   *= (good_leptons[0].SF + good_leptons[0].SFErr)
                    w_electron_SFDown *= (good_leptons[0].SF - good_leptons[0].SFErr)
                if abs(good_leptons[0].pdgId) == 11:
                    w_electron_SF     *=  good_leptons[1].SF
                    w_electron_SFUp   *= (good_leptons[1].SF + good_leptons[1].SFErr)
                    w_electron_SFDown *= (good_leptons[1].SF - good_leptons[1].SFErr)
                if abs(good_leptons[0].pdgId) == 13:
                    w_muon_SF     *=  good_leptons[0].SF
                    w_muon_SFUp   *= (good_leptons[0].SF + good_leptons[0].SFErr)
                    w_muon_SFDown *= (good_leptons[0].SF - good_leptons[0].SFErr)
                if abs(good_leptons[1].pdgId) == 13:
                    w_muon_SF     *=  good_leptons[1].SF
                    w_muon_SFUp   *= (good_leptons[1].SF + good_leptons[1].SFErr)
                    w_muon_SFDown *= (good_leptons[1].SF - good_leptons[1].SFErr)

            self.out.fillBranch("w_muon_SF"        , w_muon_SF        )
            self.out.fillBranch("w_muon_SFUp"      , w_muon_SFUp      )
            self.out.fillBranch("w_muon_SFDown"    , w_muon_SFDown    )
            self.out.fillBranch("w_electron_SF"    , w_electron_SF    )
            self.out.fillBranch("w_electron_SFUp"  , w_electron_SFUp  )
            self.out.fillBranch("w_electron_SFDown", w_electron_SFDown)

        # process taus
        had_taus = []
        for tau in taus:
            if tk.closest(tau, good_leptons)[1] < 0.4:
                continue
            # only hadronic tau decay
            if tau.decayMode != 5:
                continue
            if tau.pt > 18 and abs(tau.eta) <= 2.3:
                had_taus.append(tau)
        _nhad_taus = len(had_taus)

        self.out.fillBranch("nhad_taus{}".format(self.syst_suffix), _nhad_taus)
        self.out.fillBranch("lead_tau_pt{}".format(self.syst_suffix), had_taus[0].pt if _nhad_taus else 0)

        ##############################
        ## process jet 
        ##############################

        z_candidate = []
        zcand_p4 = ROOT.TLorentzVector()
        emulated_met = ROOT.TLorentzVector()
        all_lepton_p4 = ROOT.TLorentzVector()
        rem_lepton_p4 = ROOT.TLorentzVector()

        good_jets  = []
        good_bjets = []
        for jet in jets:
            if jet.pt < 30.0 or abs(jet.eta) > 4.7:
                continue
            if not jet.jetId:
                continue
            if tk.closest(jet, good_leptons)[1] < 0.4:
                continue
            good_jets.append(jet)
            # Count b-tag with medium WP DeepJet
            # ref : https://twiki.cern.ch/twiki/bin/view/CMS/BtagRecommendation
            if abs(jet.eta) <= 2.4 and jet.btagDeepFlavB > self.btag_id("loose"):
                good_bjets.append(jet)

        _ngood_jets = len(good_jets)
        _ngood_bjets = len(good_bjets)
        good_jets.sort(key=lambda jet: jet.pt, reverse=True)
        good_bjets.sort(key=lambda jet: jet.pt, reverse=True)

        _lead_jet_pt = good_jets[0].pt if _ngood_jets >= 1 else 0.
        _lead_jet_eta = good_jets[0].eta if _ngood_jets >= 1 else -99.
        _lead_jet_phi = good_jets[0].phi if _ngood_jets >= 1 else -99.
        _lead_jet_mass = good_jets[0].mass if _ngood_jets >= 1 else -99.
        _trail_jet_pt = good_jets[1].pt if _ngood_jets >= 2 else 0.
        _trail_jet_eta = good_jets[1].eta if _ngood_jets >= 2 else -99.
        _trail_jet_phi = good_jets[1].phi if _ngood_jets >= 2 else -99.
        _trail_jet_mass = good_jets[1].mass if _ngood_jets >= 2 else -99.
        _third_jet_pt = good_jets[2].pt if _ngood_jets >= 3 else 0.
        _third_jet_eta = good_jets[2].eta if _ngood_jets >= 3 else -99.
        _third_jet_phi = good_jets[2].phi if _ngood_jets >= 3 else -99.
        _third_jet_mass = good_jets[2].mass if _ngood_jets >= 3 else -99.
        _H_T = sum([jet.pt for jet in good_jets])
        _dphi_j_met = tk.deltaPhi(good_jets[0], met.phi) if _ngood_jets >= 1 else -99.
        _lead_bjet_pt = good_bjets[0].pt if _ngood_bjets else 0.

        self.out.fillBranch("ngood_jets{}".format(self.syst_suffix), _ngood_jets)
        self.out.fillBranch("ngood_bjets{}".format(self.syst_suffix), _ngood_bjets)
        self.out.fillBranch("lead_jet_pt{}".format(self.syst_suffix), _lead_jet_pt)
        self.out.fillBranch("lead_jet_eta{}".format(self.syst_suffix), _lead_jet_eta)
        self.out.fillBranch("lead_jet_phi{}".format(self.syst_suffix), _lead_jet_phi)
        self.out.fillBranch("lead_jet_mass{}".format(self.syst_suffix), _lead_jet_mass)
        self.out.fillBranch("trail_jet_pt{}".format(self.syst_suffix), _trail_jet_pt)
        self.out.fillBranch("trail_jet_eta{}".format(self.syst_suffix), _trail_jet_eta)
        self.out.fillBranch("trail_jet_phi{}".format(self.syst_suffix), _trail_jet_phi)
        self.out.fillBranch("trail_jet_mass{}".format(self.syst_suffix), _trail_jet_mass)
        self.out.fillBranch("third_jet_pt{}".format(self.syst_suffix), _third_jet_pt)
        self.out.fillBranch("third_jet_eta{}".format(self.syst_suffix), _third_jet_eta)
        self.out.fillBranch("third_jet_phi{}".format(self.syst_suffix), _third_jet_phi)
        self.out.fillBranch("third_jet_mass{}".format(self.syst_suffix), _third_jet_mass)
        self.out.fillBranch("H_T{}".format(self.syst_suffix), _H_T)
        self.out.fillBranch("delta_phi_j_met{}".format(self.syst_suffix), _dphi_j_met)
        self.out.fillBranch("lead_bjet_pt{}".format(self.syst_suffix), _lead_bjet_pt)

        ##############################
        ## construct Z and category
        ##############################

        lep_category = 0
        if ngood_leptons < 2:
            lep_category = -1

        if ngood_leptons == 2 and nextra_leptons==0:
            # constructing the signal region
            if (good_leptons[0].pdgId * good_leptons[1].pdgId) == -11*11:
                lep_category = 1 # EE category
            if (good_leptons[0].pdgId * good_leptons[1].pdgId) == -11*13:
                lep_category = 2 # EM category
            if (good_leptons[0].pdgId * good_leptons[1].pdgId) == -13*13:
                lep_category = 3 # MM category
            z_candidate = [good_leptons[0], good_leptons[1]]
            zcand_p4 = good_leptons[0].p4() + good_leptons[1].p4()
            all_lepton_p4 = zcand_p4

        elif ngood_leptons == 3 and nextra_leptons==0:
            # constructing the 3 leptons CR
            for pair in itertools.combinations(good_leptons, 2):
                if pair[0].pdgId == -pair[1].pdgId:
                    zcand_ = pair[0].p4() + pair[1].p4()
                    if abs(zcand_.M()-self.zmass) < abs(zcand_p4.M()-self.zmass):
                        zcand_p4 = zcand_
                        z_candidate = list(pair)
                        lep3_idx_ = 3 - good_leptons.index(pair[0]) - good_leptons.index(pair[1])
                        emulated_met = good_leptons[lep3_idx_].p4() + met_p4
                        all_lepton_p4 = zcand_ + good_leptons[lep3_idx_].p4()
                        rem_lepton_p4 = good_leptons[lep3_idx_].p4()
                        if abs(pair[0].pdgId) == 11:
                            lep_category = 4 # EEL category
                        if abs(pair[0].pdgId) == 13:
                            lep_category = 5 # MML category

        elif ngood_leptons>=2 and (ngood_leptons + nextra_leptons) == 4:
            # constructing the 4 leptons CR
            for pair in itertools.combinations(good_leptons, 2):
                # checking if OSSF pair
                rem_pair = [x for x in good_leptons + extra_leptons if x not in pair]
                if (pair[0].pdgId == -pair[1].pdgId) and (rem_pair[0].pdgId == -rem_pair[1].pdgId):
                    zcand_0 = pair[0].p4() + pair[1].p4()
                    zcand_1 = rem_pair[0].p4() + rem_pair[1].p4()
                    if abs(zcand_0.M()-self.zmass) < abs(zcand_p4.M()-self.zmass):
                        zcand_p4 = zcand_0
                        z_candidate = pair
                        emulated_met =  zcand_1 + met_p4
                        all_lepton_p4 = zcand_p4 + zcand_1
                        rem_lepton_p4 = zcand_1
                        if abs(pair[0].pdgId) == 11:
                            lep_category = 6 # EELL category
                        if abs(pair[0].pdgId) == 13:
                            lep_category = 7 # MMLL category

        else:
            # too many bad leptons, with no obvious meaning ?
            if ngood_leptons==1 and (ngood_leptons + nextra_leptons)>=1:
                lep_category = -2
            elif ngood_leptons>=2 and (ngood_leptons + nextra_leptons)>=2:
                lep_category = -3
            else:
                lep_category = -4

        # filling MonoZ type of variables
        self.out.fillBranch("lep_category{}".format(self.syst_suffix), lep_category)
        self.out.fillBranch("Z_pt{}".format(self.syst_suffix), zcand_p4.Pt())
        self.out.fillBranch("Z_eta{}".format(self.syst_suffix), zcand_p4.Eta())
        self.out.fillBranch("Z_phi{}".format(self.syst_suffix), zcand_p4.Phi())
        self.out.fillBranch("Z_mass{}".format(self.syst_suffix), zcand_p4.M())
        self.out.fillBranch("Z_mt{}".format(self.syst_suffix), zcand_p4.Mt())
        
        ##############################
        ## high level info
        ##############################

        _delta_zphi = tk.deltaPhi(z_candidate[0].phi, z_candidate[1].phi) if lep_category > 0 else -99
        _delta_zdR  = tk.deltaR(z_candidate[0].eta, z_candidate[0].phi,
                                z_candidate[1].eta, z_candidate[1].phi,) if lep_category > 0 else -99
        _delta_zeta     = abs(z_candidate[0].eta - z_candidate[1].eta) if lep_category > 0 else -99
        _delta_phi_zmet = tk.deltaPhi(zcand_p4.Phi(), met.phi)
        _vec_delta_balance  = (met_p4 - zcand_p4).Pt()/zcand_p4.Pt() if zcand_p4.Pt() != 0 else -1
        _sca_delta_balance  = met.pt/zcand_p4.Pt() if zcand_p4.Pt() != 0 else -1

        # hadronic recoil
        had_recoil_p4 = ROOT.TLorentzVector()
        had_recoil_p4 += met_p4
        for lep in good_leptons + extra_leptons:
            had_recoil_p4 += lep.p4()
        had_recoil_p4 = -had_recoil_p4
        _delta_met_rec = tk.deltaPhi(met.phi, had_recoil_p4.Phi()) if lep_category > 0 else -99

        _MT = np.sqrt(2 * zcand_p4.Pt() * var_met_pt * (1 - np.cos(_delta_phi_zmet)))
        # defined as from https://arxiv.org/pdf/1808.09054.pdf
        _Ell = np.sqrt(zcand_p4.Mag2() + zcand_p4.M2())
        _altMT = np.sqrt(np.power(_Ell + met_p4.Pt(),2) + (met_p4 + zcand_p4).Mag2())
        # checking the transverse mass
        _rem_p4 = ROOT.TLorentzVector()
        _rem_p4.SetPtEtaPhiM(rem_lepton_p4.Pt(), 0, rem_lepton_p4.Phi(), 0)

        self.out.fillBranch("delta_phi_ll{}".format(self.syst_suffix), _delta_zphi)
        self.out.fillBranch("delta_eta_ll{}".format(self.syst_suffix), _delta_zeta)
        self.out.fillBranch("delta_R_ll{}".format(self.syst_suffix), _delta_zdR)
        self.out.fillBranch("delta_phi_ZMet{}".format(self.syst_suffix), _delta_phi_zmet)
        self.out.fillBranch("vec_balance{}".format(self.syst_suffix), _vec_delta_balance)
        self.out.fillBranch("sca_balance{}".format(self.syst_suffix), _sca_delta_balance)
        self.out.fillBranch("hadronic_recoil{}".format(self.syst_suffix), had_recoil_p4.Pt())
        self.out.fillBranch("delta_met_rec{}".format(self.syst_suffix), _delta_met_rec)
        self.out.fillBranch("emulatedMET{}".format(self.syst_suffix), emulated_met.Pt())
        self.out.fillBranch("emulatedMET_phi{}".format(self.syst_suffix), emulated_met.Phi())
        self.out.fillBranch("mass_alllep{}".format(self.syst_suffix), all_lepton_p4.M())
        self.out.fillBranch("pt_alllep{}".format(self.syst_suffix), all_lepton_p4.Pt())
        self.out.fillBranch("remll_mass{}".format(self.syst_suffix), rem_lepton_p4.M())
        self.out.fillBranch("MT{}".format(self.syst_suffix), _MT)
        self.out.fillBranch("altMT{}".format(self.syst_suffix), _altMT)
        self.out.fillBranch("trans_mass{}".format(self.syst_suffix), (_rem_p4 + met_p4).M())

        # Let remove the negative categories with no obvious meaning meaning
        # This will reduce the size of most of the bacground and data
        if (lep_category > 0 and zcand_p4.Pt()>60 and zcand_p4.M() > 55 and zcand_p4.M() < 127):
            return True
        else:
            return False
Exemple #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
    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