2. Mix ThOr and LoKi Functors

This tutorial shows how to add both LoKi and ThOr functors to the Funtuple. It can be split in few steps:

  1. Definition of a dictionary of {"field name" : "decay descriptor component"}.

  • For particle properties, names, etc checkout ParticleTable.txt that can be obtained via command

    $DVPATH/run dump_ParticleProperties -t Upgrade | tee ParticleTable.txt
    
  • For decay descriptor info see for example LoKiNewDecayFinders If your decay is self-tagged (which is the most common case) then you will need “[<decay-descriptor>]CC”

  1. Define a collection of functors called FunctorCollection, which takes dictionary of “variable name” -> “ThOr” functor (Can also be a “LoKi” functor see next tutorial). For more info on ThOr see the ThOr functors page For list of ThOr functors see the ThOr functors reference For information on LoKi functor see the StarterKit

  2. Define a LoKi preamble (Note that one can define preambles in ThOr using python lambda function see next tutorial or via FunctorComposition) i.e. rename a complex LoKi functor to a user defined name (e.g. TRACK_MAX_PT) This helps us to use TRACK_MAX_PT when constructing FunctorCollection

  3. Define collections to be added to fields and the variables dictionary in the form “field name” -> Collections of functor.

  4. Finally there are the definition of the TES location, of a filter and the FunTuple instance.

import Functors as F
from DaVinci import Options, make_config
from DaVinci.algorithms import create_lines_filter
from PyConf.reading import get_particles
from FunTuple import FunctorCollection
from FunTuple import FunTuple_Particles as Funtuple


def main(options: Options):
    # Define a dictionary of "field name" -> "decay descriptor component".
    fields = {
        "Bs": "B_s0 -> (J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ K-)",
        "Jpsi": "B_s0 -> ^(J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ K-)",
        "Phi": "B_s0 ->  (J/psi(1S) -> mu+ mu-) ^(phi(1020) ->K+ K-)",
        "Mup": "B_s0 ->  (J/psi(1S) ->^mu+ mu-) (phi(1020) ->K+ K-)",
        "Mum": "B_s0 ->  (J/psi(1S) -> mu+ ^mu-) (phi(1020) ->K+ K-)",
        "Kp": "B_s0 ->  (J/psi(1S) -> mu+ mu-) (phi(1020) ->^K+ K-)",
        "Km": "B_s0 ->  (J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ ^K-)",
    }

    # Define a collection of functors called FunctorCollection, which takes dictionary of "variable name" -> "LoKi" or "ThOr" functor
    # For more info on ThOr see https://lhcbdoc.web.cern.ch/lhcbdoc/moore/master/selection/thor_functors.html#functor-cache
    # For list of ThOr functors see https://lhcbdoc.web.cern.ch/lhcbdoc/moore/master/selection/thor_functors_reference.html
    # For information on LoKi functor see https://lhcb.github.io/starterkit-lessons/first-analysis-steps/loki-functors.html
    mom_fun = FunctorCollection(
        {
            "THOR_PT": F.PT,
            "THOR_PX": F.PX,
            "THOR_PY": F.PY,
            "LOKI_PT": "PT",  # LoKi functor code is represented in a string
            "LOKI_PX": "PX",
            "LOKI_PY": "PY",
        }
    )

    # Define a LoKi preamble (Note that one can define preambles in ThOr using python lambda function see next tutorial or via FunctorComposition)
    # i.e. rename a complex LoKi functor to a user deinfed name (e.g. TRACK_MAX_PT)
    # This helps us to use "TRACK_MAX_PT" when constructing FunctorCollection
    loki_preamble = ["TRACK_MAX_PT = MAXTREE(ISBASIC & HASTRACK, PT, -1)"]

    # Define collections to be added to fields
    max_pt_fun = FunctorCollection(
        {
            # With LoKi
            "MAX_PT_LOKI": "TRACK_MAX_PT",
            # ThOr (not equivalent, sum of pT of composites not basic). MAXTREE ThOr doesn't exist yet.
            "MAX_PT_THOR": F.MAX(F.PT),
        }
    )

    # Define variables dictionary "field name" -> Collections of functor.
    variables = {
        "ALL": mom_fun,
        "Bs": max_pt_fun,
        "Jpsi": max_pt_fun,
        "Phi": max_pt_fun,
    }

    # Load data from dst onto a TES
    turbo_line = "Hlt2B2CC_BsToJpsiPhi_Detached"
    input_data = get_particles(f"/Event/HLT2/{turbo_line}/Particles")

    # Add a filter
    my_filter = create_lines_filter("HDRFilter_SeeNoEvil", lines=[f"{turbo_line}"])

    # Define instance of FunTuple
    mytuple = Funtuple(
        "TDirectoryName",
        "TTreeName",
        fields=fields,
        variables=variables,
        loki_preamble=loki_preamble,  # optional argument
        inputs=input_data,
    )

    config = make_config(options, [my_filter, mytuple])
    return config

To run the example:

lbexec DaVinciTutorials.tutorial2_LoKi:main $DAVINCITUTORIALSROOT/options.yaml

For reference, these are the options of this example

input_files:
   - 'root://eoslhcb.cern.ch//eos/lhcb/wg/dpa/wp3/tests/hlt2_passthrough_thor_lines.dst'
input_manifest_file: 'root://eoslhcb.cern.ch//eos/lhcb/wg/dpa/wp3/tests/hlt2_passthrough_thor_lines.tck.json'
input_type: ROOT
evt_max: 100
ntuple_file: davinci_ntuple.root
input_process: TurboPass
print_freq: 1
simulation: True
lumi: False
conddb_tag: sim-20180530-vc-md100
dddb_tag: dddb-20180815
conditions_version: master
geometry_version: run3/trunk
persistreco_version: 0.0