Exemple #1
0
    def get_objects(ievent):
        visible_momentum = MadMinerParticle()
        for p in (
            electrons_all_events[ievent]
            + jets_all_events[ievent]
            + muons_all_events[ievent]
            + leptons_all_events[ievent]
        ):
            visible_momentum += p
        all_momentum = visible_momentum + met_all_events[ievent][0]

        objects = math_commands()
        objects.update(
            {
                "e": electrons_all_events[ievent],
                "j": jets_all_events[ievent],
                "a": photons_all_events[ievent],
                "mu": muons_all_events[ievent],
                "l": leptons_all_events[ievent],
                "met": met_all_events[ievent][0],
                "visible": visible_momentum,
                "all": all_momentum,
                "boost_to_com": lambda momentum: momentum.boost(all_momentum.boost_vector()),
            }
        )

        return objects
Exemple #2
0
def _get_particles_charged(tree, name, mass, pdgid_positive_charge, pt_min,
                           eta_max):
    pts = tree.array(f"{name}.PT")
    etas = tree.array(f"{name}.Eta")
    phis = tree.array(f"{name}.Phi")
    charges = tree.array(f"{name}.Charge")

    all_particles = []

    for ievent in range(len(pts)):
        event_particles = []

        for pt, eta, phi, charge in zip(pts[ievent], etas[ievent],
                                        phis[ievent], charges[ievent]):

            if pt_min is not None and pt < pt_min:
                continue
            if eta_max is not None and abs(eta) > eta_max:
                continue

            pdgid = pdgid_positive_charge if charge >= 0.0 else -pdgid_positive_charge

            particle = MadMinerParticle.from_rhophietatau(pt, phi, eta, mass)
            particle.set_pdgid(pdgid)
            event_particles.append(particle)

        all_particles.append(event_particles)

    return all_particles
Exemple #3
0
def _get_particles_photons(tree, pt_min, eta_max):
    pts = tree.array("Photon.PT")
    etas = tree.array("Photon.Eta")
    phis = tree.array("Photon.Phi")
    es = tree.array("Photon.E")

    all_particles = []

    for ievent in range(len(pts)):
        event_particles = []

        for pt, eta, phi, e in zip(pts[ievent], etas[ievent], phis[ievent],
                                   es[ievent]):

            if pt_min is not None and pt < pt_min:
                continue
            if eta_max is not None and abs(eta) > eta_max:
                continue

            particle = MadMinerParticle.from_rhophietat(pt, phi, eta, e)
            particle.set_pdgid(22)
            event_particles.append(particle)

        all_particles.append(event_particles)

    return all_particles
Exemple #4
0
def _get_particles_truth(tree, pt_min, eta_max, included_pdgids=None):
    es = tree.array("Particle.E")
    pts = tree.array("Particle.PT")
    etas = tree.array("Particle.Eta")
    phis = tree.array("Particle.Phi")
    charges = tree.array("Particle.Charge")
    pdgids = tree.array("Particle.PID")

    all_particles = []

    for ievent in range(len(pts)):
        event_particles = []

        for e, pt, eta, phi, pdgid in zip(es[ievent], pts[ievent],
                                          etas[ievent], phis[ievent],
                                          pdgids[ievent]):

            if pt_min is not None and pt < pt_min:
                continue
            if eta_max is not None and abs(eta) > eta_max:
                continue
            if (included_pdgids is not None) and (pdgid
                                                  not in included_pdgids):
                continue

            particle = MadMinerParticle.from_rhophietat(pt, phi, eta, e)
            particle.set_pdgid(pdgid)
            event_particles.append(particle)

        all_particles.append(event_particles)

    return all_particles
Exemple #5
0
def _parse_xml_event(event, sampling_benchmark):
    # Initialize weights and momenta
    weights = OrderedDict()
    particles = []
    global_event_data = {}

    # Split kinematics part in tag line and momenta
    event_text = event.text
    tag_line = None
    particle_lines = []
    for line in event_text.splitlines():
        elements = line.split()
        if len(elements) < 2:
            continue
        if tag_line is None:
            tag_line = elements
        else:
            particle_lines.append(elements)

    # Parse tag
    assert tag_line is not None
    global_event_data["n_particles"] = float(tag_line[0])
    weights[sampling_benchmark] = float(tag_line[2])
    global_event_data["scale"] = float(tag_line[3])
    global_event_data["alpha_qed"] = float(tag_line[4])
    global_event_data["alpha_qcd"] = float(tag_line[5])

    # Parse momenta
    for elements in particle_lines:
        if len(elements) < 10:
            continue
        status = int(elements[1])
        if elements[0] == "#aMCatNLO":
            elements = elements[1:]
        if status == 1:
            pdgid = int(elements[0])
            px = float(elements[6])
            py = float(elements[7])
            pz = float(elements[8])
            e = float(elements[9])
            spin = float(elements[12])
            particle = MadMinerParticle()
            particle.setpxpypze(px, py, pz, e)
            particle.set_pdgid(pdgid)
            particle.set_spin(spin)
            particles.append(particle)

    # Weights
    if event.find("rwgt") is not None:
        for weight in event.find("rwgt").findall("wgt"):
            weight_id, weight_value = weight.attrib["id"], float(weight.text)
            weights[weight_id] = weight_value

    return particles, weights, global_event_data
Exemple #6
0
def _get_particles_truth_jets(tree, pt_min, eta_max):
    pts = tree.array("GenJet.PT")
    etas = tree.array("GenJet.Eta")
    phis = tree.array("GenJet.Phi")
    masses = tree.array("GenJet.Mass")

    all_particles = []

    for ievent in range(len(pts)):
        event_particles = []

        for pt, eta, phi, mass in zip(pts[ievent], etas[ievent], phis[ievent], masses[ievent]):

            if pt_min is not None and pt < pt_min:
                continue
            if eta_max is not None and abs(eta) > eta_max:
                continue

            particle = MadMinerParticle()
            particle.setptetaphim(pt, eta, phi, mass)
            particle.set_pdgid(9)
            event_particles.append(particle)

        all_particles.append(event_particles)

    return all_particles
Exemple #7
0
def _get_particles_truth_leptons(tree, pt_min_e, eta_max_e, pt_min_mu, eta_max_mu):
    es = tree.array("Particle.E")
    pts = tree.array("Particle.PT")
    etas = tree.array("Particle.Eta")
    phis = tree.array("Particle.Phi")
    charges = tree.array("Particle.Charge")
    pdgids = tree.array("Particle.PID")

    all_particles = []

    for ievent in range(len(pts)):
        event_particles = []

        for e, pt, eta, phi, pdgid in zip(es[ievent], pts[ievent], etas[ievent], phis[ievent], pdgids[ievent]):
            if pdgid not in [11, 13, -11, -13]:
                continue
            if pdgid in [11, -11] and (pt_min_e is not None and pt < pt_min_e):
                continue
            if pdgid in [11, -11] and (eta_max_e is not None and abs(eta) > eta_max_e):
                continue
            if pdgid in [13, -13] and (pt_min_mu is not None and pt < pt_min_mu):
                continue
            if pdgid in [13, -13] and (eta_max_mu is not None and abs(eta) > eta_max_mu):
                continue

            particle = MadMinerParticle()
            particle.setptetaphie(pt, eta, phi, e)
            particle.set_pdgid(pdgid)
            event_particles.append(particle)

        all_particles.append(event_particles)

    return all_particles
Exemple #8
0
def _get_particles_met(tree):
    mets = tree.array("MissingET.MET")
    phis = tree.array("MissingET.Phi")

    all_particles = []

    for ievent in range(len(mets)):
        event_particles = []

        for met, phi in zip(mets[ievent], phis[ievent]):
            particle = MadMinerParticle.from_rhophietatau(met, phi, 0.0, 0.0)
            particle.set_pdgid(0)
            event_particles.append(particle)

        all_particles.append(event_particles)

    return all_particles
Exemple #9
0
def _get_particles_truth_jets(tree, pt_min, eta_max):
    pts = tree.array("GenJet.PT")
    etas = tree.array("GenJet.Eta")
    phis = tree.array("GenJet.Phi")
    masses = tree.array("GenJet.Mass")
    try:
        tau_tags = tree.array("GenJet.TauTag")
    except:
        logger.warning(
            "Did not find tau-tag information for GenJets in Delphes ROOT file."
        )
        tau_tags = [0 for _ in range(len(pts))]
    try:
        b_tags = tree.array("GenJet.BTag")
    except:
        logger.warning(
            "Did not find b-tag information for GenJets in Delphes ROOT file.")
        b_tags = [0 for _ in range(len(pts))]

    all_particles = []

    for ievent in range(len(pts)):
        event_particles = []

        for pt, eta, phi, mass, tau_tag, b_tag in zip(
                pts[ievent], etas[ievent], phis[ievent], masses[ievent],
                tau_tags[ievent], b_tags[ievent]):

            if pt_min is not None and pt < pt_min:
                continue
            if eta_max is not None and abs(eta) > eta_max:
                continue

            particle = MadMinerParticle()
            particle.setptetaphim(pt, eta, phi, mass)
            particle.set_pdgid(9)
            particle.set_tags(tau_tag >= 1, b_tag >= 1, False)
            event_particles.append(particle)

        all_particles.append(event_particles)

    return all_particles
Exemple #10
0
def _get_particles_truth_leptons(tree, pt_min_e, eta_max_e, pt_min_mu,
                                 eta_max_mu):
    ids_e = {int(p.pdgid) for p in Particle.findall(pdg_name="e")}
    ids_mu = {int(p.pdgid) for p in Particle.findall(pdg_name="mu")}
    es = tree.array("Particle.E")
    pts = tree.array("Particle.PT")
    etas = tree.array("Particle.Eta")
    phis = tree.array("Particle.Phi")
    charges = tree.array("Particle.Charge")
    pdgids = tree.array("Particle.PID")

    all_particles = []

    for ievent in range(len(pts)):
        event_particles = []

        for e, pt, eta, phi, pdgid in zip(es[ievent], pts[ievent],
                                          etas[ievent], phis[ievent],
                                          pdgids[ievent]):
            if pdgid not in {*ids_e, *ids_mu}:
                continue
            if pdgid in ids_e and (pt_min_e is not None and pt < pt_min_e):
                continue
            if pdgid in ids_e and (eta_max_e is not None
                                   and abs(eta) > eta_max_e):
                continue
            if pdgid in ids_mu and (pt_min_mu is not None and pt < pt_min_mu):
                continue
            if pdgid in ids_mu and (eta_max_mu is not None
                                    and abs(eta) > eta_max_mu):
                continue

            particle = MadMinerParticle.from_rhophietat(pt, phi, eta, e)
            particle.set_pdgid(pdgid)
            event_particles.append(particle)

        all_particles.append(event_particles)

    return all_particles
Exemple #11
0
def _get_particles_truth_met(tree):
    mets = tree.array("GenMissingET.MET")
    phis = tree.array("GenMissingET.Phi")

    all_particles = []

    for ievent in range(len(mets)):
        event_particles = []

        for met, phi in zip(mets[ievent], phis[ievent]):
            particle = MadMinerParticle()
            particle.setptetaphim(met, 0.0, phi, 0.0)
            particle.set_pdgid(0)
            event_particles.append(particle)

        all_particles.append(event_particles)

    return all_particles
Exemple #12
0
def _parse_events_text(filename, sampling_benchmark):
    # Initialize weights and momenta
    weights = OrderedDict()
    particles = []

    # Some tags so that we know where in the event we are
    do_tag = False
    do_momenta = False
    do_reweight = False

    # Event
    n_events = 0

    reset_event = False

    # Loop through lines in Event
    with open(filename, "r") as file:
        for line in file.readlines():
            # Clean up line
            try:
                line = line.split("#")[0]
            except:
                pass
            line = line.strip()
            elements = line.split()

            # Skip empty/commented out lines
            if len(line) == 0 or len(elements) == 0:
                continue

            # End of LHE file
            elif line == "</LesHouchesEvents>":
                return

            # Beginning of event
            elif line == "<event>":
                # Initialize weights and momenta
                weights = OrderedDict()
                particles = []

                # Some tags so that we know where in the event we are
                do_tag = True
                do_momenta = False
                do_reweight = False

            # End of event
            elif line == "</event>":
                n_events += 1
                if n_events % 10000 == 0:
                    logger.debug("%s events parsed", n_events)

                yield particles, weights

                # Reset weights and momenta
                weights = OrderedDict()
                particles = []

                # Some tags so that we know where in the event we are
                do_tag = False
                do_momenta = False
                do_reweight = False

            # Beginning of unimportant block
            elif line == "<mgrwt>":
                do_tag = False
                do_momenta = False
                do_reweight = False

            # Beginning of weight block
            elif line == "<rwgt>":
                do_tag = False
                do_momenta = False
                do_reweight = True

            # End of weight block
            elif line == "</rwgt>":
                do_tag = False
                do_momenta = False
                do_reweight = False

            # Read tag -> first weight
            elif do_tag:
                weights[sampling_benchmark] = float(elements[2])

                do_tag = False
                do_momenta = True
                do_reweight = False

            # Read Momenta and store as 4-vector
            elif do_momenta:
                status = int(elements[1])
                if status == 1:
                    pdgid = int(elements[0])
                    px = float(elements[6])
                    py = float(elements[7])
                    pz = float(elements[8])
                    e = float(elements[9])
                    particle = MadMinerParticle()
                    particle.setpxpypze(px, py, pz, e)
                    particle.set_pdgid(pdgid)
                    particles.append(particle)

            # Read reweighted weights
            elif do_reweight:
                rwgtid = line[line.find("<") +
                              1:line.find(">")].split("=")[1][1:-1]
                rwgtval = float(line[line.find(">") +
                                     1:line.find("<",
                                                 line.find("<") + 1)])
                weights[rwgtid] = rwgtval
Exemple #13
0
def _get_objects(particles):
    # Find visible particles
    electrons = []
    muons = []
    taus = []
    photons = []
    jets = []
    leptons = []
    neutrinos = []
    unstables = []
    invisibles = []

    for particle in particles:
        pdgid = abs(particle.pdgid)
        if pdgid in [1, 2, 3, 4, 5, 6, 9, 21]:
            jets.append(particle)
        elif pdgid == 11:
            electrons.append(particle)
            leptons.append(particle)
        elif pdgid == 13:
            muons.append(particle)
            leptons.append(particle)
        elif pdgid == 15:
            taus.append(particle)
        elif pdgid == 22:
            photons.append(particle)
        elif pdgid in [12, 14, 16]:
            neutrinos.append(particle)
            invisibles.append(particle)
        elif pdgid in [23, 24, 25]:
            unstables.append(particle)
        else:
            logger.warning("Unknown particle with PDG id %s, treating as invisible!")
            invisibles.append(particle)

    # Sort by pT
    electrons = sorted(electrons, reverse=True, key=lambda x: x.pt)
    muons = sorted(muons, reverse=True, key=lambda x: x.pt)
    taus = sorted(taus, reverse=True, key=lambda x: x.pt)
    photons = sorted(photons, reverse=True, key=lambda x: x.pt)
    leptons = sorted(leptons, reverse=True, key=lambda x: x.pt)
    neutrinos = sorted(neutrinos, reverse=True, key=lambda x: x.pt)
    jets = sorted(jets, reverse=True, key=lambda x: x.pt)

    # MET
    visible_sum = MadMinerParticle()
    visible_sum.setpxpypze(0.0, 0.0, 0.0, 0.0)

    for particle in particles:
        pdgid = abs(particle.pdgid)
        if pdgid in [1, 2, 3, 4, 5, 6, 9, 11, 13, 15, 21, 22, 23, 24, 25]:
            visible_sum += particle

    met = MadMinerParticle()
    met.setpxpypze(-visible_sum.px, -visible_sum.px, 0.0, visible_sum.pt)

    # Build objects
    objects = math_commands()
    objects.update(
        {
            "p": particles,
            "e": electrons,
            "j": jets,
            "a": photons,
            "mu": muons,
            "tau": taus,
            "l": leptons,
            "met": met,
            "v": neutrinos,
        }
    )

    return objects
    def get_objects(ievent):


        visible_momentum = MadMinerParticle()
        for p in (
            electrons_all_events[ievent]
            + jets_all_events[ievent]
            + muons_all_events[ievent]
            + photons_all_events[ievent]
        ):
            visible_momentum += p
        all_momentum = visible_momentum + met_all_events[ievent][0]

        objects = math_commands()
        objects.update(
            {
                "e": electrons_all_events[ievent],
                "j": jets_all_events[ievent],
                "a": photons_all_events[ievent],
                "mu": muons_all_events[ievent],
                "l": leptons_all_events[ievent],
                "met": met_all_events[ievent][0],
                "visible": visible_momentum,
                "all": all_momentum,
                "boost_to_com": lambda momentum: momentum.boost(all_momentum.boost_vector()),
            }
        )

        ##################### PREPARE FUNCTIONS TO FIND BEST ZZ CANDIDATE #####################

        #find same flavour opposite sign lepton pairs,
        #given the list of electrons or muons in an event
        #returns all possible SFOS pairs ([pos_idx, neg_idx],...)
        #which satisfy invariant mass cuts
        def find_Z_cand(cand_list, part_list):
            #positively and negatively charged leptons, and their
            idx_pos = []
            cand_pos = []
            idx_neg = []
            cand_neg = []
            for idx, (is_cand, part) in enumerate(zip(cand_list, part_list)):
                #checking if the lepton is a candidate
                if part.charge > 0:
                    idx_pos.append(idx)
                    cand_pos.append(is_cand)
                if part.charge < 0:
                    idx_neg.append(idx)
                    cand_neg.append(is_cand)

            z_cand_list = []
            for candpair, pair in zip(itertools.product(cand_pos, cand_neg), itertools.product(idx_pos, idx_neg)):
                iscand = candpair[0]*candpair[1] #1 only if both are candidates
                #cut invariant mass
                invm = (part_list[pair[0]] + part_list[pair[1]]).m
                if invm < 120 and invm > 12:
                    z_cand_list.append([pair[0],pair[1]])

            return z_cand_list #[[pos_idx,neg_idx], [pos_idx,neg_idx], ...]

        #find pairs of SFOS pairs with no leptons in common
        #keep track of their different flavours
        #order of Z1 and Z2 is not important (each only counted once)
        def find_ZZ_cand(Z_cand_e_list, Z_cand_mu_list):
            ZZ_cand_ee = []; ZZ_cand_mm = []; ZZ_cand_em = []
            #same flavour e
            for Zcand1,Zcand2 in itertools.product(Z_cand_e_list,Z_cand_e_list):
                if not any(x in Zcand1 for x in Zcand2):
                    ZZ_cand_ee.append([Zcand1[0], Zcand1[1], Zcand2[0], Zcand2[1]])

            #same flavour mu
            for Zcand1,Zcand2 in itertools.product(Z_cand_mu_list,Z_cand_mu_list):
                if not any(x in Zcand1 for x in Zcand2):
                    ZZ_cand_mm.append([Zcand1[0], Zcand1[1], Zcand2[0], Zcand2[1]])

            #different flavour
            for Zcand1,Zcand2 in itertools.product(Z_cand_e_list,Z_cand_mu_list):
                ZZ_cand_em.append([Zcand1[0], Zcand1[1], Zcand2[0], Zcand2[1]])

            return ZZ_cand_ee, ZZ_cand_mm, ZZ_cand_em

        #return the list of particles in the correct order:
        #first list with flavour of first Z, second flavour of second Z
        def set_flavours_lists(part_list_e, part_list_mu, flavours):
            if flavours == "ee":
                part_list1 = part_list_e
                part_list2 = part_list_e
            elif flavours == "mm":
                part_list1 = part_list_mu
                part_list2 = part_list_mu
            elif flavours == "em":
                part_list1 = part_list_e
                part_list2 = part_list_mu
            elif flavours == "me":
                part_list1 = part_list_mu
                part_list2 = part_list_e
            else:
                print("set_flavours_lists: flavour not valid: choose between ee, mm, em")
                return
            return part_list1, part_list2

        #return the leptons corresponding to the index in ZZcand
        #taking into account the flavours
        def ZZidx_to_leps(ZZcand, part_list_e, part_list_mu, flavours):
            part_list1, part_list2 = set_flavours_lists(part_list_e, part_list_mu, flavours)
            leps = [part_list1[ZZcand[0]], part_list1[ZZcand[1]], part_list2[ZZcand[2]], part_list2[ZZcand[3]]]
            return leps

        #reorder the two Z in each pair: first the one with closest mass to Z
        #keep track of the possible swapping in case of different flavours
        def Z1Z2_ordering(ZZcand, part_list_e, part_list_mu, flavours):
            leps = ZZidx_to_leps(ZZcand, part_list_e, part_list_mu, flavours)
            #compute invariant masses of each Z
            mz_p1 = (leps[0] + leps[1]).m
            mz_p2 = (leps[2] + leps[3]).m
            #order accordingly to closest mass to Z mass
            if min([mz_p1,mz_p2], key=lambda x:abs(x-91.2), default=-1) == mz_p1:
                z1z2 = ZZcand
                swapped = False
            else:
                z1z2 = [ZZcand[2],ZZcand[3],ZZcand[0],ZZcand[1]]
                swapped = True
            return(z1z2, swapped)

        #apply cuts to ZZ candidate
        #consider differently the case of same flavour ZZ
        def ZZ_cuts(ZZcand, part_list_e, part_list_mu, flavours, isSF):
            leps = ZZidx_to_leps(ZZcand, part_list_e, part_list_mu, flavours)
            #Z1 mass
            mz1 = (leps[0] + leps[1]).m
            if not mz1 > 40:
                #print("fail mz1 mass cut")
                return False
            #leptons pt
            leps_pt_sort = sorted(leps, key=lambda x:x.pt)
            if not (leps_pt_sort[3].pt > 20 and leps_pt_sort[2].pt > 10):
                #print("fail leptons pt cut")
                #print("leptons pt: ", [a.pt for a in leps_pt_sort])
                return False
            #OS invariant mass (pos, neg, pos, neg)
            mza = (leps[0]+leps[3]).m
            mzb = (leps[1]+leps[2]).m
            mz2 = (leps[2]+leps[3]).m
            if not (mza > 4 and mzb > 4 and mz2 > 4):
                #print("fail os cut")
                return False
            #4l invariant mass
            m4l = (leps[0]+leps[1]+leps[2]+leps[3]).m
            #print("m4l: ", m4l)
            if not m4l>70:
                #print("fail m4l cut")
                return False
            #same flavour cut
            if isSF == True:
                mz_pdg = 91.2
                mzab_ord = [mza, mzb] if min([mza,mzb], key=lambda x:abs(x-mz_pdg)) == mza else [mzb,mza]
                if (abs(mzab_ord[0]-mz_pdg) < abs(mz1-mz_pdg) and mzb < mzab_ord[0]):
                    #print("fail SF cut")
                    return False
            #if candidate passes all cuts
            return True

        #choose ZZ candidate for which Z1 has mass closest to Z
        #keep track of the flavour of Z1 and Z2
        def choose_final_ZZ(ZZlist, part_list_e, part_list_mu, flavourslist):
            if len(ZZlist) == 1:
                return ZZlist[0], flavourslist[0]
            else:
                mz1list = []
                for ZZcand, flavours in zip(ZZlist,flavourslist):
                    part_list1, part_list2 = set_flavours_lists(part_list_e, part_list_mu, flavours)
                    mz1 = (part_list1[ZZcand[0]] + part_list1[ZZcand[1]]).m
                    mz1list.append(mz1)
                mz1min = min(mz1list, key=lambda x:abs(x-91.2))
                idx = mz1list.index(mz1min)
                return ZZlist[idx], flavourslist[idx]

        ##################### MAIN CODE TO FIND BEST ZZ CANDIDATE #####################
        #default values
        isZZcand = 0
        lep1 = MadMinerParticle(); lep2 = MadMinerParticle(); lep3 = MadMinerParticle(); lep4 = MadMinerParticle()

        #list of candidates electrons/muons: 1 if candidate, 0 if not
        candidate_es = np.ones(len(objects["e"]))
        candidate_mus = np.ones(len(objects["mu"]))
        #print(len(objects["e"]), len(objects["mu"]))

        #find candidate leptons: eta and pt cuts (to be checked)
        for idx, el in enumerate(objects["e"]):
            if not (abs(el.eta) < 2.5 and el.pt > 7):
                candidate_es[idx] = 0
        for idx, mu in enumerate(objects["mu"]):
            if not (abs(mu.eta) < 2.4 and mu.pt > 5):
                candidate_mus[idx] = 0

        #find Z candidates
        e_Z_cand = find_Z_cand(candidate_es, objects["e"])
        mu_Z_cand = find_Z_cand(candidate_mus, objects["mu"])

        #find ZZ candidates
        ZZ_cand_ee_list, ZZ_cand_mm_list, ZZ_cand_em_list = find_ZZ_cand(e_Z_cand,mu_Z_cand)
 
        #initialise lists for ZZ candidates which pass cuts, and keep track of flavours
        ZZ_cands_final = []
        ZZ_cands_final_flavours = []

        #same flavours, electrons
        for ZZ_cand_ee in ZZ_cand_ee_list:
            ZZ_cand_ee, swapped = Z1Z2_ordering(ZZ_cand_ee, objects["e"], objects["mu"], flavours="ee")
            #apply cuts
            if ZZ_cuts(ZZ_cand_ee, objects["e"], objects["mu"], flavours="ee", isSF=True) == True:
                ZZ_cands_final.append(ZZ_cand_ee)
                ZZ_cands_final_flavours.append("ee")
        #same flavours, muons
        for ZZ_cand_mm in ZZ_cand_mm_list:
            ZZ_cand_mm, swapped = Z1Z2_ordering(ZZ_cand_mm, objects["e"], objects["mu"], flavours="mm")
            #apply cuts
            if ZZ_cuts(ZZ_cand_mm, objects["e"], objects["mu"], flavours="mm", isSF=True) == True:
                ZZ_cands_final.append(ZZ_cand_mm)
                ZZ_cands_final_flavours.append("mm")
        #different flavours
        for ZZ_cand_em in ZZ_cand_em_list:
            ZZ_cand_em, swapped = Z1Z2_ordering(ZZ_cand_em, objects["e"], objects["mu"], flavours="em")
            #apply cuts, careful when swapping em/me
            flavours_OF = "em" if swapped==False else "me"
            if ZZ_cuts(ZZ_cand_em, objects["e"], objects["mu"], flavours=flavours_OF, isSF=False) == True:
                ZZ_cands_final.append(ZZ_cand_em)
                ZZ_cands_final_flavours.append(flavours_OF)

        #find final best ZZ candidate
        #if more than one ZZ candidate is left: choose the one with Z1 mass closest to MZ

        def printlep(lep, name):
            #print(name, " = [", lep.px, ",", lep.py, ",", lep.pz, "]")
            print("[", lep.e,",", lep.px, ",", lep.py, ",", lep.pz, "]")
            return
          

        if len(ZZ_cands_final) > 0:
            isZZcand = 1
            ZZfinal, flavours = choose_final_ZZ(ZZ_cands_final, objects["e"], objects["mu"], ZZ_cands_final_flavours)
            lep1, lep2, lep3, lep4 = ZZidx_to_leps(ZZfinal, objects["e"], objects["mu"], flavours)
            #print("chosen leptons: (flavours", flavours)
            #for lep, nlep in zip([lep1,lep2,lep3,lep4],["a","b","c","d"]):
                #printlep(lep, nlep)
            #print((lep1+lep2+lep3+lep4).m)
            #print((lep1+lep2).m, (lep3+lep4).m)

            #print("original leptons: e")
            #for idx, lep in enumerate(objects["e"]):
                #nlep = "ne" + str(idx)
                #printlep(lep, nlep)
            #print("original leptons: mu")
            #for idx, lep in enumerate(objects["mu"]):
                #nlep = "nmu" + str(idx)
                #printlep(lep, nlep)


        #logger.debug("Value of isZZcand: %d", isZZcand)
        #debugging
        #print(len(objects["e"]), len(objects["mu"]))

        #if(len(ZZ_cand_ee_list) + len(ZZ_cand_mm_list) + len(ZZ_cand_em_list)) >= 1:
            #print(len(objects["e"]), len(objects["mu"]))
            #if isZZcand != 1:
                #print("no ZZ cand found after cuts")
            #else:
                #print("ok candidate and found")

        #update objects dictionary
        objects.update(
            {
                "isZZcand": isZZcand,
                "lep1ZZ": lep1,
                "lep2ZZ": lep2,
                "lep3ZZ": lep3,
                "lep4ZZ": lep4,
            }
        )
        return objects
Exemple #15
0
def _get_objects(particles, particles_truth, met_resolution=None, global_event_data=None):
    # Find visible particles
    electrons = []
    muons = []
    taus = []
    photons = []
    jets = []
    leptons = []
    neutrinos = []
    unstables = []
    invisibles = []

    for particle in particles:
        pdgid = abs(particle.pdgid)
        if pdgid in [1, 2, 3, 4, 5, 6, 9, 21]:
            if pdgid == 5:
                particle.set_tags(False, True, False)
            if pdgid == 6:
                particle.set_tags(False, False, True)
            jets.append(particle)
        elif pdgid == 11:
            electrons.append(particle)
            leptons.append(particle)
        elif pdgid == 13:
            muons.append(particle)
            leptons.append(particle)
        elif pdgid == 15:
            taus.append(particle)
        elif pdgid == 22:
            photons.append(particle)
        elif pdgid in [12, 14, 16]:
            neutrinos.append(particle)
            invisibles.append(particle)
        elif pdgid in [23, 24, 25]:
            unstables.append(particle)
        else:
            logger.warning("Unknown particle with PDG id %s, treating as invisible!")
            invisibles.append(particle)

    # Sort by pT
    electrons = sorted(electrons, reverse=True, key=lambda x: x.pt)
    muons = sorted(muons, reverse=True, key=lambda x: x.pt)
    taus = sorted(taus, reverse=True, key=lambda x: x.pt)
    photons = sorted(photons, reverse=True, key=lambda x: x.pt)
    leptons = sorted(leptons, reverse=True, key=lambda x: x.pt)
    neutrinos = sorted(neutrinos, reverse=True, key=lambda x: x.pt)
    jets = sorted(jets, reverse=True, key=lambda x: x.pt)

    # Sum over all particles
    ht = 0.0
    visible_sum = MadMinerParticle.from_xyzt(0.0, 0.0, 0.0, 0.0)

    standard_ids = set(get_elementary_pdg_ids())
    neutrino_ids = set(
        int(p.pdgid)
        for p in Particle.findall(lambda p: p.pdgid.is_sm_lepton and p.charge == 0)
    )

    for particle in particles:
        if particle.pdgid in standard_ids and particle.pdgid not in neutrino_ids:
            visible_sum += particle
            ht += particle.pt

    # Soft noise
    if met_resolution is not None:
        noise_std = met_resolution[0] + met_resolution[1] * ht
        noise_x = np.random.normal(0.0, noise_std, size=None)
        noise_y = np.random.normal(0.0, noise_std, size=None)
    else:
        noise_x = 0.0
        noise_y = 0.0

    # MET
    met_x = -visible_sum.x + noise_x
    met_y = -visible_sum.y + noise_y
    met = MadMinerParticle.from_xyzt(
        x=met_x,
        y=met_y,
        z=0.0,
        t=(met_x ** 2 + met_y ** 2) ** 0.5,
    )

    # Build objects
    objects = math_commands()
    objects.update(
        {
            "p": particles,
            "p_truth": particles_truth,
            "e": electrons,
            "j": jets,
            "a": photons,
            "mu": muons,
            "tau": taus,
            "l": leptons,
            "met": met,
            "v": neutrinos,
        }
    )

    # Global event_data
    if global_event_data is not None:
        objects.update(global_event_data)

    return objects
Exemple #16
0
def _get_objects(particles, met_resolution=None):
    # Find visible particles
    electrons = []
    muons = []
    taus = []
    photons = []
    jets = []
    leptons = []
    neutrinos = []
    unstables = []
    invisibles = []

    for particle in particles:
        pdgid = abs(particle.pdgid)
        if pdgid in [1, 2, 3, 4, 5, 6, 9, 21]:
            jets.append(particle)
        elif pdgid == 11:
            electrons.append(particle)
            leptons.append(particle)
        elif pdgid == 13:
            muons.append(particle)
            leptons.append(particle)
        elif pdgid == 15:
            taus.append(particle)
        elif pdgid == 22:
            photons.append(particle)
        elif pdgid in [12, 14, 16]:
            neutrinos.append(particle)
            invisibles.append(particle)
        elif pdgid in [23, 24, 25]:
            unstables.append(particle)
        else:
            logger.warning(
                "Unknown particle with PDG id %s, treating as invisible!")
            invisibles.append(particle)

    # Sort by pT
    electrons = sorted(electrons, reverse=True, key=lambda x: x.pt)
    muons = sorted(muons, reverse=True, key=lambda x: x.pt)
    taus = sorted(taus, reverse=True, key=lambda x: x.pt)
    photons = sorted(photons, reverse=True, key=lambda x: x.pt)
    leptons = sorted(leptons, reverse=True, key=lambda x: x.pt)
    neutrinos = sorted(neutrinos, reverse=True, key=lambda x: x.pt)
    jets = sorted(jets, reverse=True, key=lambda x: x.pt)

    # Sum over all particles
    ht = 0.0
    visible_sum = MadMinerParticle()
    visible_sum.setpxpypze(0.0, 0.0, 0.0, 0.0)

    for particle in particles:
        ht += particle.pt
        pdgid = abs(particle.pdgid)
        if pdgid in [1, 2, 3, 4, 5, 6, 9, 11, 13, 15, 21, 22, 23, 24, 25]:
            visible_sum += particle

    # Soft noise
    if met_resolution is not None:
        noise_std = met_resolution[0] + met_resolution[1] * ht
        noise_x = np.random.normal(0.0, noise_std, size=None)
        noise_y = np.random.normal(0.0, noise_std, size=None)
    else:
        noise_x = 0.0
        noise_y = 0.0

    # MET
    met_x = -visible_sum.px + noise_x
    met_y = -visible_sum.px + noise_y
    met = MadMinerParticle()
    met.setpxpypze(met_x, met_y, 0.0, (met_x**2 + met_y**2)**0.5)

    # Build objects
    objects = math_commands()
    objects.update({
        "p": particles,
        "e": electrons,
        "j": jets,
        "a": photons,
        "mu": muons,
        "tau": taus,
        "l": leptons,
        "met": met,
        "v": neutrinos,
    })

    return objects
Exemple #17
0
def _smear_particles(particles, energy_resolutions, pt_resolutions,
                     eta_resolutions, phi_resolutions):
    """ Applies smearing function to particles of one event """

    # No smearing if any argument is None
    if energy_resolutions is None or pt_resolutions is None or eta_resolutions is None or phi_resolutions is None:
        return particles

    smeared_particles = []

    for particle in particles:
        pdgid = particle.pdgid

        if (pdgid not in six.iterkeys(energy_resolutions)
                or pdgid not in six.iterkeys(pt_resolutions)
                or pdgid not in six.iterkeys(eta_resolutions)
                or pdgid not in six.iterkeys(phi_resolutions)):
            continue

        if None in energy_resolutions[pdgid] and None in pt_resolutions[pdgid]:
            raise RuntimeError(
                "Cannot derive both pT and energy from on-shell conditions!")

        # Minimum energy and pT
        m = particle.m
        min_e = 0.0
        if None in pt_resolutions[pdgid]:
            min_e = m
        min_pt = 0.0

        # Smear four-momenta
        e = None
        if None not in energy_resolutions[pdgid]:
            e = min_e - 1.0
            while e <= min_e:
                e = _smear_variable(particle.e, energy_resolutions, pdgid)
        pt = None
        if None not in pt_resolutions[pdgid]:
            pt = min_pt - 1.0
            while pt <= min_pt:
                pt = _smear_variable(particle.pt, pt_resolutions, pdgid)
        eta = _smear_variable(particle.eta, eta_resolutions, pdgid)
        phi = _smear_variable(particle.phi(), phi_resolutions, pdgid)
        while phi > 2.0 * np.pi:
            phi -= 2.0 * np.pi
        while phi < 0.0:
            phi += 2.0 * np.pi

        # Construct particle
        smeared_particle = MadMinerParticle()

        if None in energy_resolutions[pdgid]:
            # Calculate E from on-shell conditions
            smeared_particle.setptetaphim(pt, eta, phi, particle.m)

        elif None in pt_resolutions[pdgid]:
            # Calculate pT from on-shell conditions
            if e > m:
                pt = (e**2 - m**2)**0.5 / np.cosh(eta)
            else:
                pt = 0.0
            smeared_particle.setptetaphie(pt, eta, phi, e)

        else:
            # Everything smeared manually
            smeared_particle.setptetaphie(pt, eta, phi, e)

        # PDG id (also sets charge)
        smeared_particle.set_pdgid(pdgid)

        smeared_particles.append(smeared_particle)

    return smeared_particles
Exemple #18
0
def _get_particles_leptons(tree, pt_min_e, eta_max_e, pt_min_mu, eta_max_mu):
    pt_mu = tree.array("Muon.PT")
    eta_mu = tree.array("Muon.Eta")
    phi_mu = tree.array("Muon.Phi")
    charge_mu = tree.array("Muon.Charge")
    pt_e = tree.array("Electron.PT")
    eta_e = tree.array("Electron.Eta")
    phi_e = tree.array("Electron.Phi")
    charge_e = tree.array("Electron.Charge")

    all_particles = []

    for ievent in range(len(pt_mu)):
        event_particles = []

        # Combined muons and electrons
        event_pts = np.concatenate((pt_mu[ievent], pt_e[ievent]))
        event_etas = np.concatenate((eta_mu[ievent], eta_e[ievent]))
        event_phis = np.concatenate((phi_mu[ievent], phi_e[ievent]))
        event_masses = np.concatenate((0.105 * np.ones_like(pt_mu[ievent]), 0.000511 * np.ones_like(pt_e[ievent])))
        event_charges = np.concatenate((charge_mu[ievent], charge_e[ievent]))
        event_pdgid_positive_charges = np.concatenate(
            (-13 * np.ones_like(pt_mu[ievent], dtype=np.int), -11 * np.ones_like(pt_e[ievent], dtype=np.int))
        )

        # Sort by descending pT
        order = np.argsort(-1.0 * event_pts, axis=None)
        event_pts = event_pts[order]
        event_etas = event_etas[order]
        event_phis = event_phis[order]

        # Create particles
        for pt, eta, phi, mass, charge, pdgid_positive_charge in zip(
            event_pts, event_etas, event_phis, event_masses, event_charges, event_pdgid_positive_charges
        ):

            pdgid = pdgid_positive_charge if charge >= 0.0 else -pdgid_positive_charge

            if abs(int(pdgid)) == 11:
                if pt_min_e is not None and pt < pt_min_e:
                    continue
                if eta_max_e is not None and abs(eta) > eta_max_e:
                    continue

            elif abs(int(pdgid)) == 13:
                if pt_min_mu is not None and pt < pt_min_mu:
                    continue
                if eta_max_mu is not None and abs(eta) > eta_max_mu:
                    continue

            else:
                logging.warning("Delphes ROOT file has lepton with PDG ID %s, ignoring it", pdgid)
                continue

            particle = MadMinerParticle()
            particle.setptetaphim(pt, eta, phi, mass)
            particle.set_pdgid(pdgid)
            event_particles.append(particle)

        all_particles.append(event_particles)

    return all_particles