def filler(s):
    # shortcut
    r = reader.data
    if isMC: gPart = getGenPartsAll(r)

    # weight
    if options.T2tt:
        s.weight = signalWeight[(r.GenSusyMScan1, r.GenSusyMScan2)]['weight']
        s.mStop = r.GenSusyMScan1
        s.mNeu = r.GenSusyMScan2
        s.reweightXSecUp = signalWeight[(r.GenSusyMScan1,
                                         r.GenSusyMScan2)]['xSecFacUp']
        s.reweightXSecDown = signalWeight[(r.GenSusyMScan1,
                                           r.GenSusyMScan2)]['xSecFacDown']
    elif isMC:
        s.weight = lumiScaleFactor * r.genWeight if lumiScaleFactor is not None else 1
    elif isData:
        s.weight = 1
    else:
        raise NotImplementedError("isMC %r isData %r T2tt? %r TTDM?" %
                                  (isMC, isData, options.T2tt, options.TTDM))

    # lumi lists and vetos
    if isData:
        s.vetoPassed = vetoList.passesVeto(r.run, r.lumi, r.evt)
        s.jsonPassed = lumiList.contains(r.run, r.lumi)
        # store decision to use after filler has been executed
        s.jsonPassed_ = s.jsonPassed

    if isMC:
        s.reweightPU = puRW(r.nTrueInt)
        s.reweightPUDown = puRWDown(r.nTrueInt)
        s.reweightPUUp = puRWUp(r.nTrueInt)

    # top pt reweighting
    if isMC:
        s.reweightTopPt = topPtReweightingFunc(getTopPtsForReweighting(
            r)) / topScaleF if doTopPtReweighting else 1.

    # jet/met related quantities, also load the leptons already
    allJets = getGoodJets(r, ptCut=0, jetVars=jetVarNames)
    jets = filter(lambda j: jetId(j, ptCut=30, absEtaCut=2.4), allJets)
    bJets = filter(lambda j: isBJet(j), jets)
    nonBJets = filter(lambda j: not isBJet(j), jets)
    if isVeryLoose:
        # all leptons up to relIso 1
        miniRelIso = 999.
        ptCut = 20 if not isVeryLoosePt10 else 10
        leptons_pt10 = getGoodAndOtherLeptons(r,
                                              ptCut=10,
                                              miniRelIso=miniRelIso,
                                              dz=0.1,
                                              dxy=1.)
        leptons = filter(lambda l: l['pt'] > ptCut, leptons_pt10)
    elif isLoose:
        # reliso 0.4
        miniRelIso = 0.4
        leptons_pt10 = getGoodLeptons(r, ptCut=10, miniRelIso=miniRelIso)
        leptons = filter(lambda l: l['pt'] > 20, leptons_pt10)
    else:
        miniRelIso = 0.2
        leptons_pt10 = getGoodLeptons(r, ptCut=10, miniRelIso=miniRelIso)
        # relIso 0.2
        leptons = filter(lambda l: l['pt'] > 20, leptons_pt10)

    s.met_pt = r.met_pt
    s.met_phi = r.met_phi

    # Filling jets
    s.nJetGood = len(jets)
    for iJet, jet in enumerate(jets):
        for b in jetVarNames:
            getattr(s, "JetGood_" + b)[iJet] = jet[b]
    if isSingleLep:
        # Compute M3 and the three indiced of the jets entering m3
        s.m3, s.m3_ind1, s.m3_ind2, s.m3_ind3 = m3(jets)

    s.ht = sum([j['pt'] for j in jets])
    s.metSig = s.met_pt / sqrt(s.ht) if s.ht > 0 else float('nan')
    s.nBTag = len(bJets)

    jets_sys = {}
    bjets_sys = {}
    nonBjets_sys = {}

    metVariants = ['']  # default

    # Keep photons and estimate met including (leading pt) photon
    if options.keepPhotons:
        photons = getGoodPhotons(r, ptCut=20, idLevel="loose", isData=isData)
        s.nPhotonGood = len(photons)
        if s.nPhotonGood > 0:
            metVariants += [
                '_photonEstimated'
            ]  # do all met calculations also for the photonEstimated variant
            s.photon_pt = photons[0]['pt']
            s.photon_eta = photons[0]['eta']
            s.photon_phi = photons[0]['phi']
            s.photon_idCutBased = photons[0]['idCutBased']
            if isMC:
                genPhoton = getGenPhoton(gPart)
                s.photon_genPt = genPhoton[
                    'pt'] if genPhoton is not None else float('nan')
                s.photon_genEta = genPhoton[
                    'eta'] if genPhoton is not None else float('nan')

            s.met_pt_photonEstimated, s.met_phi_photonEstimated = getMetPhotonEstimated(
                r.met_pt, r.met_phi, photons[0])
            s.metSig_photonEstimated = s.met_pt_photonEstimated / sqrt(
                s.ht) if s.ht > 0 else float('nan')

            s.photonJetdR = min(deltaR(photons[0], j)
                                for j in jets) if len(jets) > 0 else 999
            s.photonLepdR = min(
                deltaR(photons[0], l)
                for l in leptons_pt10) if len(leptons_pt10) > 0 else 999

    if options.checkTTGJetsOverlap and isMC:
        s.TTGJetsEventType = getTTGJetsEventType(r)

    if addSystematicVariations:
        for j in allJets:
            j['pt_JECUp'] = j['pt'] / j['corr'] * j['corr_JECUp']
            j['pt_JECDown'] = j['pt'] / j['corr'] * j['corr_JECDown']
            # JERUp, JERDown, JER
            addJERScaling(j)
        for var in ['JECUp', 'JECDown', 'JERUp', 'JERDown']:
            jets_sys[var] = filter(
                lambda j: jetId(j, ptCut=30, absEtaCut=2.4, ptVar='pt_' + var),
                allJets)
            bjets_sys[var] = filter(isBJet, jets_sys[var])
            nonBjets_sys[var] = filter(lambda j: not isBJet(j), jets_sys[var])

            setattr(s, "nJetGood_" + var, len(jets_sys[var]))
            setattr(s, "ht_" + var,
                    sum([j['pt_' + var] for j in jets_sys[var]]))
            setattr(s, "nBTag_" + var, len(bjets_sys[var]))

        for var in [
                'JECUp', 'JECDown', 'JERUp', 'JERDown', 'UnclusteredEnUp',
                'UnclusteredEnDown'
        ]:
            for i in metVariants:
                # use cmg MET correction values ecept for JER where it is zero. There, propagate jet variations.
                if 'JER' in var:
                    (met_corr_pt, met_corr_phi) = getMetJetCorrected(
                        getattr(s, "met_pt" + i), getattr(s, "met_phi" + i),
                        jets_sys[var], var)
                else:
                    (met_corr_pt, met_corr_phi) = getMetCorrected(
                        r, var,
                        photons[0] if i.count("photonEstimated") else None)

                setattr(s, "met_pt" + i + "_" + var, met_corr_pt)
                setattr(s, "met_phi" + i + "_" + var, met_corr_phi)
                ht = getattr(s, "ht_" +
                             var) if 'Unclustered' not in var else s.ht
                setattr(
                    s, "metSig" + i + "_" + var,
                    getattr(s, "met_pt" + i + "_" + var) /
                    sqrt(ht) if ht > 0 else float('nan'))

    if isSingleLep or isDiLep:
        s.nGoodMuons = len(filter(lambda l: abs(l['pdgId']) == 13, leptons))
        s.nGoodElectrons = len(filter(lambda l: abs(l['pdgId']) == 11,
                                      leptons))

        if len(leptons) >= 1:
            s.l1_pt = leptons[0]['pt']
            s.l1_eta = leptons[0]['eta']
            s.l1_phi = leptons[0]['phi']
            s.l1_pdgId = leptons[0]['pdgId']
            s.l1_index = leptons[0]['index']
            s.l1_jetPtRelv2 = leptons[0]['jetPtRelv2']
            s.l1_jetPtRatiov2 = leptons[0]['jetPtRatiov2']
            s.l1_jetPtRelv2 = leptons[0]['jetPtRelv2']
            s.l1_miniRelIso = leptons[0]['miniRelIso']
            s.l1_dxy = leptons[0]['dxy']
            s.l1_dz = leptons[0]['dz']

        # For TTZ studies: find Z boson candidate, and use third lepton to calculate mt
        (s.mlmZ_mass, zl1, zl2) = closestOSDLMassToMZ(leptons_pt10)
        #        if len(leptons_pt10) >= 3:
        #            thirdLepton = leptons_pt10[[x for x in range(len(leptons_pt10)) if x != zl1 and x != zl2][0]]
        #            for i in metVariants:
        #              setattr(s, "mt"+i, sqrt(2*thirdLepton['pt']*getattr(s, "met_pt"+i)*(1-cos(thirdLepton['phi']-getattr(s, "met_phi"+i)))))

        if options.fastSim:
            s.reweightLeptonFastSimSF = reduce(mul, [
                leptonFastSimSF.get3DSF(
                    pdgId=l['pdgId'], pt=l['pt'], eta=l['eta'], nvtx=r.nVert)
                for l in leptons
            ], 1)
            s.reweightLeptonFastSimSFUp = reduce(mul, [
                leptonFastSimSF.get3DSF(pdgId=l['pdgId'],
                                        pt=l['pt'],
                                        eta=l['eta'],
                                        nvtx=r.nVert,
                                        sigma=+1) for l in leptons
            ], 1)
            s.reweightLeptonFastSimSFDown = reduce(mul, [
                leptonFastSimSF.get3DSF(pdgId=l['pdgId'],
                                        pt=l['pt'],
                                        eta=l['eta'],
                                        nvtx=r.nVert,
                                        sigma=-1) for l in leptons
            ], 1)

    if isDiLep:
        if len(
                leptons
        ) >= 2:  # and leptons[0]['pdgId']*leptons[1]['pdgId']<0 and abs(leptons[0]['pdgId'])==abs(leptons[1]['pdgId']): #OSSF choice
            mt2Calc.reset()
            s.l2_pt = leptons[1]['pt']
            s.l2_eta = leptons[1]['eta']
            s.l2_phi = leptons[1]['phi']
            s.l2_pdgId = leptons[1]['pdgId']
            s.l2_index = leptons[1]['index']
            s.l2_jetPtRatiov2 = leptons[1]['jetPtRatiov2']
            s.l2_jetPtRelv2 = leptons[1]['jetPtRelv2']
            s.l2_miniRelIso = leptons[1]['miniRelIso']
            s.l2_dxy = leptons[1]['dxy']
            s.l2_dz = leptons[1]['dz']

            l_pdgs = [abs(leptons[0]['pdgId']), abs(leptons[1]['pdgId'])]
            l_pdgs.sort()
            s.isMuMu = l_pdgs == [13, 13]
            s.isEE = l_pdgs == [11, 11]
            s.isEMu = l_pdgs == [11, 13]
            s.isOS = s.l1_pdgId * s.l2_pdgId < 0

            l1 = ROOT.TLorentzVector()
            l1.SetPtEtaPhiM(leptons[0]['pt'], leptons[0]['eta'],
                            leptons[0]['phi'], 0)
            l2 = ROOT.TLorentzVector()
            l2.SetPtEtaPhiM(leptons[1]['pt'], leptons[1]['eta'],
                            leptons[1]['phi'], 0)
            dl = l1 + l2
            s.dl_pt = dl.Pt()
            s.dl_eta = dl.Eta()
            s.dl_phi = dl.Phi()
            s.dl_mass = dl.M()
            mt2Calc.setLeptons(s.l1_pt, s.l1_eta, s.l1_phi, s.l2_pt, s.l2_eta,
                               s.l2_phi)

            # To check MC truth when looking at the TTZToLLNuNu sample
            if isMC:
                zBoson = getGenZ(gPart)
                s.zBoson_genPt = zBoson['pt'] if zBoson is not None else float(
                    'nan')
                s.zBoson_genEta = zBoson[
                    'eta'] if zBoson is not None else float('nan')

            if options.keepPhotons and s.nPhotonGood > 0:
                gamma = ROOT.TLorentzVector()
                gamma.SetPtEtaPhiM(photons[0]['pt'], photons[0]['eta'],
                                   photons[0]['phi'], photons[0]['mass'])
                dlg = dl + gamma
                s.dlg_mass = dlg.M()

            for i in metVariants:
                mt2Calc.setMet(getattr(s, 'met_pt' + i),
                               getattr(s, 'met_phi', i))
                setattr(s, "dl_mt2ll" + i, mt2Calc.mt2ll())

                if len(jets) >= 2:
                    bj0, bj1 = (bJets + nonBJets)[:2]
                    mt2Calc.setBJets(bj0['pt'], bj0['eta'], bj0['phi'],
                                     bj1['pt'], bj1['eta'], bj1['phi'])
                    setattr(s, "dl_mt2bb" + i, mt2Calc.mt2bb())
                    setattr(s, "dl_mt2blbl" + i, mt2Calc.mt2blbl())

                if addSystematicVariations:
                    for var in [
                            'JECUp', 'JECDown', 'JERUp', 'JERDown',
                            'UnclusteredEnUp', 'UnclusteredEnDown'
                    ]:
                        mt2Calc.setMet(getattr(s, "met_pt" + i + "_" + var),
                                       getattr(s, "met_phi" + i + "_" + var))
                        setattr(s, "dl_mt2ll" + i + "_" + var, mt2Calc.mt2ll())
                        bj0_, bj1_ = bj0, bj1
                        if not 'Unclustered' in var:
                            if len(jets_sys[var]) >= 2:
                                bj0_, bj1_ = (bjets_sys[var] +
                                              nonBjets_sys[var])[:2]
                            else:
                                bj0_, bj1_ = None, None
                        if bj0_ and bj1_:
                            mt2Calc.setBJets(bj0_['pt'], bj0_['eta'],
                                             bj0_['phi'], bj1_['pt'],
                                             bj1_['eta'], bj1_['phi'])
                            setattr(s, 'dl_mt2bb' + i + '_' + var,
                                    mt2Calc.mt2bb())
                            setattr(s, 'dl_mt2blbl' + i + '_' + var,
                                    mt2Calc.mt2blbl())

    if addSystematicVariations:
        # B tagging weights method 1a
        for j in jets:
            btagEff.addBTagEffToJet(j)
        for var in btagEff.btagWeightNames:
            if var != 'MC':
                setattr(s, 'reweightBTag_' + var,
                        btagEff.getBTagSF_1a(var, bJets, nonBJets))

    # gen information on extra leptons
    if isMC and not options.skipGenLepMatching:
        genSearch.init(gPart)
        # Start with status 1 gen leptons in acceptance
        gLep = filter(
            lambda p: abs(p['pdgId']) in [11, 13] and p['status'] == 1 and p[
                'pt'] > 20 and abs(p['eta']) < 2.5, gPart)
        for l in gLep:
            ancestry = [gPart[x]['pdgId'] for x in genSearch.ancestry(l)]
            l["n_D"] = sum([ancestry.count(p) for p in D_mesons])
            l["n_B"] = sum([ancestry.count(p) for p in B_mesons])
            l["n_W"] = sum([ancestry.count(p) for p in [24, -24]])
            l["n_t"] = sum([ancestry.count(p) for p in [6, -6]])
            l["n_tau"] = sum([ancestry.count(p) for p in [15, -15]])
            matched_lep = bestDRMatchInCollection(l, leptons_pt10)
            if matched_lep:
                l["lepGoodMatchIndex"] = matched_lep['index']
                if isSingleLep:
                    l["matchesPromptGoodLepton"] = l["lepGoodMatchIndex"] in [
                        s.l1_index
                    ]
                elif isDiLep:
                    l["matchesPromptGoodLepton"] = l["lepGoodMatchIndex"] in [
                        s.l1_index, s.l2_index
                    ]
                else:
                    l["matchesPromptGoodLepton"] = 0
            else:
                l["lepGoodMatchIndex"] = -1
                l["matchesPromptGoodLepton"] = 0
#            if      l["n_t"]>0 and l["n_W"]>0 and l["n_B"]==0 and l["n_D"]==0 and l["n_tau"]==0:
#                print "t->W->l"
#            elif    l["n_t"]>0 and l["n_W"]==0 and l["n_B"]>0 and l["n_D"]==0 and l["n_tau"]==0:
#                print "t->b->B->l"
#            elif    l["n_t"]>0 and l["n_W"]==0 and l["n_B"]>0 and l["n_D"]>0 and l["n_tau"]==0:
#                print "t->b->B->D->l"
#            elif    l["n_t"]>0 and l["n_W"]>0 and l["n_B"]==0 and l["n_D"]==0 and l["n_tau"]>0 :
#                print "t->W->tau->l"
#            elif    l["n_t"]>0 and l["n_W"]>0 and l["n_B"]==0 and l["n_D"]>0 and l["n_tau"]==0:
#                print "t->W->c->D->l"
#            elif    l["n_t"]==0 and l["n_W"]==0 and l["n_B"]>0 and l["n_D"]>=0 and l["n_tau"]==0:
#                print l['pdgId'], l['pt'], l['phi'], l['eta'], ",".join(pdgToName( gPart[x]['pdgId']) for x in genSearch.ancestry(l) )
#                for p in genSearch.ancestry(l):
#                    print p, gPart[p]
#            else:
#                pass
# print l['pdgId'], l['pt'], l['phi'], l['eta'], ",".join(pdgToName(gPart[x]['pdgId']) for x in genSearch.ancestry(l))
        s.nGenLep = len(gLep)
        for iLep, lep in enumerate(gLep):
            for b in genLepVarNames:
                getattr(s, "GenLep_" + b)[iLep] = lep[b]
def filler(s):
    # shortcut
    r = reader.data
    if isMC: gPart = getGenPartsAll(r)

    # weight
    if options.T2tt:
        s.weight=signalWeight[(r.GenSusyMScan1, r.GenSusyMScan2)]['weight']
        s.mStop = r.GenSusyMScan1
        s.mNeu  = r.GenSusyMScan2
        s.reweightXSecUp    = signalWeight[(r.GenSusyMScan1, r.GenSusyMScan2)]['xSecFacUp']
        s.reweightXSecDown  = signalWeight[(r.GenSusyMScan1, r.GenSusyMScan2)]['xSecFacDown']
    elif isMC:
        s.weight = lumiScaleFactor*r.genWeight if lumiScaleFactor is not None else 1
    elif isData:
        s.weight = 1
    else:
        raise NotImplementedError( "isMC %r isData %r T2tt? %r TTDM?" % (isMC, isData, options.T2tt, options.TTDM) )

    # lumi lists and vetos
    if isData:
        s.vetoPassed  = vetoList.passesVeto(r.run, r.lumi, r.evt)
        s.jsonPassed  = lumiList.contains(r.run, r.lumi)
        # store decision to use after filler has been executed
        s.jsonPassed_ = s.jsonPassed

    if isMC:
        s.reweightPU     = puRW(r.nTrueInt)
        s.reweightPUDown = puRWDown(r.nTrueInt)
        s.reweightPUUp   = puRWUp(r.nTrueInt)

    # top pt reweighting
    if isMC: s.reweightTopPt = topPtReweightingFunc(getTopPtsForReweighting(r))/topScaleF if doTopPtReweighting else 1.

    # jet/met related quantities, also load the leptons already
    allJets      = getGoodJets(r, ptCut=0, jetVars = jetVarNames )
    jets         = filter(lambda j:jetId(j, ptCut=30, absEtaCut=2.4), allJets)
    bJets        = filter(lambda j:isBJet(j), jets)
    nonBJets     = filter(lambda j:not isBJet(j), jets)
    if isVeryLoose:
        # all leptons up to relIso 1
        miniRelIso = 999.
        ptCut = 20 if not isVeryLoosePt10 else 10 
        leptons_pt10 = getGoodAndOtherLeptons(r, ptCut=10, miniRelIso = miniRelIso , dz = 0.1, dxy = 1.)
        leptons      = filter(lambda l:l['pt']>ptCut, leptons_pt10)
    elif isLoose:
        # reliso 0.4
        miniRelIso = 0.4
        leptons_pt10 = getGoodLeptons(r, ptCut=10, miniRelIso = miniRelIso)
        leptons      = filter(lambda l:l['pt']>20, leptons_pt10)
    else:
        miniRelIso = 0.2
        leptons_pt10 = getGoodLeptons(r, ptCut=10, miniRelIso = miniRelIso)
        # relIso 0.2
        leptons      = filter(lambda l:l['pt']>20, leptons_pt10)

    s.met_pt  = r.met_pt
    s.met_phi = r.met_phi

    # Filling jets
    s.nJetGood   = len(jets)
    for iJet, jet in enumerate(jets):
        for b in jetVarNames:
            getattr(s, "JetGood_"+b)[iJet] = jet[b]
    if isSingleLep:
        # Compute M3 and the three indiced of the jets entering m3
        s.m3, s.m3_ind1, s.m3_ind2, s.m3_ind3 = m3( jets )

    s.ht         = sum([j['pt'] for j in jets])
    s.metSig     = s.met_pt/sqrt(s.ht) if s.ht>0 else float('nan')
    s.nBTag      = len(bJets)

    jets_sys      = {}
    bjets_sys     = {}
    nonBjets_sys  = {}

    metVariants = [''] # default

    # Keep photons and estimate met including (leading pt) photon
    if options.keepPhotons:
       photons = getGoodPhotons(r, ptCut=20, idLevel="loose", isData=isData)
       s.nPhotonGood = len(photons)
       if s.nPhotonGood > 0:
         metVariants += ['_photonEstimated']  # do all met calculations also for the photonEstimated variant
         s.photon_pt         = photons[0]['pt']
         s.photon_eta        = photons[0]['eta']
         s.photon_phi        = photons[0]['phi']
         s.photon_idCutBased = photons[0]['idCutBased']
         if isMC:
           genPhoton       = getGenPhoton(gPart)
           s.photon_genPt  = genPhoton['pt']  if genPhoton is not None else float('nan')
           s.photon_genEta = genPhoton['eta'] if genPhoton is not None else float('nan')

         s.met_pt_photonEstimated, s.met_phi_photonEstimated = getMetPhotonEstimated(r.met_pt, r.met_phi, photons[0])
         s.metSig_photonEstimated = s.met_pt_photonEstimated/sqrt(s.ht) if s.ht>0 else float('nan')

         s.photonJetdR = min(deltaR(photons[0], j) for j in jets) if len(jets) > 0 else 999
         s.photonLepdR = min(deltaR(photons[0], l) for l in leptons_pt10) if len(leptons_pt10) > 0 else 999

    if options.checkTTGJetsOverlap and isMC:
       s.TTGJetsEventType = getTTGJetsEventType(r)

    if addSystematicVariations:
        for j in allJets:
            j['pt_JECUp']   =j['pt']/j['corr']*j['corr_JECUp']
            j['pt_JECDown'] =j['pt']/j['corr']*j['corr_JECDown']
            # JERUp, JERDown, JER
            addJERScaling(j)
        for var in ['JECUp', 'JECDown', 'JERUp', 'JERDown']:
            jets_sys[var]       = filter(lambda j:jetId(j, ptCut=30, absEtaCut=2.4, ptVar='pt_'+var), allJets)
            bjets_sys[var]      = filter(isBJet, jets_sys[var])
            nonBjets_sys[var]   = filter(lambda j: not isBJet(j), jets_sys[var])

            setattr(s, "nJetGood_"+var, len(jets_sys[var]))
            setattr(s, "ht_"+var,       sum([j['pt_'+var] for j in jets_sys[var]]))
            setattr(s, "nBTag_"+var,    len(bjets_sys[var]))

        for var in ['JECUp', 'JECDown', 'JERUp', 'JERDown', 'UnclusteredEnUp', 'UnclusteredEnDown']:
            for i in metVariants:
                # use cmg MET correction values ecept for JER where it is zero. There, propagate jet variations.
                if 'JER' in var:
                  (met_corr_pt, met_corr_phi) = getMetJetCorrected(getattr(s, "met_pt" + i), getattr(s,"met_phi" + i), jets_sys[var], var)
                else:
                  (met_corr_pt, met_corr_phi) = getMetCorrected(r, var, photons[0] if i.count("photonEstimated") else None)

                setattr(s, "met_pt" +i+"_"+var, met_corr_pt)
                setattr(s, "met_phi"+i+"_"+var, met_corr_phi)
                ht = getattr(s, "ht_"+var) if 'Unclustered' not in var else s.ht 
                setattr(s, "metSig" +i+"_"+var, getattr(s, "met_pt"+i+"_"+var)/sqrt( ht ) if ht>0 else float('nan') )

    if isSingleLep or isDiLep:
        s.nGoodMuons      = len(filter( lambda l:abs(l['pdgId'])==13, leptons))
        s.nGoodElectrons  = len(filter( lambda l:abs(l['pdgId'])==11, leptons))

        if len(leptons)>=1:
            s.l1_pt     = leptons[0]['pt']
            s.l1_eta    = leptons[0]['eta']
            s.l1_phi    = leptons[0]['phi']
            s.l1_pdgId  = leptons[0]['pdgId']
            s.l1_index  = leptons[0]['index']
            s.l1_jetPtRelv2  = leptons[0]['jetPtRelv2']
            s.l1_jetPtRatiov2  = leptons[0]['jetPtRatiov2']
            s.l1_jetPtRelv2    = leptons[0]['jetPtRelv2']
            s.l1_miniRelIso = leptons[0]['miniRelIso']
            s.l1_dxy = leptons[0]['dxy']
            s.l1_dz = leptons[0]['dz']

        # For TTZ studies: find Z boson candidate, and use third lepton to calculate mt
        (s.mlmZ_mass, zl1, zl2) = closestOSDLMassToMZ(leptons_pt10)
#        if len(leptons_pt10) >= 3:
#            thirdLepton = leptons_pt10[[x for x in range(len(leptons_pt10)) if x != zl1 and x != zl2][0]]
#            for i in metVariants:
#              setattr(s, "mt"+i, sqrt(2*thirdLepton['pt']*getattr(s, "met_pt"+i)*(1-cos(thirdLepton['phi']-getattr(s, "met_phi"+i)))))

        if options.fastSim:
            s.reweightLeptonFastSimSF     = reduce(mul, [leptonFastSimSF.get3DSF(pdgId=l['pdgId'], pt=l['pt'], eta=l['eta'] , nvtx = r.nVert) for l in leptons], 1)
            s.reweightLeptonFastSimSFUp   = reduce(mul, [leptonFastSimSF.get3DSF(pdgId=l['pdgId'], pt=l['pt'], eta=l['eta'] , nvtx = r.nVert, sigma = +1) for l in leptons], 1)
            s.reweightLeptonFastSimSFDown = reduce(mul, [leptonFastSimSF.get3DSF(pdgId=l['pdgId'], pt=l['pt'], eta=l['eta'] , nvtx = r.nVert, sigma = -1) for l in leptons], 1)

    if isDiLep:
        if len(leptons)>=2:# and leptons[0]['pdgId']*leptons[1]['pdgId']<0 and abs(leptons[0]['pdgId'])==abs(leptons[1]['pdgId']): #OSSF choice
            mt2Calc.reset()
            s.l2_pt     = leptons[1]['pt']
            s.l2_eta    = leptons[1]['eta']
            s.l2_phi    = leptons[1]['phi']
            s.l2_pdgId  = leptons[1]['pdgId']
            s.l2_index  = leptons[1]['index']
            s.l2_jetPtRatiov2  = leptons[1]['jetPtRatiov2']
            s.l2_jetPtRelv2    = leptons[1]['jetPtRelv2']
            s.l2_miniRelIso = leptons[1]['miniRelIso']
            s.l2_dxy = leptons[1]['dxy']
            s.l2_dz = leptons[1]['dz']

            l_pdgs = [abs(leptons[0]['pdgId']), abs(leptons[1]['pdgId'])]
            l_pdgs.sort()
            s.isMuMu = l_pdgs==[13,13]
            s.isEE   = l_pdgs==[11,11]
            s.isEMu  = l_pdgs==[11,13]
            s.isOS   = s.l1_pdgId*s.l2_pdgId<0

            l1 = ROOT.TLorentzVector()
            l1.SetPtEtaPhiM(leptons[0]['pt'], leptons[0]['eta'], leptons[0]['phi'], 0 )
            l2 = ROOT.TLorentzVector()
            l2.SetPtEtaPhiM(leptons[1]['pt'], leptons[1]['eta'], leptons[1]['phi'], 0 )
            dl = l1+l2
            s.dl_pt   = dl.Pt()
            s.dl_eta  = dl.Eta()
            s.dl_phi  = dl.Phi()
            s.dl_mass = dl.M()
            mt2Calc.setLeptons(s.l1_pt, s.l1_eta, s.l1_phi, s.l2_pt, s.l2_eta, s.l2_phi)

            # To check MC truth when looking at the TTZToLLNuNu sample
            if isMC:
              zBoson          = getGenZ(gPart)
              s.zBoson_genPt  = zBoson['pt']  if zBoson is not None else float('nan')
              s.zBoson_genEta = zBoson['eta'] if zBoson is not None else float('nan')

            if options.keepPhotons and s.nPhotonGood > 0:
              gamma = ROOT.TLorentzVector()
              gamma.SetPtEtaPhiM(photons[0]['pt'], photons[0]['eta'], photons[0]['phi'], photons[0]['mass'] )
              dlg = dl + gamma
              s.dlg_mass = dlg.M()

            for i in metVariants:
                mt2Calc.setMet(getattr(s, 'met_pt'+i), getattr(s, 'met_phi', i))
                setattr(s, "dl_mt2ll"+i, mt2Calc.mt2ll())

                if len(jets)>=2:
                    bj0, bj1 = (bJets+nonBJets)[:2]
                    mt2Calc.setBJets(bj0['pt'], bj0['eta'], bj0['phi'], bj1['pt'], bj1['eta'], bj1['phi'])
                    setattr(s, "dl_mt2bb"+i,   mt2Calc.mt2bb())
                    setattr(s, "dl_mt2blbl"+i, mt2Calc.mt2blbl())

                if addSystematicVariations:
                    for var in ['JECUp', 'JECDown', 'JERUp', 'JERDown', 'UnclusteredEnUp', 'UnclusteredEnDown']:
                        mt2Calc.setMet( getattr(s, "met_pt"+i+"_"+var), getattr(s, "met_phi"+i+"_"+var) )
                        setattr(s, "dl_mt2ll"+i+"_"+var,  mt2Calc.mt2ll())
                        bj0_, bj1_ = bj0, bj1
                        if not 'Unclustered' in var:
                            if len(jets_sys[var])>=2:
                                bj0_, bj1_ = (bjets_sys[var]+nonBjets_sys[var])[:2]
                            else: 
                                bj0_, bj1_ = None, None
                        if bj0_ and bj1_:
                            mt2Calc.setBJets(bj0_['pt'], bj0_['eta'], bj0_['phi'], bj1_['pt'], bj1_['eta'], bj1_['phi'])
                            setattr(s, 'dl_mt2bb'  +i+'_'+var, mt2Calc.mt2bb())
                            setattr(s, 'dl_mt2blbl'+i+'_'+var, mt2Calc.mt2blbl())

    if addSystematicVariations:
        # B tagging weights method 1a
        for j in jets:
            btagEff.addBTagEffToJet(j)
        for var in btagEff.btagWeightNames:
            if var!='MC':
                setattr(s, 'reweightBTag_'+var, btagEff.getBTagSF_1a( var, bJets, nonBJets ) )

    # gen information on extra leptons
    if isMC and not options.skipGenLepMatching:
        genSearch.init( gPart )
        # Start with status 1 gen leptons in acceptance
        gLep = filter( lambda p:abs(p['pdgId']) in [11, 13] and p['status']==1 and p['pt']>20 and abs(p['eta'])<2.5, gPart )
        for l in gLep:
            ancestry = [ gPart[x]['pdgId'] for x in genSearch.ancestry( l ) ]
            l["n_D"]   =  sum([ancestry.count(p) for p in D_mesons])
            l["n_B"]   =  sum([ancestry.count(p) for p in B_mesons])
            l["n_W"]   =  sum([ancestry.count(p) for p in [24, -24]])
            l["n_t"]   =  sum([ancestry.count(p) for p in [6, -6]])
            l["n_tau"] =  sum([ancestry.count(p) for p in [15, -15]])
            matched_lep = bestDRMatchInCollection(l, leptons_pt10)
            if matched_lep:
                l["lepGoodMatchIndex"] = matched_lep['index']
                if isSingleLep:
                    l["matchesPromptGoodLepton"] = l["lepGoodMatchIndex"] in [s.l1_index]
                elif isDiLep:
                    l["matchesPromptGoodLepton"] = l["lepGoodMatchIndex"] in [s.l1_index, s.l2_index]
                else:
                    l["matchesPromptGoodLepton"] = 0
            else:
                l["lepGoodMatchIndex"] = -1
                l["matchesPromptGoodLepton"] = 0
#            if      l["n_t"]>0 and l["n_W"]>0 and l["n_B"]==0 and l["n_D"]==0 and l["n_tau"]==0:
#                print "t->W->l"
#            elif    l["n_t"]>0 and l["n_W"]==0 and l["n_B"]>0 and l["n_D"]==0 and l["n_tau"]==0:
#                print "t->b->B->l"
#            elif    l["n_t"]>0 and l["n_W"]==0 and l["n_B"]>0 and l["n_D"]>0 and l["n_tau"]==0:
#                print "t->b->B->D->l"
#            elif    l["n_t"]>0 and l["n_W"]>0 and l["n_B"]==0 and l["n_D"]==0 and l["n_tau"]>0 :
#                print "t->W->tau->l"
#            elif    l["n_t"]>0 and l["n_W"]>0 and l["n_B"]==0 and l["n_D"]>0 and l["n_tau"]==0:
#                print "t->W->c->D->l"
#            elif    l["n_t"]==0 and l["n_W"]==0 and l["n_B"]>0 and l["n_D"]>=0 and l["n_tau"]==0:
#                print l['pdgId'], l['pt'], l['phi'], l['eta'], ",".join(pdgToName( gPart[x]['pdgId']) for x in genSearch.ancestry(l) )
#                for p in genSearch.ancestry(l):
#                    print p, gPart[p]
#            else:
#                pass
                # print l['pdgId'], l['pt'], l['phi'], l['eta'], ",".join(pdgToName(gPart[x]['pdgId']) for x in genSearch.ancestry(l))
        s.nGenLep   = len(gLep)
        for iLep, lep in enumerate(gLep):
            for b in genLepVarNames:
                getattr(s, "GenLep_"+b)[iLep] = lep[b]
                decayMode+="ToHad"
            W_decay.append( decayMode )
        elif W_daughters_pdgId in [ [1,2], [3,4] ]:
            W_decay.append( "Had" )
        else:
            W_decay.append( "Unknown_%i_%i"%W_daughters )

    W_decay.sort()
    prompt_gen_leptons.sort(key = lambda l:-l['pt'] )

    prompt_gen_mu = filter( lambda l:abs(l['pdgId']) == 13, prompt_gen_leptons )
    prompt_gen_e  = filter( lambda l:abs(l['pdgId']) == 11, prompt_gen_leptons )

    logger.info( "GenDecay: %s providing prompt gen mu: %i ele: %i" , bold("/".join(W_decay) ), len(prompt_gen_mu), len(prompt_gen_e) )
    for l in prompt_gen_leptons:
        reco_match = bestDRMatchInCollection( l, filter(lambda p:p['pdgId']==l['pdgId'], all_reco_leps ), deltaRelPt = -1 )
        delta_pt = reco_match['pt'] - l['pt'] if reco_match else float('nan')
        if reco_match is None:
            selected_lepton_match_string = ""
        elif reco_match['pt']==reader.data.l1_pt:
            selected_lepton_match_string = bold("leading")
        elif reco_match['pt']==reader.data.l2_pt:
            selected_lepton_match_string = bold("trailing")
        else:
            selected_lepton_match_string = "Not matched to l1,l2"
        logger.info( "gen prompt %s %s pt %3.2f eta %3.2f all-reco-match %s delta_pt %3.2f matched to: %s", \
            pdgToName(l['pdgId']),l['source'], l['pt'], l['eta'],
            bool(reco_match), delta_pt, selected_lepton_match_string
            )

    # Status 1 gen leptons in acceptance