Particle refitting on data

This example shows how to read data, refit the decay tree with the updated alignment parameters, and tuple the new particles.

from PyConf.reading import get_particles
import Functors as F

from FunTuple import FunctorCollection
from FunTuple import FunTuple_Particles as Funtuple
import FunTuple.functorcollections as FC
from DaVinci.algorithms import create_lines_filter
from DaVinci import Options, make_config

from PyConf.reading import get_pvs, get_rec_summary
from RecoConf import track_refitting


def main(options: Options):
    line_name = "Hlt2Charm_DstpToD0Pip_D0ToKmPip"
    original_particles = get_particles(f"/Event/HLT2/{line_name}/Particles")
    my_filter = create_lines_filter(name="HDRFilter_D0Kpi", lines=[f"{line_name}"])

    pvs = get_pvs()

    refitted_data = track_refitting.refit_decay_tree(
        input_particles=original_particles, input_pvs=pvs
    )
    refitted_particles = refitted_data.OutputParticles

    fields = {
        "Dst": "[D*(2010)+ -> (D0 -> K- pi+) pi+]CC",
        "Dzero": "[D*(2010)+ -> ^(D0 -> K- pi+) pi+]CC",
        "Km": "[D*(2010)+ -> (D0 -> ^K- pi+) pi+]CC",
        "Pip": "[D*(2010)+ -> (D0 -> K- ^pi+) pi+]CC",
        "TagPi": "[D*(2010)+ -> (D0 -> K- pi+) ^pi+]CC",
    }

    composite_variables = FunctorCollection(
        {
            "M": F.MASS,
            "ID": F.PARTICLE_ID,
            "KEY": F.OBJECT_KEY,
            "PT": F.PT,
            "PX": F.PX,
            "PY": F.PY,
            "PZ": F.PZ,
            "ENERGY": F.ENERGY,
            "P": F.P,
            "FOURMOMENTUM": F.FOURMOMENTUM,
            "BPVDIRA": F.BPVDIRA(pvs),
            "BPVFDCHI2": F.BPVFDCHI2(pvs),
            "BPVIPCHI2": F.BPVIPCHI2(pvs),
        }
    )

    daughter_variables = FunctorCollection(
        {
            "ID": F.PARTICLE_ID,
            "PT": F.PT,
            "PX": F.PX,
            "PY": F.PY,
            "PZ": F.PZ,
            "ENERGY": F.ENERGY,
            "P": F.P,
            "FOURMOMENTUM": F.FOURMOMENTUM,
        }
    )

    # we also have access to the previous iteration of the decay tree,
    # which can be compared to candidate-per-candidate through a relation table
    refitted_decay_tree_relations = refitted_data.OutputRelationsNewToOld
    PRE_REFIT_FUNCTOR = lambda n: F.VALUE_OR(-1) @ F.MAP_INPUT(
        Functor=n, Relations=refitted_decay_tree_relations
    )

    pre_refit_variables = FunctorCollection(
        {
            "Refitting_OLD_M": PRE_REFIT_FUNCTOR(F.MASS),
            "Refitting_OLD_PT": PRE_REFIT_FUNCTOR(F.PT),
            "Refitting_OLD_P": PRE_REFIT_FUNCTOR(F.P),
        }
    )

    composite_variables += pre_refit_variables

    variables = {
        "Dst": composite_variables,
        "Dzero": composite_variables,
        "Km": daughter_variables,
        "Pip": daughter_variables,
        "TagPi": daughter_variables,
    }

    rec_summary = get_rec_summary()
    evt_variables = FC.RecSummary(rec_summary) + FC.AllPrimaryVertexInfo(
        pvs, extra_info=True
    )

    my_tuple = Funtuple(
        name="DecayTreeTuple",
        tuple_name="DecayTree",
        fields=fields,
        variables=variables,
        event_variables=evt_variables,
        inputs=refitted_particles,
    )

    return make_config(options, [my_filter, my_tuple])

To run the example:

lb-run DaVinci/vXXrY lbexec DaVinciExamples.tupling.option_davinci_tupling_from_spruced_turbo_with_refitting:main $DAVINCIEXAMPLESROOT/example_data/2024_sprucing24c2_charm_turbo_data.yaml

For reference, these are the options of this example

input_files:
 - root://eoslhcb.cern.ch//eos/lhcb/wg/dpa/wp3/tests/Sprucing24c2_Run297156_TruboStreamOnline_charmDST_example.dst
input_type: 'ROOT'
simulation: False
input_raw_format: 0.5
input_process: TurboPass
input_stream: charm
conditions_version: master
geometry_version: run3/2024.Q1.2-v00.00
python_logging_level: 3
persistreco_version: 1.0
lumi: False
write_fsr: False
ntuple_file: 2024_data.root
evt_max: 300