FunTuple event-by-event primary b- and c-hadrons and their descendants

This script demonstrates how to use the FunTuple_Event framework to create a tuple with information on the MC particles for each event to study and reconstruct the decay of prompt b and c hadrons (ancestors).

from PyConf.reading import get_mc_header
import Functors as F
from FunTuple import FunctorCollection
from FunTuple import FunTuple_Event
from DaVinci import Options, make_config


def main(options: Options):
    # get the header and the event variables
    mc_header = get_mc_header()
    evt_variables = FunctorCollection()

    # functors to filter on prompt B and C hadrons
    PRODUCTS_WITH_BOTTOM = (
        F.FILTER(F.HAS_BOTTOM & F.IS_HADRON @ F.PARTICLE_ID_OBJ) @ F.MC_VTX_PRODUCTS
    )
    PRODUCTS_WITH_CHARM = (
        F.FILTER(F.HAS_CHARM & F.IS_HADRON @ F.PARTICLE_ID_OBJ) @ F.MC_VTX_PRODUCTS
    )

    # filters functors to get the number of decay prongs
    filter_charged_inacc = F.FILTER((F.CHARGE != 0) & (F.ETA > 2) & (F.ETA < 5))
    filter_notcharged = F.FILTER(F.CHARGE == 0)
    filter_charged = F.FILTER(F.CHARGE != 0)
    filter_inacc = F.FILTER((F.ETA > 2) & (F.ETA < 5))

    # number of charged descentants in acceptance
    # cast the integer to float because SUM_RANGE requires float
    num_charged_descentants_inacc = F.SUM_RANGE @ F.MAP(
        F.CAST_TO_FLOAT @ F.SIZE_OF @ filter_charged_inacc @ F.GET_ALL_DESCENDANTS
    )
    # number of decay prongs to reconstruct the vertex
    num_decay_prongs = (
        F.VALUE_OR(0)
        @ (
            (num_charged_descentants_inacc @ filter_notcharged)
            + (F.SIZE_OF @ filter_charged)
        )
        @ filter_inacc
        @ F.GET_CHILDREN
    )

    # distance between the origin vertex and the end vertex
    orig_vtx_pos = F.VALUE @ F.TOLINALG @ F.POSITION @ F.MC_ORIGINVERTEX
    end_vtx_pos = F.VALUE @ F.TOLINALG @ F.POSITION @ F.ENDVERTEX
    decaylength = F.VALUE_OR(0.0) @ F.MAGNITUDE @ (orig_vtx_pos - end_vtx_pos)

    # functors for ancestors
    f_pid = F.VALUE_OR([0]) @ F.MAP(F.PARTICLE_ID)
    f_key = F.VALUE_OR([0]) @ F.MAP(F.OBJECT_KEY)
    f_charge = F.VALUE_OR([0]) @ F.MAP(F.CHARGE)
    f_nprongs = F.VALUE @ F.MAP(num_decay_prongs)
    f_decaylength = F.VALUE @ F.MAP(decaylength)
    f_Ndescendants = F.VALUE_OR([0]) @ F.MAP(F.SIZE_OF @ F.GET_ALL_DESCENDANTS)

    # functors for descendants
    flat_products_key = (
        F.VALUE_OR([0]) @ F.FLATTEN @ F.MAP(F.MAP(F.OBJECT_KEY) @ F.GET_ALL_DESCENDANTS)
    )
    flat_products_pid = (
        F.VALUE_OR([0])
        @ F.FLATTEN
        @ F.MAP(F.MAP(F.PARTICLE_ID) @ F.GET_ALL_DESCENDANTS)
    )
    flat_products_nprongs = (
        F.VALUE @ F.FLATTEN @ F.MAP(F.MAP(num_decay_prongs) @ F.GET_ALL_DESCENDANTS)
    )
    flat_products_decaylength = (
        F.VALUE @ F.FLATTEN @ F.MAP(F.MAP(decaylength) @ F.GET_ALL_DESCENDANTS)
    )
    flat_products_vtx = (
        F.VALUE_OR([-1])
        @ F.FLATTEN
        @ F.MAP(
            F.MAP(F.VALUE_OR(-42) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
            @ F.GET_ALL_DESCENDANTS
        )
    )
    flat_products_mother_key = (
        F.VALUE_OR([0])
        @ F.FLATTEN
        @ F.MAP(
            F.MAP(F.VALUE_OR(-42) @ F.MC_MOTHER(1, F.OBJECT_KEY))
            @ F.GET_ALL_DESCENDANTS
        )
    )
    # event variables
    evt_up = {
        "B_Ancestor_Ndescendants[ba_indx]": F.FLATTEN
        @ F.MAP(f_Ndescendants @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "B_Ancestor_PID[ba_indx]": F.FLATTEN
        @ F.MAP(f_pid @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "B_Ancestor_KEY[ba_indx]": F.FLATTEN
        @ F.MAP(f_key @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "B_Ancestor_NPRONGS[ba_indx]": F.FLATTEN
        @ F.MAP(f_nprongs @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "B_Ancestor_DL[ba_indx]": F.FLATTEN
        @ F.MAP(f_decaylength @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "B_Ancestor_Q[ba_indx]": F.FLATTEN
        @ F.MAP(f_charge @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "B_Children_PID[bc_indx]": F.FLATTEN
        @ F.MAP(flat_products_pid @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "B_Children_KEY[bc_indx]": F.FLATTEN
        @ F.MAP(flat_products_key @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "B_Children_NPRONGS[bc_indx]": F.FLATTEN
        @ F.MAP(flat_products_nprongs @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "B_Children_DL[bc_indx]": F.FLATTEN
        @ F.MAP(flat_products_decaylength @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "B_Children_VTX_type[bc_indx]": F.FLATTEN
        @ F.MAP(flat_products_vtx @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "B_Children_Mother_KEY[bc_indx]": F.FLATTEN
        @ F.MAP(flat_products_mother_key @ PRODUCTS_WITH_BOTTOM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Ancestor_Ndescendants[ca_indx]": F.FLATTEN
        @ F.MAP(f_Ndescendants @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Ancestor_PID[ca_indx]": F.FLATTEN
        @ F.MAP(f_pid @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Ancestor_KEY[ca_indx]": F.FLATTEN
        @ F.MAP(f_key @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Ancestor_NPRONGS[ca_indx]": F.FLATTEN
        @ F.MAP(f_nprongs @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Ancestor_DL[ca_indx]": F.FLATTEN
        @ F.MAP(f_decaylength @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Ancestor_Q[ca_indx]": F.FLATTEN
        @ F.MAP(f_charge @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Children_PID[cc_indx]": F.FLATTEN
        @ F.MAP(flat_products_pid @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Children_KEY[cc_indx]": F.FLATTEN
        @ F.MAP(flat_products_key @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Children_NPRONGS[cc_indx]": F.FLATTEN
        @ F.MAP(flat_products_nprongs @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Children_DL[cc_indx]": F.FLATTEN
        @ F.MAP(flat_products_decaylength @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Children_VTX_type[cc_indx]": F.FLATTEN
        @ F.MAP(flat_products_vtx @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
        "C_Children_Mother_KEY[cc_indx]": F.FLATTEN
        @ F.MAP(flat_products_mother_key @ PRODUCTS_WITH_CHARM)
        @ F.MC_ALLPVS(mc_header=mc_header),
    }
    evt_variables.update(evt_up)

    # create the tuple
    my_tuple = FunTuple_Event(
        name="Tuple", tuple_name="EventInfo", variables=evt_variables
    )

    return make_config(options, [my_tuple])

To run the example:

lbexec DaVinciExamples.tupling.option_davinci_tupling_FunTupleEvent_dfei:main $DAVINCIEXAMPLESROOT/example_data/test_hlt1_trigger_decisions.yaml

For reference, these are the options of this example