def cut_hlt(wvz):
    presel = reduce_and(
        wvz["lep_pass_veto"].sum() >= 2,
        wvz["firstgoodvertex"] == 0,
        wvz["passesMETfiltersRun2"],
        np.logical_or(~wvz["isData"], wvz["pass_duplicate_mm_em_ee"]),
    )

    # Check if any of the combination of leptons pass the trigger thresholds
    # Ele 23 12
    # El23 Mu8
    # Mu23 El12
    # Mu 17 8
    # The thresholds are rounded up to 25, 15, or 10

    pt = wvz["lep_pt"][wvz["lep_pass_veto"]]
    pdg = np.abs(wvz["lep_id"][wvz["lep_pass_veto"]])

    ele_pt = pt[pdg == 11]
    mu_pt = pt[pdg == 13]
    triggered = reduce_or(
        reduce_and(wvz["HLT_DoubleEl"], (ele_pt > 25).sum(),
                   (ele_pt > 15).sum() > 1),
        reduce_and(wvz["HLT_MuEG"], (mu_pt > 25).sum(), (ele_pt > 15).sum()),
        reduce_and(wvz["HLT_MuEG"], (ele_pt > 25).sum(), (mu_pt > 10).sum()),
        reduce_and(wvz["HLT_DoubleMu"], (mu_pt > 20).sum(),
                   (mu_pt > 10).sum() > 1),
    )

    return np.logical_and(presel, triggered)
def pass_nominal_lepton_mva_id(wvz):
    pdg = np.abs(wvz["lep_id"])
    pass_el = reduce_and(
        pdg == 11,
        wvz["lep_isMVAwp90IsoPOG"],
        np.abs(wvz["lep_sip3d"]) < 4.0,
        wvz["lep_relIso03EAwLep"] < 0.2,
        wvz["lep_isMVAwpLooseNoIsoPOG"],
    )
    pass_mu = reduce_and(pdg == 13, wvz["lep_isMediumPOG"],
                         np.abs(wvz["lep_relIso04DB"] < 0.15),
                         np.abs(wvz["lep_sip3d"]) < 4.0)
    return reduce_and(wvz["lep_pass_veto"], reduce_or(pass_el, pass_mu))
def pass_vefrom_electron_id(wvz):
    return reduce_and(
        np.abs(wvz["lep_id"]) == 11,
        wvz["lep_isCutBasedIsoVetoPOG"] == 1,
        np.abs(wvz["lep_sip3d"]) < 4.0,
        wvz["lep_pt"] > 10.0,
        np.abs(wvz["lep_eta"]) < 2.5,
    )
def ele_nom_sf(wvz):
    m = reduce_and(wvz["lep_is_nom"], np.abs(wvz["lep_id"]) == 11)
    reco_sf = scale_factors.elec_reco_sf[year](wvz["lep_pt"][m],
                                               wvz["lep_eta"][m])
    id_sf = scale_factors.elec_mva_medium_sf[year](wvz["lep_pt"][m],
                                                   wvz["lep_eta"][m])

    return (reco_sf * id_sf).prod()
def pass_vefrom_muon_id(wwz):
    return reduce_and(
        np.abs(wwz["lep_id"]) == 13,
        wwz["lep_isMediumPOG"] == 1,
        np.abs(wwz["lep_sip3d"]) < 4.0,
        wwz["lep_pt"] > 10.0,
        wwz["lep_relIso04DB"] < 0.25,
        np.abs(wwz["lep_eta"]) < 2.4,
    )
def muon_nom_sf(wvz, year=None):
    m = reduce_and(wvz["lep_is_nom"], np.abs(wvz["lep_id"]) == 13)
    reco_sf = scale_factors.muon_reco_sf[year](wvz["lep_pt"][m],
                                               wvz["lep_eta"][m])

    pt_min = 20.1
    if year == 2018:
        pt_min = 15.1
    id_sf = scale_factors.muon_tightiso_sf[year](np.maximum(
        wvz["lep_pt"][m], pt_min), wvz["lep_eta"][m])

    return (reco_sf * id_sf).prod()
 def is_4_lepton_event(wvz):
     m = reduce_and(wvz["lep_pass_veto"].sum() == 4,
                    np.sign(wvz["lep_id"][wvz["lep_pass_veto"]]).sum() == 0)
     pdg = wvz["lep_id"][wvz["lep_pass_veto"]][m]
     m[m] = reduce_or(
         pdg[:, 0] + pdg[:, 1] == 0,
         pdg[:, 0] + pdg[:, 2] == 0,
         pdg[:, 0] + pdg[:, 3] == 0,
         pdg[:, 1] + pdg[:, 2] == 0,
         pdg[:, 1] + pdg[:, 3] == 0,
         pdg[:, 2] + pdg[:, 3] == 0,
     )
     return m
def pass_nominal_lepton_id(wvz):
    pdg = np.abs(wvz["lep_id"])
    pass_el = reduce_and(pdg == 11, wvz["lep_isCutBasedIsoMediumPOG"])
    pass_mu = reduce_and(pdg == 13, wvz["lep_relIso04DB"] < 0.15)
    return reduce_and(wvz["lep_pass_veto"], reduce_or(pass_el, pass_mu))
def ele_z_cand_sf(wvz):
    m = reduce_and(wvz["lep_is_z"], np.abs(wvz["lep_id"]) == 11)
    return scale_factors.elec_reco_sf[year](wvz["lep_pt"][m],
                                            wvz["lep_eta"][m]).prod()
def cut_four_lepton_pt(wvz):
    pt = wvz["lep_pt"]
    return reduce_and(pt[wvz["lep_is_z"]].max() > 25.0,
                      pt[wvz["lep_is_nom"]].max() > 25.0)
 def veto(i, j):
     return reduce_and(ch[:, i] == -ch[:, j],
                       (p4[:, i] + p4[:, j]).mass < mll_cut)
def run_baby_analysis():
    import uproot
    import uproot_methods
    import numpy as np
    import pandas as pd

    from libwwz.array_utils import reduce_and, reduce_or
    from libwwz.array_utils import awkward_indices
    from libwwz.cut_utils import add_cut
    from libwwz.physics import find_z_pairs
    import libwwz.scale_factors as scale_factors

    import libwwz

    from geeksw.utils.data_loader_tools import TreeWrapper

    def cut_gen_filter(df, sample_name, year):
        if "wwz_amcatnlo" in sample_name and year != 2016:
            return df["nLightLep"] == 4
        return True

    def pass_vefrom_electron_id(wvz):
        return reduce_and(
            np.abs(wvz["lep_id"]) == 11,
            wvz["lep_isCutBasedIsoVetoPOG"] == 1,
            np.abs(wvz["lep_sip3d"]) < 4.0,
            wvz["lep_pt"] > 10.0,
            np.abs(wvz["lep_eta"]) < 2.5,
        )

    def pass_vefrom_muon_id(wwz):
        return reduce_and(
            np.abs(wwz["lep_id"]) == 13,
            wwz["lep_isMediumPOG"] == 1,
            np.abs(wwz["lep_sip3d"]) < 4.0,
            wwz["lep_pt"] > 10.0,
            wwz["lep_relIso04DB"] < 0.25,
            np.abs(wwz["lep_eta"]) < 2.4,
        )

    def pass_vefrom_lepton_id(wvz):
        return reduce_or(pass_vefrom_electron_id(wvz),
                         pass_vefrom_muon_id(wvz))

    def pass_vefrom_lepton_mva_id(wvz):
        return wvz["lep_isVVVVeto"] > 0

    def pass_nominal_lepton_id(wvz):
        pdg = np.abs(wvz["lep_id"])
        pass_el = reduce_and(pdg == 11, wvz["lep_isCutBasedIsoMediumPOG"])
        pass_mu = reduce_and(pdg == 13, wvz["lep_relIso04DB"] < 0.15)
        return reduce_and(wvz["lep_pass_veto"], reduce_or(pass_el, pass_mu))

    def pass_z_lepton_mva_id(wvz):
        pdg = np.abs(wvz["lep_id"])
        pass_el = reduce_and(
            pdg == 11,
            # wvz["lep_isMVAwp90IsoPOG"],
            np.abs(wvz["lep_sip3d"]) < 4.0,
            wvz["lep_relIso03EAwLep"] < 0.2,
            wvz["lep_isMVAwpLooseNoIsoPOG"],
        )
        pass_mu = reduce_and(pdg == 13, wvz["lep_isMediumPOG"],
                             np.abs(wvz["lep_relIso04DB"] < 0.25),
                             np.abs(wvz["lep_sip3d"]) < 4.0)
        return reduce_and(wvz["lep_pass_veto"], reduce_or(pass_el, pass_mu))

    def pass_nominal_lepton_mva_id(wvz):
        pdg = np.abs(wvz["lep_id"])
        pass_el = reduce_and(
            pdg == 11,
            wvz["lep_isMVAwp90IsoPOG"],
            np.abs(wvz["lep_sip3d"]) < 4.0,
            wvz["lep_relIso03EAwLep"] < 0.2,
            wvz["lep_isMVAwpLooseNoIsoPOG"],
        )
        pass_mu = reduce_and(pdg == 13, wvz["lep_isMediumPOG"],
                             np.abs(wvz["lep_relIso04DB"] < 0.15),
                             np.abs(wvz["lep_sip3d"]) < 4.0)
        return reduce_and(wvz["lep_pass_veto"], reduce_or(pass_el, pass_mu))

    def is_4_lepton_event(wvz):
        m = reduce_and(wvz["lep_pass_veto"].sum() == 4,
                       np.sign(wvz["lep_id"][wvz["lep_pass_veto"]]).sum() == 0)
        pdg = wvz["lep_id"][wvz["lep_pass_veto"]][m]
        m[m] = reduce_or(
            pdg[:, 0] + pdg[:, 1] == 0,
            pdg[:, 0] + pdg[:, 2] == 0,
            pdg[:, 0] + pdg[:, 3] == 0,
            pdg[:, 1] + pdg[:, 2] == 0,
            pdg[:, 1] + pdg[:, 3] == 0,
            pdg[:, 2] + pdg[:, 3] == 0,
        )
        return m

    def cut_hlt(wvz):
        presel = reduce_and(
            wvz["lep_pass_veto"].sum() >= 2,
            wvz["firstgoodvertex"] == 0,
            wvz["passesMETfiltersRun2"],
            np.logical_or(~wvz["isData"], wvz["pass_duplicate_mm_em_ee"]),
        )

        # Check if any of the combination of leptons pass the trigger thresholds
        # Ele 23 12
        # El23 Mu8
        # Mu23 El12
        # Mu 17 8
        # The thresholds are rounded up to 25, 15, or 10

        pt = wvz["lep_pt"][wvz["lep_pass_veto"]]
        pdg = np.abs(wvz["lep_id"][wvz["lep_pass_veto"]])

        ele_pt = pt[pdg == 11]
        mu_pt = pt[pdg == 13]
        triggered = reduce_or(
            reduce_and(wvz["HLT_DoubleEl"], (ele_pt > 25).sum(),
                       (ele_pt > 15).sum() > 1),
            reduce_and(wvz["HLT_MuEG"], (mu_pt > 25).sum(),
                       (ele_pt > 15).sum()),
            reduce_and(wvz["HLT_MuEG"], (ele_pt > 25).sum(),
                       (mu_pt > 10).sum()),
            reduce_and(wvz["HLT_DoubleMu"], (mu_pt > 20).sum(),
                       (mu_pt > 10).sum() > 1),
        )

        return np.logical_and(presel, triggered)

    year = 2017
    sample_name = "wwz_4l2v_amcatnlo_1"
    # year = 2016
    # sample_name = "wwz_amcatnlo_1"

    tag = "WVZMVA{0}_v0.1.21".format(year)
    # tag = "WVZMVA{0}_v0.1.15".format(year)
    # tag = "WVZ{0}_v0.1.12.7".format(year)

    root_file_name = "/scratch/rembser/babies/{0}/{1}.root".format(
        tag, sample_name)
    t = uproot.open(root_file_name)["t"]

    entrystop = 10000
    wvz = TreeWrapper(t, n_max_events=entrystop, extendable=True)

    wvz["lep_mass"] = 0.0

    wvz["lep_p4_"] = uproot_methods.TLorentzVectorArray.from_ptetaphim(
        wvz["lep_pt"], wvz["lep_eta"], wvz["lep_phi"], wvz["lep_mass"])

    use_mva = True

    if use_mva:
        wvz["lep_pass_veto"] = pass_vefrom_lepton_mva_id(wvz)
        wvz["lep_pass_z_id"] = pass_z_lepton_mva_id(wvz)
        wvz["lep_pass_nominal"] = pass_nominal_lepton_mva_id(wvz)
    else:
        wvz["lep_pass_veto"] = pass_vefrom_lepton_id(wvz)
        wvz["lep_pass_z_id"] = wvz["lep_pass_veto"]
        wvz["lep_pass_nominal"] = pass_nominal_lepton_id(wvz)

    wvz["evt_weight"] = libwwz.baby_analysis.event_weight(
        wvz, sample_name, year, tag)
    wvz["lep_idx_"] = awkward_indices(wvz["lep_pt"])

    lep_z_id_is_z = find_z_pairs(wvz["lep_p4_"][wvz["lep_pass_z_id"]],
                                 wvz["lep_id"][wvz["lep_pass_z_id"]])

    wvz["lep_is_z"] = wvz["lep_pt"] < 0.0
    wvz["lep_is_z"][wvz["lep_idx_"][wvz["lep_pass_z_id"]]
                    [lep_z_id_is_z]] = True

    wvz["z_mass"] = wvz["lep_p4_"][wvz["lep_is_z"]].sum().mass

    wvz["lep_is_nom"] = np.logical_and(~wvz["lep_is_z"],
                                       wvz["lep_pass_nominal"])

    wvz["lep_et"] = wvz["lep_energy"] / np.cosh(wvz["lep_eta"])
    wvz["lep_mt"] = np.sqrt(2.0 * wvz["met_pt"] * wvz["lep_et"] *
                            (1.0 - np.cos(wvz["lep_phi"] - wvz["met_phi"])))

    def cut_four_leptons_low_mll(wvz):
        mask = reduce_or(wvz["lep_is_z"], wvz["lep_is_nom"])

        res = mask.sum() == 4

        p4 = wvz["lep_p4_"][mask][res]
        ch = np.sign(wvz["lep_id"][mask][res])

        mll_cut = 12.0

        combinations = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]

        def veto(i, j):
            return reduce_and(ch[:, i] == -ch[:, j],
                              (p4[:, i] + p4[:, j]).mass < mll_cut)

        res[res] = ~reduce_or(*[veto(i, j) for i, j in combinations])

        return res

    def cut_four_lepton_pt(wvz):
        pt = wvz["lep_pt"]
        return reduce_and(pt[wvz["lep_is_z"]].max() > 25.0,
                          pt[wvz["lep_is_nom"]].max() > 25.0)

    wvz["has_two_lep_nom"] = reduce_and(
        wvz["lep_is_z"].sum() == 2, wvz["lep_is_nom"].sum() == 2,
        wvz["lep_id"][wvz["lep_is_nom"]].prod() < 0.0)

    wvz["is_SFOS"] = wvz["lep_id"][wvz["lep_is_nom"]].prod() != -143
    wvz["is_on_z"] = np.logical_and(
        np.abs(wvz["lep_p4_"][wvz["lep_is_nom"]].sum().mass - 91.1876) < 10.0,
        wvz["lep_id"][wvz["lep_is_nom"]].sum() == 0,
    )

    wvz["is_high_mt"] = np.logical_and(
        (wvz["lep_mt"][wvz["lep_is_nom"]] > 40).sum() >= 1,
        (wvz["lep_mt"][wvz["lep_is_nom"]] > 20).sum() >= 2)

    # Start with cutflow
    tgt = pd.DataFrame(index=np.arange(len(wvz["evt"])))
    tgt = add_cut(tgt, "Root", True)
    tgt = add_cut(tgt,
                  "EventWeight",
                  True,
                  previous_cut="Root",
                  weight=wvz["evt_weight"])
    tgt = add_cut(tgt,
                  "GenFilter",
                  cut_gen_filter(wvz, sample_name, year),
                  previous_cut="EventWeight")

    # List of common four lepton related selections
    tgt = add_cut(tgt, "Weight", True, previous_cut="GenFilter")

    def ele_z_cand_sf(wvz):
        m = reduce_and(wvz["lep_is_z"], np.abs(wvz["lep_id"]) == 11)
        return scale_factors.elec_reco_sf[year](wvz["lep_pt"][m],
                                                wvz["lep_eta"][m]).prod()

    def ele_nom_sf(wvz):
        m = reduce_and(wvz["lep_is_nom"], np.abs(wvz["lep_id"]) == 11)
        reco_sf = scale_factors.elec_reco_sf[year](wvz["lep_pt"][m],
                                                   wvz["lep_eta"][m])
        id_sf = scale_factors.elec_mva_medium_sf[year](wvz["lep_pt"][m],
                                                       wvz["lep_eta"][m])

        return (reco_sf * id_sf).prod()

    def muon_z_cand_sf(wvz, year=None):
        m = reduce_and(wvz["lep_is_z"], np.abs(wvz["lep_id"]) == 13)
        reco_sf = scale_factors.muon_reco_sf[year](wvz["lep_pt"][m],
                                                   wvz["lep_eta"][m])

        pt_min = 20.1
        if year == 2018:
            pt_min = 15.1
        id_sf = scale_factors.muon_looseiso_sf[year](np.maximum(
            wvz["lep_pt"][m], pt_min), wvz["lep_eta"][m])

        return (reco_sf * id_sf).prod()

    def muon_nom_sf(wvz, year=None):
        m = reduce_and(wvz["lep_is_nom"], np.abs(wvz["lep_id"]) == 13)
        reco_sf = scale_factors.muon_reco_sf[year](wvz["lep_pt"][m],
                                                   wvz["lep_eta"][m])

        pt_min = 20.1
        if year == 2018:
            pt_min = 15.1
        id_sf = scale_factors.muon_tightiso_sf[year](np.maximum(
            wvz["lep_pt"][m], pt_min), wvz["lep_eta"][m])

        return (reco_sf * id_sf).prod()

    tgt = add_cut(tgt,
                  "FourLeptons",
                  is_4_lepton_event(wvz),
                  previous_cut="Weight")

    tgt = add_cut(tgt,
                  "ElectronZCandSF",
                  True,
                  previous_cut="FourLeptons",
                  weight=ele_z_cand_sf(wvz))
    tgt = add_cut(tgt,
                  "MuonZCandSF",
                  True,
                  previous_cut="ElectronZCandSF",
                  weight=muon_z_cand_sf(wvz, year=year))
    tgt = add_cut(tgt,
                  "ElectronNomSF",
                  True,
                  previous_cut="MuonZCandSF",
                  weight=ele_nom_sf(wvz))
    tgt = add_cut(tgt,
                  "MuonNomSF",
                  True,
                  previous_cut="ElectronNomSF",
                  weight=muon_nom_sf(wvz, year=year))

    tgt = add_cut(tgt, "CutHLT", cut_hlt(wvz), previous_cut="MuonNomSF")
    tgt = add_cut(tgt,
                  "FindTwoOSNominalLeptons",
                  wvz["has_two_lep_nom"],
                  previous_cut="CutHLT")
    tgt = add_cut(tgt,
                  "Cut4LepLowMll",
                  cut_four_leptons_low_mll(wvz),
                  previous_cut="FindTwoOSNominalLeptons")
    tgt = add_cut(tgt,
                  "Cut4LepLeptonPt",
                  cut_four_lepton_pt(wvz),
                  previous_cut="Cut4LepLowMll")
    tgt = add_cut(tgt,
                  "FindZCandLeptons",
                  True,
                  previous_cut="Cut4LepLeptonPt")
    tgt = add_cut(tgt,
                  "Cut4LepBVeto",
                  wvz["nb"] == 0,
                  previous_cut="FindZCandLeptons",
                  weight=wvz["weight_btagsf"])

    # emu channel
    tgt = add_cut(tgt,
                  "ChannelEMu",
                  ~wvz["is_SFOS"],
                  previous_cut="Cut4LepBVeto")

    # OnZ channel
    tgt = add_cut(tgt,
                  "ChannelOnZ",
                  wvz["is_on_z"],
                  previous_cut="Cut4LepBVeto")
    tgt = add_cut(tgt,
                  "ChannelOnZNjet",
                  wvz["nj"] >= 2,
                  previous_cut="ChannelOnZ")

    # OffZ channel
    tgt = add_cut(tgt,
                  "ChannelOffZ",
                  np.logical_and(~wvz["is_on_z"], wvz["is_SFOS"]),
                  previous_cut="Cut4LepBVeto")
    tgt = add_cut(tgt,
                  "ChannelOffZHighMET",
                  wvz["met_pt"] > 100.0,
                  previous_cut="ChannelOffZ")
    tgt = add_cut(tgt,
                  "ChannelOffZLowMET",
                  wvz["met_pt"] <= 100.0,
                  previous_cut="ChannelOffZ")
    tgt = add_cut(tgt,
                  "ChannelOffZHighMT",
                  wvz["is_high_mt"],
                  previous_cut="ChannelOffZ")
    tgt = add_cut(tgt,
                  "ChannelOffZLowMT",
                  ~wvz["is_high_mt"],
                  previous_cut="ChannelOffZ")

    return tgt