예제 #1
0
class TauEnergyScale:
    
    def __init__(self, year, algorithm):
        self.testool = TauESTool(YEARLIB[year], ALGOLIB[algorithm])
        self.tfestool = TauESTool(YEARLIB[year])

    #tlv is four vector to correct
    def applyES(self, tlv, dm, genmatch):
        if genmatch == 1 or genmatch == 3:
            if dm == 0 or dm == 1:
                tlv *= self.tfestool.getFES(tlv.Eta(), dm, genmatch)
            else:
                pass
        else:
            tlv *= self.tfestool.getTES(tlv.Pt(), dm, genmatch)
        return tlv

    #tlv is four vector to correct
    def readES(self, tlv, dm, genmatch):
        if genmatch == 1 or genmatch == 3:
            if dm == 0 or dm == 1:
                return self.tfestool.getFES(tlv.Eta(), dm, genmatch)
            else:
                return 1.
        else:
            return self.tfestool.getTES(tlv.Pt(), dm, genmatch)
예제 #2
0
def printTESTable(year):
  testool = TauESTool(year)
  dmvals  = [0,1,5,6,10,11]
  print ">>> "
  print ">>> TES for '%s'"%(year)
  print ">>> "
  print ">>> %10s"%('var \ DM')+''.join("%9d"%dm for dm in dmvals)
  print ">>> %10s"%("central") +''.join("%9.5f"%testool.getTES(dm,5)        for dm in dmvals)
  print ">>> %10s"%("up")      +''.join("%9.5f"%testool.getTES(dm,5,'Up')   for dm in dmvals)
  print ">>> %10s"%("down")    +''.join("%9.5f"%testool.getTES(dm,5,'Down') for dm in dmvals)
  print ">>> "
예제 #3
0
def printTESTable(year,id):
  testool = TauESTool(year,id)
  ptvals  = [25,102,175] #[25,30,102,170,175]
  dmvals  = [0,1,5,10,11]
  for pt in ptvals:
    print(">>> ")
    print(">>> TES for '%s' ('%s') and pT = %s GeV"%(green(id),year,pt))
    print(">>> ")
    print(">>> %10s"%('var \ DM')+''.join("%9d"%dm for dm in dmvals))
    print(">>> %10s"%("central") +''.join("%9.5f"%testool.getTES(pt,dm,5)        for dm in dmvals))
    print(">>> %10s"%("up")      +''.join("%9.5f"%testool.getTES(pt,dm,5,'Up')   for dm in dmvals))
    print(">>> %10s"%("down")    +''.join("%9.5f"%testool.getTES(pt,dm,5,'Down') for dm in dmvals))
    print(">>> ")
예제 #4
0
class TauEnergyScale:
    def __init__(self, year, algorithm):
        self.testool = TauESTool(YEARLIB[year], algorithm)
        self.tfestool = TauESTool(YEARLIB[year])

    def applyES(tlv, dm, genmatch):
        if genmatch == 1 or genmatch == 3:
            tlv *= self.tfestool.getFES(tlv.Eta(), dm, genmatch)
        else:
            tlv *= self.tfestool.getTES(tlv.Pt(), dm, genmatch)
        return tlv
예제 #5
0
class ModuleETau(ModuleTauPair):
    def __init__(self, fname, **kwargs):
        kwargs['channel'] = 'etau'
        super(ModuleETau, self).__init__(fname, **kwargs)
        self.out = TreeProducerETau(fname, self)

        # TRIGGERS
        jsonfile = os.path.join(datadir,
                                "trigger/tau_triggers_%d.json" % (self.year))
        self.trigger = TrigObjMatcher(jsonfile,
                                      trigger='SingleElectron',
                                      isdata=self.isdata)
        self.eleCutPt = self.trigger.ptmins[0]
        self.tauCutPt = 20
        self.eleCutEta = 2.3
        self.tauCutEta = 2.3

        # CORRECTIONS
        if self.ismc:
            self.eleSFs = ElectronSFs(
                era=self.era)  # electron id/iso/trigger SFs
            self.tesTool = TauESTool(
                tauSFVersion[self.year])  # real tau energy scale corrections
            self.fesTool = TauFESTool(
                tauSFVersion[self.year])  # e -> tau fake energy scale
            self.tauSFs = TauIDSFTool(tauSFVersion[self.year],
                                      'DeepTau2017v2p1VSjet', 'Tight')
            self.etfSFs = TauIDSFTool(tauSFVersion[self.year],
                                      'DeepTau2017v2p1VSe', 'VLoose')
            self.mtfSFs = TauIDSFTool(tauSFVersion[self.year],
                                      'DeepTau2017v2p1VSmu', 'Tight')

        # CUTFLOW
        self.out.cutflow.addcut('none', "no cut")
        self.out.cutflow.addcut('trig', "trigger")
        self.out.cutflow.addcut('electron', "electron")
        self.out.cutflow.addcut('tau', "tau")
        self.out.cutflow.addcut('pair', "pair")
        self.out.cutflow.addcut('weight', "no cut, weighted", 15)
        self.out.cutflow.addcut('weight_no0PU', "no cut, weighted, PU>0",
                                16)  # use for normalization

    def beginJob(self):
        """Before processing any events or files."""
        super(ModuleETau, self).beginJob()
        print ">>> %-12s = %s" % ('tauwp', self.tauwp)
        print ">>> %-12s = %s" % ('eleCutPt', self.eleCutPt)
        print ">>> %-12s = %s" % ('eleCutEta', self.eleCutEta)
        print ">>> %-12s = %s" % ('tauCutPt', self.tauCutPt)
        print ">>> %-12s = %s" % ('tauCutEta', self.tauCutEta)
        pass

    def analyze(self, event):
        """Process and pre-select events; fill branches and return True if the events passes,
    return False otherwise."""
        sys.stdout.flush()

        ##### NO CUT #####################################
        self.out.cutflow.fill('none')
        if self.isdata:
            self.out.cutflow.fill('weight', 1.)
            if event.PV_npvs > 0:
                self.out.cutflow.fill('weight_no0PU', 1.)
            else:
                return False
        else:
            self.out.cutflow.fill('weight', event.genWeight)
            self.out.pileup.Fill(event.Pileup_nTrueInt)
            if event.Pileup_nTrueInt > 0:
                self.out.cutflow.fill('weight_no0PU', event.genWeight)
            else:
                return False

        ##### TRIGGER ####################################
        if not self.trigger.fired(event):
            return False
        self.out.cutflow.fill('trig')

        ##### ELECTRON ###################################
        electrons = []
        for electron in Collection(event, 'Electron'):
            #if self.ismc and self.ees!=1:
            #  electron.pt   *= self.ees
            #  electron.mass *= self.ees
            if electron.pt < self.eleCutPt: continue
            if abs(electron.eta) > self.eleCutEta: continue
            if abs(electron.dz) > 0.2: continue
            if abs(electron.dxy) > 0.045: continue
            if not electron.convVeto: continue
            if electron.lostHits > 1: continue
            if not (electron.mvaFall17V2Iso_WP90
                    or electron.mvaFall17V2noIso_WP90):
                continue
            if not self.trigger.match(event, electron): continue
            electrons.append(electron)
        if len(electrons) == 0:
            return False
        self.out.cutflow.fill('electron')

        ##### TAU ########################################
        taus = []
        for tau in Collection(event, 'Tau'):
            if abs(tau.eta) > self.tauCutEta: continue
            if abs(tau.dz) > 0.2: continue
            if tau.decayMode not in [0, 1, 10, 11]: continue
            if abs(tau.charge) != 1: continue
            if tau.idDeepTau2017v2p1VSe < 1: continue  # VVVLoose
            if tau.idDeepTau2017v2p1VSmu < 1: continue  # VLoose
            if tau.idDeepTau2017v2p1VSjet < self.tauwp: continue
            if self.ismc:
                tau.es = 1  # store energy scale for propagating to MET
                genmatch = tau.genPartFlav
                if genmatch == 5:  # real tau
                    if self.tes != None:  # user-defined energy scale (for TES studies)
                        tes = self.tes
                    else:  # recommended energy scale (apply by default)
                        tes = self.tesTool.getTES(tau.pt,
                                                  tau.decayMode,
                                                  unc=self.tessys)
                    if tes != 1:
                        tau.pt *= tes
                        tau.mass *= tes
                        tau.es = tes
                elif self.ltf and 0 < genmatch < 5:  # lepton -> tau fake
                    tau.pt *= self.ltf
                    tau.mass *= self.ltf
                    tau.es = self.ltf
                elif genmatch in [
                        1, 3
                ]:  # electron -> tau fake (apply by default, override with 'ltf=1.0')
                    fes = self.fesTool.getFES(tau.eta,
                                              tau.decayMode,
                                              unc=self.fes)
                    tau.pt *= fes
                    tau.mass *= fes
                    tau.es = fes
                elif self.jtf != 1.0 and genmatch == 0:  # jet -> tau fake
                    tau.pt *= self.jtf
                    tau.mass *= self.jtf
                    tau.es = self.jtf
            if tau.pt < self.tauCutPt: continue
            taus.append(tau)
        if len(taus) == 0:
            return False
        self.out.cutflow.fill('tau')

        ##### ETAU PAIR ##################################
        ltaus = []
        for electron in electrons:
            for tau in taus:
                if tau.DeltaR(electron) < 0.5: continue
                ltau = LeptonTauPair(electron, electron.pfRelIso03_all, tau,
                                     tau.rawDeepTau2017v2p1VSjet)
                ltaus.append(ltau)

        if len(ltaus) == 0:
            return False
        electron, tau = max(ltaus).pair
        electron.tlv = electron.p4()
        tau.tlv = tau.p4()
        self.out.cutflow.fill('pair')

        # VETOS
        extramuon_veto, extraelec_veto, dilepton_veto = getlepvetoes(
            event, [electron], [], [tau], self.channel)
        self.out.extramuon_veto[0], self.out.extraelec_veto[
            0], self.out.dilepton_veto[0] = getlepvetoes(
                event, [electron], [], [], self.channel)
        self.out.lepton_vetoes[0] = self.out.extramuon_veto[
            0] or self.out.extraelec_veto[0] or self.out.dilepton_veto[0]
        self.out.lepton_vetoes_notau[
            0] = extramuon_veto or extraelec_veto or dilepton_veto

        # TIGHTEN PRE-SELECTION
        if self.dotight:  # do not save all events to reduce disk space
            fail = (self.out.lepton_vetoes[0] and self.out.lepton_vetoes_notau[0]) or\
                   (tau.idMVAoldDM2017v2<2 and tau.idDeepTau2017v2p1VSjet<1) or\
                   (tau.idAntiMu<2  and tau.idDeepTau2017v2p1VSmu<1) or\
                   (tau.idAntiEle<2 and tau.idDeepTau2017v2p1VSe<2)
            if (self.tes not in [1, None]
                    or self.tessys != None) and (fail or tau.genPartFlav != 5):
                return False
            if (self.ltf != 1 or self.fes != None
                ) and tau.genPartFlav < 1 and tau.genPartFlav > 4:
                return False
            ###if self.jtf!=1 and tau.genPartFlav!=0:
            ###  return False

        # EVENT
        self.fillEventBranches(event)

        # ELECTRON
        self.out.pt_1[0] = electron.pt
        self.out.eta_1[0] = electron.eta
        self.out.phi_1[0] = electron.phi
        self.out.m_1[0] = electron.mass
        self.out.y_1[0] = electron.tlv.Rapidity()
        self.out.dxy_1[0] = electron.dxy
        self.out.dz_1[0] = electron.dz
        self.out.q_1[0] = electron.charge
        self.out.iso_1[0] = electron.pfRelIso03_all
        self.out.cutBased_1[0] = electron.cutBased
        self.out.mvaFall17Iso_WP90_1[0] = electron.mvaFall17V2Iso_WP90
        self.out.mvaFall17Iso_WP80_1[0] = electron.mvaFall17V2Iso_WP80
        self.out.mvaFall17noIso_WP90_1[0] = electron.mvaFall17V2noIso_WP90
        self.out.mvaFall17noIso_WP80_1[0] = electron.mvaFall17V2noIso_WP80

        # TAU
        self.out.pt_2[0] = tau.pt
        self.out.eta_2[0] = tau.eta
        self.out.phi_2[0] = tau.phi
        self.out.m_2[0] = tau.mass
        self.out.y_2[0] = tau.tlv.Rapidity()
        self.out.dxy_2[0] = tau.dxy
        self.out.dz_2[0] = tau.dz
        self.out.q_2[0] = tau.charge
        self.out.dm_2[0] = tau.decayMode
        self.out.iso_2[0] = tau.rawIso
        self.out.idiso_2[0] = idIso(tau)  # cut-based tau isolation (rawIso)
        self.out.rawAntiEle_2[0] = tau.rawAntiEle
        self.out.rawMVAoldDM2017v2_2[0] = tau.rawMVAoldDM2017v2
        self.out.rawMVAnewDM2017v2_2[0] = tau.rawMVAnewDM2017v2
        self.out.rawDeepTau2017v2p1VSe_2[0] = tau.rawDeepTau2017v2p1VSe
        self.out.rawDeepTau2017v2p1VSmu_2[0] = tau.rawDeepTau2017v2p1VSmu
        self.out.rawDeepTau2017v2p1VSjet_2[0] = tau.rawDeepTau2017v2p1VSjet
        self.out.idAntiEle_2[0] = tau.idAntiEle
        self.out.idAntiMu_2[0] = tau.idAntiMu
        self.out.idDecayMode_2[0] = tau.idDecayMode
        self.out.idDecayModeNewDMs_2[0] = tau.idDecayModeNewDMs
        self.out.idMVAoldDM2017v2_2[0] = tau.idMVAoldDM2017v2
        self.out.idMVAnewDM2017v2_2[0] = tau.idMVAnewDM2017v2
        self.out.idDeepTau2017v2p1VSe_2[0] = tau.idDeepTau2017v2p1VSe
        self.out.idDeepTau2017v2p1VSmu_2[0] = tau.idDeepTau2017v2p1VSmu
        self.out.idDeepTau2017v2p1VSjet_2[0] = tau.idDeepTau2017v2p1VSjet
        self.out.chargedIso_2[0] = tau.chargedIso
        self.out.neutralIso_2[0] = tau.neutralIso
        self.out.leadTkPtOverTauPt_2[0] = tau.leadTkPtOverTauPt
        self.out.photonsOutsideSignalCone_2[0] = tau.photonsOutsideSignalCone
        self.out.puCorr_2[0] = tau.puCorr

        # GENERATOR
        if self.ismc:
            self.out.genmatch_1[0] = electron.genPartFlav
            self.out.genmatch_2[0] = tau.genPartFlav
            dRmin = 0.5
            taumatch = None
            for genvistau in Collection(event, 'GenVisTau'):
                dR = genvistau.DeltaR(tau)
                if dR < dRmin:
                    dRmin = dR
                    taumatch = genvistau
            if taumatch:
                self.out.genvistaupt_2[0] = taumatch.pt
                self.out.genvistaueta_2[0] = taumatch.eta
                self.out.genvistauphi_2[0] = taumatch.phi
                self.out.gendm_2[0] = taumatch.status
            else:
                self.out.genvistaupt_2[0] = -1
                self.out.genvistaueta_2[0] = -9
                self.out.genvistauphi_2[0] = -9
                self.out.gendm_2[0] = -1

        # JETS
        jets, met, njets_vars, met_vars = self.fillJetBranches(
            event, electron, tau)
        if self.ismc:
            self.out.jpt_match_2[0], self.out.jpt_genmatch_2[0] = matchtaujet(
                event, tau, self.ismc)
        else:
            self.out.jpt_match_2[0] = matchtaujet(event, tau, self.ismc)[0]

        # WEIGHTS
        if self.ismc:
            self.fillCommonCorrBraches(event, jets, met, njets_vars, met_vars)
            if electron.pfRelIso03_all < 0.50 and tau.idDeepTau2017v2p1VSjet >= 2:
                self.btagTool.fillEffMaps(jets, usejec=self.dojec)

            # MUON WEIGHTS
            self.out.trigweight[0] = self.eleSFs.getTriggerSF(
                electron.pt, electron.eta)
            self.out.idisoweight_1[0] = self.eleSFs.getIdIsoSF(
                electron.pt, electron.eta)

            # TAU WEIGHTS
            if tau.genPartFlav == 5:  # real tau
                self.out.idweight_2[0] = self.tauSFs.getSFvsPT(tau.pt)
                if not self.dotight:
                    self.out.idweightUp_2[0] = self.tauSFs.getSFvsPT(tau.pt,
                                                                     unc='Up')
                    self.out.idweightDown_2[0] = self.tauSFs.getSFvsPT(
                        tau.pt, unc='Down')
            elif tau.genPartFlav in [1, 3]:  # muon -> tau fake
                self.out.ltfweight_2[0] = self.etfSFs.getSFvsEta(
                    tau.eta, tau.genPartFlav)
                if not self.dotight:
                    self.out.ltfweightUp_2[0] = self.etfSFs.getSFvsEta(
                        tau.eta, tau.genPartFlav, unc='Up')
                    self.out.ltfweightDown_2[0] = self.etfSFs.getSFvsEta(
                        tau.eta, tau.genPartFlav, unc='Down')
            elif tau.genPartFlav in [2, 4]:  # electron -> tau fake
                self.out.ltfweight_2[0] = self.mtfSFs.getSFvsEta(
                    tau.eta, tau.genPartFlav)
                if not self.dotight:
                    self.out.ltfweightUp_2[0] = self.mtfSFs.getSFvsEta(
                        tau.eta, tau.genPartFlav, unc='Up')
                    self.out.ltfweightDown_2[0] = self.mtfSFs.getSFvsEta(
                        tau.eta, tau.genPartFlav, unc='Down')
            self.out.weight[0] = self.out.genweight[0] * self.out.puweight[
                0] * self.out.trigweight[0] * self.out.idisoweight_1[
                    0]  #*self.out.idisoweight_2[0]
        elif self.isembed:
            ###self.applyCommonEmbdedCorrections(event,jets,jetIds50,met,njets_vars,met_vars)
            self.out.genweight[0] = event.genWeight
            self.out.trackweight[
                0] = 0.975 if tau.decayMode == 0 else 1.0247 if tau.decayMode == 1 else 0.927 if tau.decayMode == 10 else 0.974 if tau.decayMode == 11 else 1.0

        # MET & DILEPTON VARIABLES
        self.fillMETAndDiLeptonBranches(event, electron, tau, met, met_vars)

        self.out.fill()
        return True
예제 #6
0
class ModuleMuTau(ModuleTauPair):
  
  def __init__(self, fname, **kwargs):
    kwargs['channel'] = 'mutau'
    super(ModuleMuTau,self).__init__(fname,**kwargs)
    self.out = TreeProducerMuTau(fname,self)
    
    # TRIGGERS
    if self.year==2016:
      self.trigger    = lambda e: e.HLT_IsoMu22 or e.HLT_IsoMu22_eta2p1 or e.HLT_IsoTkMu22 or e.HLT_IsoTkMu22_eta2p1 #or e.HLT_IsoMu19_eta2p1_LooseIsoPFTau20_SingleL1
      self.muonCutPt  = lambda e: 23
      self.muonCutEta = lambda e: 2.4 if e.HLT_IsoMu22 or e.HLT_IsoTkMu22 else 2.1
    elif self.year==2017:
      self.trigger    = lambda e: e.HLT_IsoMu24 or e.HLT_IsoMu27 #or e.HLT_IsoMu20_eta2p1_LooseChargedIsoPFTau27_eta2p1_CrossL1
      self.muonCutPt  = lambda e: 25 if e.HLT_IsoMu24 else 28
      self.muonCutEta = lambda e: 2.4
    else:
      self.trigger    = lambda e: e.HLT_IsoMu24 or e.HLT_IsoMu27 #or e.HLT_IsoMu20_eta2p1_LooseChargedIsoPFTau27_eta2p1_CrossL1
      self.muonCutPt  = lambda e: 25
      self.muonCutEta = lambda e: 2.4
    self.tauCutPt     = 20
    self.tauCutEta    = 2.3
    
    # CORRECTIONS
    if self.ismc:
      self.muSFs      = MuonSFs(era=self.era,verb=self.verbosity) # muon id/iso/trigger SFs
      self.tesTool    = TauESTool(tauSFVersion[self.year]) # real tau energy scale corrections
      #self.fesTool    = TauFESTool(tauSFVersion[self.year]) # e -> tau fake negligible
      self.tauSFsT    = TauIDSFTool(tauSFVersion[self.year],'DeepTau2017v2p1VSjet','Tight')
      self.tauSFsM    = TauIDSFTool(tauSFVersion[self.year],'DeepTau2017v2p1VSjet','Medium')
      self.tauSFsT_dm = TauIDSFTool(tauSFVersion[self.year],'DeepTau2017v2p1VSjet','Tight', dm=True)
      self.etfSFs     = TauIDSFTool(tauSFVersion[self.year],'DeepTau2017v2p1VSe',  'VLoose')
      self.mtfSFs     = TauIDSFTool(tauSFVersion[self.year],'DeepTau2017v2p1VSmu', 'Tight')
    
    # CUTFLOW
    self.out.cutflow.addcut('none',         "no cut"                     )
    self.out.cutflow.addcut('trig',         "trigger"                    )
    self.out.cutflow.addcut('muon',         "muon"                       )
    self.out.cutflow.addcut('tau',          "tau"                        )
    self.out.cutflow.addcut('pair',         "pair"                       )
    self.out.cutflow.addcut('weight',       "no cut, weighted", 15       )
    self.out.cutflow.addcut('weight_no0PU', "no cut, weighted, PU>0", 16 ) # use for normalization
    
  
  def beginJob(self):
    """Before processing any events or files."""
    super(ModuleMuTau,self).beginJob()
    print ">>> %-12s = %s"%('tauwp',      self.tauwp)
    print ">>> %-12s = %s"%('muonCutPt',  self.muonCutPt)
    print ">>> %-12s = %s"%('muonCutEta', self.muonCutEta)
    print ">>> %-12s = %s"%('tauCutPt',   self.tauCutPt)
    print ">>> %-12s = %s"%('tauCutEta',  self.tauCutEta)
    pass
    
  
  def analyze(self, event):
    """Process and pre-select events; fill branches and return True if the events passes,
    return False otherwise."""
    sys.stdout.flush()
    
    
    ##### NO CUT #####################################
    self.out.cutflow.fill('none')
    if self.isdata:
      self.out.cutflow.fill('weight',1.)
      if event.PV_npvs>0:
        self.out.cutflow.fill('weight_no0PU',1.)
      else:
        return False
    else:
      self.out.cutflow.fill('weight',event.genWeight)
      self.out.pileup.Fill(event.Pileup_nTrueInt)
      if event.Pileup_nTrueInt>0:
        self.out.cutflow.fill('weight_no0PU',event.genWeight)
      else:
        return False
    
    
    ##### TRIGGER ####################################
    if not self.trigger(event):
      return False
    self.out.cutflow.fill('trig')
    
    
    ##### MUON #######################################
    muons = [ ]
    for muon in Collection(event,'Muon'):
      if muon.pt<self.muonCutPt(event): continue
      if abs(muon.eta)>self.muonCutEta(event): continue
      if abs(muon.dz)>0.2: continue
      if abs(muon.dxy)>0.045: continue
      if not muon.mediumId: continue
      if muon.pfRelIso04_all>0.50: continue
      muons.append(muon)
    if len(muons)==0:
      return False
    self.out.cutflow.fill('muon')
    
    
    ##### TAU ########################################
    taus = [ ]
    for tau in Collection(event,'Tau'):
      if abs(tau.eta)>self.tauCutEta: continue
      if abs(tau.dz)>0.2: continue
      if tau.decayMode not in [0,1,10,11]: continue
      if abs(tau.charge)!=1: continue
      if tau.idDeepTau2017v2p1VSe<1: continue # VVVLoose
      if tau.idDeepTau2017v2p1VSmu<1: continue # VLoose
      if tau.idDeepTau2017v2p1VSjet<self.tauwp: continue
      if self.ismc:
        tau.es   = 1 # store energy scale for propagating to MET
        genmatch = tau.genPartFlav
        if genmatch==5: # real tau
          if self.tes!=None: # user-defined energy scale (for TES studies)
            tes = self.tes
          else: # recommended energy scale (apply by default)
            tes = self.tesTool.getTES(tau.pt,tau.decayMode,unc=self.tessys)
          if tes!=1:
            tau.pt   *= tes
            tau.mass *= tes
            tau.es    = tes # store for later reuse
        elif self.ltf and 0<genmatch<5: # lepton -> tau fake
          tau.pt   *= self.ltf
          tau.mass *= self.ltf
          tau.es    = self.ltf # store for later reuse
        #elif genmatch in [1,3]: # electron -> tau fake (apply by default, override with 'ltf=1.0')
        #  fes = self.fesTool.getFES(tau.eta,tau.decayMode,unc=self.fes)
        #  tau.pt   *= fes
        #  tau.mass *= fes
        #  tau.es    = fes
        elif self.jtf!=1.0 and genmatch==0: # jet -> tau fake
          tau.pt   *= self.jtf
          tau.mass *= self.jtf
          tau.es    = self.jtf
      if tau.pt<self.tauCutPt: continue
      taus.append(tau)
    if len(taus)==0:
      return False
    self.out.cutflow.fill('tau')
    
    
    ##### MUTAU PAIR #################################
    ltaus = [ ]
    for muon in muons:
      for tau in taus:
        if tau.DeltaR(muon)<0.5: continue
        ltau = LeptonTauPair(muon,muon.pfRelIso04_all,tau,tau.rawDeepTau2017v2p1VSjet)
        ltaus.append(ltau)
    if len(ltaus)==0:
      return False
    muon, tau = max(ltaus).pair
    muon.tlv  = muon.p4()
    tau.tlv   = tau.p4()
    genmatch  = -1 if self.isdata else tau.genPartFlav
    self.out.cutflow.fill('pair')
    
    
    # VETOES
    extramuon_veto, extraelec_veto, dilepton_veto = getlepvetoes(event,[ ],[muon],[tau],self.channel)
    self.out.extramuon_veto[0], self.out.extraelec_veto[0], self.out.dilepton_veto[0] = getlepvetoes(event,[ ],[muon],[ ],self.channel)
    self.out.lepton_vetoes[0]       = self.out.extramuon_veto[0] or self.out.extraelec_veto[0] or self.out.dilepton_veto[0]
    self.out.lepton_vetoes_notau[0] = extramuon_veto or extraelec_veto or dilepton_veto
    
    # TIGHTEN PRE-SELECTION
    if self.dotight: # do not save all events to reduce disk space
      fail = (self.out.lepton_vetoes[0] and self.out.lepton_vetoes_notau[0]) or\
             (tau.idMVAoldDM2017v2<1 and tau.idDeepTau2017v2p1VSjet<1) or\
             (tau.idAntiMu<2  and tau.idDeepTau2017v2p1VSmu<2) or\
             (tau.idAntiEle<2 and tau.idDeepTau2017v2p1VSe<1)
      if (self.tes not in [1,None] or self.tessys!=None) and (fail or tau.genPartFlav!=5):
        return False
      if (self.ltf!=1 or self.fes!=None) and tau.genPartFlav<1 and tau.genPartFlav>4:
        return False
      ###if self.jtf!=1 and tau.genPartFlav!=0:
      ###  return False
    
    # EVENT
    self.fillEventBranches(event)
    
    
    # MUON
    self.out.pt_1[0]                       = muon.pt
    self.out.eta_1[0]                      = muon.eta
    self.out.phi_1[0]                      = muon.phi
    self.out.m_1[0]                        = muon.mass
    self.out.y_1[0]                        = muon.tlv.Rapidity()
    self.out.dxy_1[0]                      = muon.dxy
    self.out.dz_1[0]                       = muon.dz
    self.out.q_1[0]                        = muon.charge
    self.out.iso_1[0]                      = muon.pfRelIso04_all
    
    
    # TAU
    self.out.pt_2[0]                       = tau.pt
    self.out.eta_2[0]                      = tau.eta
    self.out.phi_2[0]                      = tau.phi
    self.out.m_2[0]                        = tau.mass
    self.out.y_2[0]                        = tau.tlv.Rapidity()
    self.out.dxy_2[0]                      = tau.dxy
    self.out.dz_2[0]                       = tau.dz
    self.out.q_2[0]                        = tau.charge
    self.out.dm_2[0]                       = tau.decayMode
    self.out.iso_2[0]                      = tau.rawIso
    self.out.idiso_2[0]                    = idIso(tau) # cut-based tau isolation (rawIso)
    self.out.rawAntiEle_2[0]               = tau.rawAntiEle
    self.out.rawMVAoldDM2017v2_2[0]        = tau.rawMVAoldDM2017v2
    self.out.rawMVAnewDM2017v2_2[0]        = tau.rawMVAnewDM2017v2
    self.out.rawDeepTau2017v2p1VSe_2[0]    = tau.rawDeepTau2017v2p1VSe
    self.out.rawDeepTau2017v2p1VSmu_2[0]   = tau.rawDeepTau2017v2p1VSmu
    self.out.rawDeepTau2017v2p1VSjet_2[0]  = tau.rawDeepTau2017v2p1VSjet
    self.out.idAntiEle_2[0]                = tau.idAntiEle
    self.out.idAntiMu_2[0]                 = tau.idAntiMu
    self.out.idDecayMode_2[0]              = tau.idDecayMode
    self.out.idDecayModeNewDMs_2[0]        = tau.idDecayModeNewDMs
    self.out.idMVAoldDM2017v2_2[0]         = tau.idMVAoldDM2017v2
    self.out.idMVAnewDM2017v2_2[0]         = tau.idMVAnewDM2017v2
    self.out.idDeepTau2017v2p1VSe_2[0]     = tau.idDeepTau2017v2p1VSe
    self.out.idDeepTau2017v2p1VSmu_2[0]    = tau.idDeepTau2017v2p1VSmu
    self.out.idDeepTau2017v2p1VSjet_2[0]   = tau.idDeepTau2017v2p1VSjet
    self.out.chargedIso_2[0]               = tau.chargedIso
    self.out.neutralIso_2[0]               = tau.neutralIso
    self.out.leadTkPtOverTauPt_2[0]        = tau.leadTkPtOverTauPt
    self.out.photonsOutsideSignalCone_2[0] = tau.photonsOutsideSignalCone
    self.out.puCorr_2[0]                   = tau.puCorr
    
    
    # GENERATOR
    if self.ismc:
      self.out.genmatch_1[0]     = muon.genPartFlav
      self.out.genmatch_2[0]     = tau.genPartFlav
      pt, phi, eta, status       = matchgenvistau(event,tau)
      self.out.genvistaupt_2[0]  = pt
      self.out.genvistaueta_2[0] = eta
      self.out.genvistauphi_2[0] = phi
      self.out.gendm_2[0]        = status
      if self.dozpt:
        self.out.mutaufilter     = filtermutau(event) # for stitching DYJetsToTauTauToMuTauh
    
    
    # JETS
    jets, met, njets_vars, met_vars = self.fillJetBranches(event,muon,tau)
    if self.ismc:
      self.out.jpt_match_2[0], self.out.jpt_genmatch_2[0] = matchtaujet(event,tau,self.ismc)
    else:
      self.out.jpt_match_2[0] = matchtaujet(event,tau,self.ismc)[0]
    
    
    # WEIGHTS
    if self.ismc:
      self.fillCommonCorrBraches(event,jets,met,njets_vars,met_vars)
      if muon.pfRelIso04_all<0.50 and tau.idDeepTau2017v2p1VSjet>=2:
        self.btagTool.fillEffMaps(jets,usejec=self.dojec)
      
      # MUON WEIGHTS
      self.out.trigweight[0]          = self.muSFs.getTriggerSF(muon.pt,muon.eta)
      self.out.idisoweight_1[0]       = self.muSFs.getIdIsoSF(muon.pt,muon.eta)
      
      # DEFAULTS
      self.out.idweight_2[0]          = 1.
      self.out.idweight_dm_2[0]       = 1.
      self.out.idweight_medium_2[0]   = 1.
      
      self.out.ltfweight_2[0]         = 1.
      if not self.dotight:
        self.out.idweightUp_2[0]      = 1.
        self.out.idweightDown_2[0]    = 1.
        self.out.idweightUp_dm_2[0]   = 1.
        self.out.idweightDown_dm_2[0] = 1.
        self.out.ltfweightUp_2[0]     = 1.
        self.out.ltfweightDown_2[0]   = 1.
      
      # TAU WEIGHTS
      if tau.genPartFlav==5: # real tau
        self.out.idweight_2[0]        = self.tauSFsT.getSFvsPT(tau.pt)
        self.out.idweight_medium_2[0] = self.tauSFsM.getSFvsPT(tau.pt)
        self.out.idweight_dm_2[0]     = self.tauSFsT_dm.getSFvsDM(tau.pt,tau.decayMode)
        if not self.dotight:
          self.out.idweightUp_2[0]    = self.tauSFsT.getSFvsPT(tau.pt,unc='Up')
          self.out.idweightDown_2[0]  = self.tauSFsT.getSFvsPT(tau.pt,unc='Down')
          self.out.idweightUp_dm_2[0]   = self.tauSFsT_dm.getSFvsDM(tau.pt,tau.decayMode,unc='Up')
          self.out.idweightDown_dm_2[0] = self.tauSFsT_dm.getSFvsDM(tau.pt,tau.decayMode,unc='Down')
      elif tau.genPartFlav in [1,3]: # muon -> tau fake
        self.out.ltfweight_2[0]       = self.etfSFs.getSFvsEta(tau.eta,tau.genPartFlav)
        if not self.dotight:
          self.out.ltfweightUp_2[0]   = self.etfSFs.getSFvsEta(tau.eta,tau.genPartFlav,unc='Up')
          self.out.ltfweightDown_2[0] = self.etfSFs.getSFvsEta(tau.eta,tau.genPartFlav,unc='Down')
      elif tau.genPartFlav in [2,4]: # electron -> tau fake
        self.out.ltfweight_2[0]       = self.mtfSFs.getSFvsEta(tau.eta,tau.genPartFlav)
        if not self.dotight:
          self.out.ltfweightUp_2[0]   = self.mtfSFs.getSFvsEta(tau.eta,tau.genPartFlav,unc='Up')
          self.out.ltfweightDown_2[0] = self.mtfSFs.getSFvsEta(tau.eta,tau.genPartFlav,unc='Down')
      self.out.weight[0]              = self.out.genweight[0]*self.out.puweight[0]*self.out.trigweight[0]*self.out.idisoweight_1[0] #*self.out.idisoweight_2[0]
    elif self.isembed:
      ###self.applyCommonEmbdedCorrections(event,jets,jetIds50,met,njets_vars,met_vars)
      self.out.genweight[0]           = event.genWeight
      self.out.trackweight[0]         = 0.975 if tau.decayMode==0 else 1.0247 if tau.decayMode==1 else 0.927 if tau.decayMode==10 else 0.974 if tau.decayMode==11 else 1.0
    
    
    # MET & DILEPTON VARIABLES
    self.fillMETAndDiLeptonBranches(event,muon,tau,met,met_vars)
    
    
    self.out.fill()
    return True
예제 #7
0
class ModuleMuTau(ModuleTauPair):
    def __init__(self, fname, **kwargs):
        kwargs['channel'] = 'mutau'
        super(ModuleMuTau, self).__init__(fname, **kwargs)
        self.out = TreeProducerMuTau(fname, self)

        # TRIGGERS
        if self.year == 2016:
            self.trigger = lambda e: e.HLT_IsoMu22 or e.HLT_IsoMu22_eta2p1 or e.HLT_IsoTkMu22 or e.HLT_IsoTkMu22_eta2p1  #or e.HLT_IsoMu19_eta2p1_LooseIsoPFTau20_SingleL1
            self.muonCutPt = lambda e: 23
            self.muonCutEta = lambda e: 2.4 if e.HLT_IsoMu22 or e.HLT_IsoTkMu22 else 2.1
        elif self.year == 2017:
            self.trigger = lambda e: e.HLT_IsoMu24 or e.HLT_IsoMu27  #or e.HLT_IsoMu20_eta2p1_LooseChargedIsoPFTau27_eta2p1_CrossL1
            self.muonCutPt = lambda e: 25 if e.HLT_IsoMu24 else 28
            self.muonCutEta = lambda e: 2.4
        else:
            self.trigger = lambda e: e.HLT_IsoMu24 or e.HLT_IsoMu27  #or e.HLT_IsoMu20_eta2p1_LooseChargedIsoPFTau27_eta2p1_CrossL1
            self.muonCutPt = lambda e: 25
            self.muonCutEta = lambda e: 2.4
        self.tauCutPt = 20
        self.tauCutEta = 2.3

        # CORRECTIONS
        if self.ismc:
            self.muSFs = MuonSFs(year=self.year)
            self.tesTool = TauESTool(tauSFVersion[self.year])
            self.tauSFs = TauIDSFTool(tauSFVersion[self.year],
                                      'DeepTau2017v2p1VSjet', 'Tight')
            self.etfSFs = TauIDSFTool(tauSFVersion[self.year],
                                      'DeepTau2017v2p1VSe', 'VLoose')
            self.mtfSFs = TauIDSFTool(tauSFVersion[self.year],
                                      'DeepTau2017v2p1VSmu', 'Tight')

        # CUTFLOW
        self.out.cutflow.addcut('none', "no cut")
        self.out.cutflow.addcut('trig', "trigger")
        self.out.cutflow.addcut('muon', "muon")
        self.out.cutflow.addcut('tau', "tau")
        self.out.cutflow.addcut('pair', "pair")
        self.out.cutflow.addcut('weight', "no cut, weighted", 15)
        self.out.cutflow.addcut('weight_no0PU', "no cut, weighted, PU>0",
                                16)  # use for normalization

    def beginJob(self):
        """Before processing any events or files."""
        super(ModuleMuTau, self).beginJob()
        print ">>> %-12s = %s" % ('muonCutPt', self.muonCutPt)
        print ">>> %-12s = %s" % ('muonCutEta', self.muonCutEta)
        print ">>> %-12s = %s" % ('tauCutPt', self.tauCutPt)
        print ">>> %-12s = %s" % ('tauCutEta', self.tauCutEta)
        pass

    def analyze(self, event):
        """Process and pre-select events; fill branches and return True if the events passes,
    return False otherwise."""
        sys.stdout.flush()

        ##### NO CUT #####################################
        self.out.cutflow.fill('none')
        if self.isdata:
            self.out.cutflow.fill('weight', 1.)
            if event.PV_npvs > 0:
                self.out.cutflow.fill('weight_no0PU', 1.)
            else:
                return False
        else:
            self.out.cutflow.fill('weight', event.genWeight)
            self.out.pileup.Fill(event.Pileup_nTrueInt)
            if event.Pileup_nTrueInt > 0:
                self.out.cutflow.fill('weight_no0PU', event.genWeight)
            else:
                return False

        ##### TRIGGER ####################################
        if not self.trigger(event):
            return False
        self.out.cutflow.fill('trig')

        ##### MUON #######################################
        muons = []
        for muon in Collection(event, 'Muon'):
            if muon.pt < self.muonCutPt(event): continue
            if abs(muon.eta) > self.muonCutEta(event): continue
            if abs(muon.dz) > 0.2: continue
            if abs(muon.dxy) > 0.045: continue
            if not muon.mediumId: continue
            if muon.pfRelIso04_all > 0.50: continue
            muons.append(muon)
        if len(muons) == 0:
            return False
        self.out.cutflow.fill('muon')

        ##### TAU ########################################
        taus = []
        for tau in Collection(event, 'Tau'):
            if abs(tau.eta) > self.tauCutEta: continue
            if abs(tau.dz) > 0.2: continue
            if tau.decayMode not in [0, 1, 10, 11]: continue
            if abs(tau.charge) != 1: continue
            if self.ismc:
                genmatch = tau.genPartFlav
                if genmatch == 5:  # real tau
                    tes = 1
                    if self.tes != None:
                        tes *= self.tes
                    else:
                        tes *= self.tesTool.getTES(tau.pt,
                                                   tau.decayMode,
                                                   unc=self.tessys)
                    if tes != 1:
                        tau.pt *= tes
                        tau.mass *= tes
                elif self.ltf != 1.0 and 0 < genmatch < 5:  # lepton -> tau fake
                    tau.pt *= self.ltf
                    tau.mass *= self.ltf
                elif self.jtf != 1.0 and genmatch == 0:  # jet -> tau fake
                    tau.pt *= self.jtf
                    tau.mass *= self.jtf
            if tau.pt < self.tauCutPt: continue
            if tau.idDeepTau2017v2p1VSe < 1: continue
            if tau.idDeepTau2017v2p1VSmu < 1: continue
            taus.append(tau)
        if len(taus) == 0:
            return False
        self.out.cutflow.fill('tau')

        ##### MUTAU PAIR #################################
        ltaus = []
        for muon in muons:
            for tau in taus:
                if tau.DeltaR(muon) < 0.5: continue
                ltau = LeptonTauPair(muon, muon.pfRelIso04_all, tau,
                                     tau.rawDeepTau2017v2p1VSjet)
                ltaus.append(ltau)
        if len(ltaus) == 0:
            return False
        muon, tau = max(ltaus).pair
        muon.tlv = muon.p4()
        tau.tlv = tau.p4()
        self.out.cutflow.fill('pair')

        # VETOS
        extramuon_veto, extraelec_veto, dilepton_veto = getLeptonVetoes(
            event, [], [muon], [tau], self.channel)
        self.out.extramuon_veto[0], self.out.extraelec_veto[
            0], self.out.dilepton_veto[0] = getLeptonVetoes(
                event, [], [muon], [], self.channel)
        self.out.lepton_vetoes[0] = self.out.extramuon_veto[
            0] or self.out.extraelec_veto[0] or self.out.dilepton_veto[0]
        self.out.lepton_vetoes_notau[
            0] = extramuon_veto or extraelec_veto or dilepton_veto

        # EVENT
        self.fillEventBranches(event)

        # MUON
        self.out.pt_1[0] = muon.pt
        self.out.eta_1[0] = muon.eta
        self.out.phi_1[0] = muon.phi
        self.out.m_1[0] = muon.mass
        self.out.y_1[0] = muon.tlv.Rapidity()
        self.out.dxy_1[0] = muon.dxy
        self.out.dz_1[0] = muon.dz
        self.out.q_1[0] = muon.charge
        self.out.iso_1[0] = muon.pfRelIso04_all

        # TAU
        self.out.pt_2[0] = tau.pt
        self.out.eta_2[0] = tau.eta
        self.out.phi_2[0] = tau.phi
        self.out.m_2[0] = tau.mass
        self.out.y_2[0] = tau.tlv.Rapidity()
        self.out.dxy_2[0] = tau.dxy
        self.out.dz_2[0] = tau.dz
        self.out.q_2[0] = tau.charge
        self.out.dm_2[0] = tau.decayMode
        self.out.iso_2[0] = tau.rawIso
        self.out.idiso_2[0] = idIso(tau)  # cut-based tau isolation (rawIso)
        self.out.rawAntiEle_2[0] = tau.rawAntiEle
        self.out.rawMVAoldDM2017v2_2[0] = tau.rawMVAoldDM2017v2
        self.out.rawMVAnewDM2017v2_2[0] = tau.rawMVAnewDM2017v2
        self.out.rawDeepTau2017v2p1VSe_2[0] = tau.rawDeepTau2017v2p1VSe
        self.out.rawDeepTau2017v2p1VSmu_2[0] = tau.rawDeepTau2017v2p1VSmu
        self.out.rawDeepTau2017v2p1VSjet_2[0] = tau.rawDeepTau2017v2p1VSjet
        self.out.idAntiEle_2[0] = tau.idAntiEle
        self.out.idAntiMu_2[0] = tau.idAntiMu
        self.out.idDecayMode_2[0] = tau.idDecayMode
        self.out.idDecayModeNewDMs_2[0] = tau.idDecayModeNewDMs
        self.out.idMVAoldDM2017v2_2[0] = tau.idMVAoldDM2017v2
        self.out.idMVAnewDM2017v2_2[0] = tau.idMVAnewDM2017v2
        self.out.idDeepTau2017v2p1VSe_2[0] = tau.idDeepTau2017v2p1VSe
        self.out.idDeepTau2017v2p1VSmu_2[0] = tau.idDeepTau2017v2p1VSmu
        self.out.idDeepTau2017v2p1VSjet_2[0] = tau.idDeepTau2017v2p1VSjet
        self.out.chargedIso_2[0] = tau.chargedIso
        self.out.neutralIso_2[0] = tau.neutralIso
        self.out.leadTkPtOverTauPt_2[0] = tau.leadTkPtOverTauPt
        self.out.photonsOutsideSignalCone_2[0] = tau.photonsOutsideSignalCone
        self.out.puCorr_2[0] = tau.puCorr

        # GENERATOR
        if self.ismc:
            self.out.genmatch_1[0] = muon.genPartFlav
            self.out.genmatch_2[0] = tau.genPartFlav
            dRmin = 0.5
            taumatch = None
            for genvistau in Collection(event, 'GenVisTau'):
                dR = genvistau.DeltaR(tau)
                if dR < dRmin:
                    dRmin = dR
                    taumatch = genvistau
            if taumatch:
                self.out.genvistaupt_2[0] = taumatch.pt
                self.out.genvistaueta_2[0] = taumatch.eta
                self.out.genvistauphi_2[0] = taumatch.phi
                self.out.gendm_2[0] = taumatch.status
            else:
                self.out.genvistaupt_2[0] = -1
                self.out.genvistaueta_2[0] = -9
                self.out.genvistauphi_2[0] = -9
                self.out.gendm_2[0] = -1

        # JETS
        jets, met, njets_vars, met_vars = self.fillJetBranches(
            event, muon, tau)
        if tau.jetIdx >= 0:
            self.out.jpt_match_2[0] = event.Jet_pt[tau.jetIdx]
            if self.ismc:
                if event.Jet_genJetIdx[tau.jetIdx] >= 0:
                    self.out.jpt_genmatch_2[0] = event.GenJet_pt[
                        event.Jet_genJetIdx[tau.jetIdx]]
                else:
                    self.out.jpt_genmatch_2[0] = -1
        else:
            self.out.jpt_match_2[0] = -1

        # WEIGHTS
        if self.ismc:
            self.fillCommonCorrBraches(event, jets, met, njets_vars, met_vars)
            if muon.pfRelIso04_all < 0.50 and tau.idDeepTau2017v2p1VSjet >= 2:
                self.btagTool.fillEffMaps(jets, usejec=self.dojec)

            # MUON WEIGHTS
            self.out.trigweight[0] = self.muSFs.getTriggerSF(muon.pt, muon.eta)
            self.out.idisoweight_1[0] = self.muSFs.getIdIsoSF(
                muon.pt, muon.eta)

            # DEFAULTS
            self.out.idweight_2[0] = 1.
            self.out.ltfweight_2[0] = 1.
            if not self.dotight:
                self.out.idweightUp_2[0] = 1.
                self.out.idweightDown_2[0] = 1.
                self.out.ltfweightUp_2[0] = 1.
                self.out.ltfweightDown_2[0] = 1.

            # TAU WEIGHTS
            if tau.genPartFlav == 5:  # real tau
                self.out.idweight_2[0] = self.tauSFs.getSFvsPT(tau.pt)
                if not self.dotight:
                    self.out.idweightUp_2[0] = self.tauSFs.getSFvsPT(tau.pt,
                                                                     unc='Up')
                    self.out.idweightDown_2[0] = self.tauSFs.getSFvsPT(
                        tau.pt, unc='Down')
            elif tau.genPartFlav in [1, 3]:  # muon -> tau fake
                self.out.ltfweight_2[0] = self.etfSFs.getSFvsEta(
                    tau.eta, tau.genPartFlav)
                if not self.dotight:
                    self.out.ltfweightUp_2[0] = self.etfSFs.getSFvsEta(
                        tau.eta, tau.genPartFlav, unc='Up')
                    self.out.ltfweightDown_2[0] = self.etfSFs.getSFvsEta(
                        tau.eta, tau.genPartFlav, unc='Down')
            elif tau.genPartFlav in [2, 4]:  # electron -> tau fake
                self.out.ltfweight_2[0] = self.mtfSFs.getSFvsEta(
                    tau.eta, tau.genPartFlav)
                if not self.dotight:
                    self.out.ltfweightUp_2[0] = self.mtfSFs.getSFvsEta(
                        tau.eta, tau.genPartFlav, unc='Up')
                    self.out.ltfweightDown_2[0] = self.mtfSFs.getSFvsEta(
                        tau.eta, tau.genPartFlav, unc='Down')
            self.out.weight[0] = self.out.genweight[0] * self.out.puweight[
                0] * self.out.trigweight[0] * self.out.idisoweight_1[
                    0]  #*self.out.idisoweight_2[0]
        elif self.isembed:
            ###self.applyCommonEmbdedCorrections(event,jets,jetIds50,met,njets_vars,met_vars)
            self.out.genweight[0] = event.genWeight
            self.out.trackweight[
                0] = 0.975 if tau.decayMode == 0 else 1.0247 if tau.decayMode == 1 else 0.927 if tau.decayMode == 10 else 0.974 if tau.decayMode == 11 else 1.0

        # MET & DILEPTON VARIABLES
        self.fillMETAndDiLeptonBranches(event, muon.tlv, tau.tlv, met,
                                        met_vars)

        self.out.fill()
        return True
예제 #8
0
class ModuleTauTau(ModuleTauPair):
    def __init__(self, fname, **kwargs):
        kwargs['channel'] = 'mutau'
        super(ModuleTauTau, self).__init__(fname, **kwargs)
        self.out = TreeProducerTauTau(fname, self)

        # TRIGGERS
        jsonfile = os.path.join(datadir,
                                "trigger/tau_triggers_%d.json" % (self.year))
        self.trigger = TrigObjMatcher(jsonfile,
                                      trigger='ditau',
                                      isdata=self.isdata)
        self.tauCutPt = 40
        self.tauCutEta = 2.1

        # CORRECTIONS
        if self.ismc:
            self.trigTool = TauTriggerSFs('tautau', 'Medium', year=self.year)
            self.trigTool_tight = TauTriggerSFs('tautau',
                                                'Tight',
                                                year=self.year)
            self.tesTool = TauESTool(
                tauSFVersion[self.year])  # real tau energy scale
            self.fesTool = TauFESTool(
                tauSFVersion[self.year])  # e -> tau fake energy scale
            self.tauSFs = TauIDSFTool(tauSFVersion[self.year],
                                      'DeepTau2017v2p1VSjet',
                                      'Medium',
                                      dm=True)
            self.tauSFs_tight = TauIDSFTool(tauSFVersion[self.year],
                                            'DeepTau2017v2p1VSjet',
                                            'Tight',
                                            dm=True)
            self.etfSFs = TauIDSFTool(tauSFVersion[self.year],
                                      'DeepTau2017v2p1VSe', 'VVLoose')
            self.mtfSFs = TauIDSFTool(tauSFVersion[self.year],
                                      'DeepTau2017v2p1VSmu', 'Loose')

        # CUTFLOW
        self.out.cutflow.addcut('none', "no cut")
        self.out.cutflow.addcut('trig', "trigger")
        self.out.cutflow.addcut('tau', "tau")
        self.out.cutflow.addcut('pair', "ditau pair")
        self.out.cutflow.addcut('weight', "no cut, weighted", 15)
        self.out.cutflow.addcut('weight_no0PU', "no cut, weighted, PU>0",
                                16)  # use for normalization

    def beginJob(self):
        """Before processing any events or files."""
        super(ModuleTauTau, self).beginJob()
        print ">>> %-12s = %s" % ('tauwp', self.tauwp)
        print ">>> %-12s = %s" % ('tauCutPt', self.tauCutPt)
        print ">>> %-12s = %s" % ('tauCutEta', self.tauCutEta)
        print ">>> %-12s = '%s'" % ('triggers',
                                    self.trigger.path.replace(
                                        "||", "\n>>> %s||" % (' ' * 16)))

    def analyze(self, event):
        """Process and pre-select events; fill branches and return True if the events passes,
    return False otherwise."""
        sys.stdout.flush()

        ##### NO CUT #####################################
        self.out.cutflow.fill('none')
        if self.isdata:
            self.out.cutflow.fill('weight', 1.)
            if event.PV_npvs > 0:
                self.out.cutflow.fill('weight_no0PU', 1.)
            else:
                return False
        else:
            self.out.cutflow.fill('weight', event.genWeight)
            self.out.pileup.Fill(event.Pileup_nTrueInt)
            if event.Pileup_nTrueInt > 0:
                self.out.cutflow.fill('weight_no0PU', event.genWeight)
            else:
                return False

        ##### TRIGGER ####################################
        if not self.trigger.fired(event):
            return False
        self.out.cutflow.fill('trig')

        ##### TAU ########################################
        taus = []
        for tau in Collection(event, 'Tau'):
            if abs(tau.eta) > self.tauCutEta: continue
            if abs(tau.dz) > 0.2: continue
            if tau.decayMode not in [0, 1, 10, 11]: continue
            if abs(tau.charge) != 1: continue
            if tau.idDeepTau2017v2p1VSe < 1: continue  # VVVLoose
            if tau.idDeepTau2017v2p1VSmu < 1: continue  # VLoose
            if tau.idDeepTau2017v2p1VSjet < self.tauwp: continue
            if self.ismc:
                tau.es = 1  # store energy scale for propagating to MET
                genmatch = tau.genPartFlav
                if genmatch == 5:  # real tau
                    if self.tes != None:  # user-defined energy scale (for TES studies)
                        tes = self.tes
                    else:  # (apply by default)
                        tes = self.tesTool.getTES(tau.pt,
                                                  tau.decayMode,
                                                  unc=self.tessys)
                    if tes != 1:
                        tau.pt *= tes
                        tau.mass *= tes
                        tau.es = tes
                elif self.ltf and 0 < genmatch < 5:  # lepton -> tau fake
                    tau.pt *= self.ltf
                    tau.mass *= self.ltf
                    tau.es = self.ltf
                elif genmatch in [
                        1, 3
                ]:  # electron -> tau fake (apply by default, override with 'ltf=1.0')
                    fes = self.fesTool.getFES(tau.eta,
                                              tau.decayMode,
                                              unc=self.fes)
                    tau.pt *= fes
                    tau.mass *= fes
                    tau.es = fes
                elif self.jtf != 1.0 and genmatch == 0:  # jet -> tau fake
                    tau.pt *= self.jtf
                    tau.mass *= self.jtf
                    tau.es = self.jtf
            if tau.pt < self.tauCutPt: continue
            taus.append(tau)
        if len(taus) == 0:
            return False
        self.out.cutflow.fill('tau')

        ##### DITAU PAIR #################################
        ditaus = []
        for i, tau1 in enumerate(taus, 1):
            for tau2 in taus[i:]:
                if tau1.DeltaR(tau2) < 0.5: continue
                ditau = DiTauPair(tau1, tau1.rawDeepTau2017v2p1VSjet, tau2,
                                  tau2.rawDeepTau2017v2p1VSjet)
                ditaus.append(ditau)
        if len(ditaus) == 0:
            return False
        tau1, tau2 = max(ditaus).pair
        tau1.tlv = tau1.p4()
        tau2.tlv = tau2.p4()
        self.out.cutflow.fill('pair')

        # VETOS
        extramuon_veto, extraelec_veto, dilepton_veto = getlepvetoes(
            event, [], [], [tau1, tau2], self.channel)
        self.out.extramuon_veto[0], self.out.extraelec_veto[
            0], self.out.dilepton_veto[0] = getlepvetoes(
                event, [], [], [], self.channel)
        self.out.lepton_vetoes[0] = self.out.extramuon_veto[
            0] or self.out.extraelec_veto[0]  #or self.out.dilepton_veto[0]
        self.out.lepton_vetoes_notau[
            0] = extramuon_veto or extraelec_veto  #or dilepton_veto

        # EVENT
        self.fillEventBranches(event)

        # TAU 1
        self.out.pt_1[0] = tau1.pt
        self.out.eta_1[0] = tau1.eta
        self.out.phi_1[0] = tau1.phi
        self.out.m_1[0] = tau1.mass
        self.out.y_1[0] = tau1.tlv.Rapidity()
        self.out.dxy_1[0] = tau1.dxy
        self.out.dz_1[0] = tau1.dz
        self.out.q_1[0] = tau1.charge
        self.out.dm_1[0] = tau1.decayMode
        self.out.iso_1[0] = tau1.rawIso
        self.out.idiso_1[0] = idIso(tau1)  # cut-based tau isolation (rawIso)
        self.out.rawDeepTau2017v2p1VSe_1[0] = tau1.rawDeepTau2017v2p1VSe
        self.out.rawDeepTau2017v2p1VSmu_1[0] = tau1.rawDeepTau2017v2p1VSmu
        self.out.rawDeepTau2017v2p1VSjet_1[0] = tau1.rawDeepTau2017v2p1VSjet
        self.out.idAntiEle_1[0] = tau1.idAntiEle
        self.out.idAntiMu_1[0] = tau1.idAntiMu
        self.out.idDecayMode_1[0] = tau1.idDecayMode
        self.out.idDecayModeNewDMs_1[0] = tau1.idDecayModeNewDMs
        self.out.idMVAoldDM2017v2_1[0] = tau1.idMVAoldDM2017v2
        self.out.idMVAnewDM2017v2_1[0] = tau1.idMVAnewDM2017v2
        self.out.idDeepTau2017v2p1VSe_1[0] = tau1.idDeepTau2017v2p1VSe
        self.out.idDeepTau2017v2p1VSmu_1[0] = tau1.idDeepTau2017v2p1VSmu
        self.out.idDeepTau2017v2p1VSjet_1[0] = tau1.idDeepTau2017v2p1VSjet
        self.out.chargedIso_1[0] = tau1.chargedIso
        self.out.neutralIso_1[0] = tau1.neutralIso
        self.out.leadTkPtOverTauPt_1[0] = tau1.leadTkPtOverTauPt
        self.out.photonsOutsideSignalCone_1[0] = tau1.photonsOutsideSignalCone
        self.out.puCorr_1[0] = tau1.puCorr

        # TAU 2
        self.out.pt_2[0] = tau2.pt
        self.out.eta_2[0] = tau2.eta
        self.out.phi_2[0] = tau2.phi
        self.out.m_2[0] = tau2.mass
        self.out.y_2[0] = tau2.tlv.Rapidity()
        self.out.dxy_2[0] = tau2.dxy
        self.out.dz_2[0] = tau2.dz
        self.out.q_2[0] = tau2.charge
        self.out.dm_2[0] = tau2.decayMode
        self.out.iso_2[0] = tau2.rawIso
        self.out.idiso_2[0] = idIso(tau2)  # cut-based tau isolation (rawIso)
        self.out.rawDeepTau2017v2p1VSe_2[0] = tau2.rawDeepTau2017v2p1VSe
        self.out.rawDeepTau2017v2p1VSmu_2[0] = tau2.rawDeepTau2017v2p1VSmu
        self.out.rawDeepTau2017v2p1VSjet_2[0] = tau2.rawDeepTau2017v2p1VSjet
        self.out.idAntiEle_2[0] = tau2.idAntiEle
        self.out.idAntiMu_2[0] = tau2.idAntiMu
        self.out.idDecayMode_2[0] = tau2.idDecayMode
        self.out.idDecayModeNewDMs_2[0] = tau2.idDecayModeNewDMs
        self.out.idMVAoldDM2017v2_2[0] = tau2.idMVAoldDM2017v2
        self.out.idMVAnewDM2017v2_2[0] = tau2.idMVAnewDM2017v2
        self.out.idDeepTau2017v2p1VSe_2[0] = tau2.idDeepTau2017v2p1VSe
        self.out.idDeepTau2017v2p1VSmu_2[0] = tau2.idDeepTau2017v2p1VSmu
        self.out.idDeepTau2017v2p1VSjet_2[0] = tau2.idDeepTau2017v2p1VSjet
        self.out.chargedIso_2[0] = tau2.chargedIso
        self.out.neutralIso_2[0] = tau2.neutralIso
        self.out.leadTkPtOverTauPt_2[0] = tau2.leadTkPtOverTauPt
        self.out.photonsOutsideSignalCone_2[0] = tau2.photonsOutsideSignalCone
        self.out.puCorr_2[0] = tau2.puCorr

        # GENERATOR
        if self.ismc:
            self.out.genmatch_1[0] = tau1.genPartFlav
            self.out.genmatch_2[0] = tau2.genPartFlav
            pt1, phi1, eta1, status1 = matchgenvistau(event, tau1)
            pt2, phi2, eta2, status2 = matchgenvistau(event, tau2)
            self.out.genvistaupt_1[0] = pt1
            self.out.genvistaueta_1[0] = eta1
            self.out.genvistauphi_1[0] = phi1
            self.out.gendm_1[0] = status1
            self.out.genvistaupt_2[0] = pt2
            self.out.genvistaueta_2[0] = eta2
            self.out.genvistauphi_2[0] = phi2
            self.out.gendm_2[0] = status2

        # JETS
        jets, met, njets_vars, met_vars = self.fillJetBranches(
            event, tau1, tau2)
        self.out.jpt_match_1[0], self.out.jpt_genmatch_1[0] = matchtaujet(
            event, tau1, self.ismc)
        self.out.jpt_match_2[0], self.out.jpt_genmatch_2[0] = matchtaujet(
            event, tau2, self.ismc)

        # WEIGHTS
        if self.ismc:
            self.fillCommonCorrBraches(event, jets, met, njets_vars, met_vars)
            if tau1.idDeepTau2017v2p1VSjet >= 2 and tau2.idDeepTau2017v2p1VSjet >= 2:
                self.btagTool.fillEffMaps(jets, usejec=self.dojec)
            self.out.trigweight[0] = self.trigTool.getSFPair(tau1, tau2)
            self.out.trigweight_tight[0] = self.trigTool_tight.getSFPair(
                tau1, tau2)
            if not self.dotight:
                self.out.trigweightUp[0] = self.trigTool.getSFPair(tau1,
                                                                   tau2,
                                                                   unc='Up')
                self.out.trigweightDown[0] = self.trigTool.getSFPair(
                    tau1, tau2, unc='Down')

            # DEFAULTS
            self.out.idweight_1[0] = 1.
            self.out.idweight_2[0] = 1.
            self.out.idweight_tight_1[0] = 1.
            self.out.idweight_tight_2[0] = 1.
            self.out.ltfweight_2[0] = 1.
            self.out.ltfweight_2[0] = 1.
            if not self.dotight:
                self.out.idweightUp_1[0] = 1.
                self.out.idweightUp_2[0] = 1.
                self.out.idweightDown_1[0] = 1.
                self.out.idweightDown_2[0] = 1.
                self.out.ltfweightUp_1[0] = 1.
                self.out.ltfweightUp_2[0] = 1.
                self.out.ltfweightDown_1[0] = 1.
                self.out.ltfweightDown_2[0] = 1.

            # TAU 1 WEIGHTS
            if tau1.genPartFlav == 5:
                self.out.idweight_1[0] = self.tauSFs.getSFvsDM(
                    tau1.pt, tau1.decayMode)
                self.out.idweight_tight_1[0] = self.tauSFs_tight.getSFvsDM(
                    tau1.pt, tau1.decayMode)
                if not self.dotight:
                    self.out.idweightUp_1[0] = self.tauSFs.getSFvsDM(
                        tau1.pt, tau1.decayMode, unc='Up')
                    self.out.idweightDown_1[0] = self.tauSFs.getSFvsDM(
                        tau1.pt, tau1.decayMode, unc='Down')
            elif tau1.genPartFlav > 0:
                ltfTool = self.etfSFs if tau1.genPartFlav in [
                    1, 3
                ] else self.mtfSFs
                self.out.ltfweight_1[0] = ltfTool.getSFvsEta(
                    tau1.eta, tau1.genPartFlav)
                if not self.dotight:
                    self.out.ltfweightUp_1[0] = ltfTool.getSFvsEta(
                        tau1.eta, tau1.genPartFlav, unc='Up')
                    self.out.ltfweightDown_1[0] = ltfTool.getSFvsEta(
                        tau1.eta, tau1.genPartFlav, unc='Down')

            # TAU 2 WEIGHTS
            if tau1.genPartFlav == 5:
                self.out.idweight_2[0] = self.tauSFs.getSFvsDM(
                    tau1.pt, tau1.decayMode)
                self.out.idweight_tight_2[0] = self.tauSFs_tight.getSFvsDM(
                    tau1.pt, tau1.decayMode)
                if not self.dotight:
                    self.out.idweightUp_2[0] = self.tauSFs.getSFvsDM(
                        tau1.pt, tau1.decayMode, unc='Up')
                    self.out.idweightDown_2[0] = self.tauSFs.getSFvsDM(
                        tau1.pt, tau1.decayMode, unc='Down')
            elif tau1.genPartFlav > 0:
                ltfTool = self.etfSFs if tau1.genPartFlav in [
                    1, 3
                ] else self.mtfSFs
                self.out.ltfweight_2[0] = ltfTool.getSFvsEta(
                    tau1.eta, tau1.genPartFlav)
                if not self.dotight:
                    self.out.ltfweightUp_2[0] = ltfTool.getSFvsEta(
                        tau1.eta, tau1.genPartFlav, unc='Up')
                    self.out.ltfweightDown_2[0] = ltfTool.getSFvsEta(
                        tau1.eta, tau1.genPartFlav, unc='Down')

        # MET & DILEPTON VARIABLES
        self.fillMETAndDiLeptonBranches(event, tau1, tau2, met, met_vars)

        self.out.fill()
        return True