diff --git a/Lb2D0Lz_run3/dtf_maker.py b/Lb2D0Lz_run3/dtf_maker.py
new file mode 100644
index 0000000000000000000000000000000000000000..e6d9bf4cb312524faab88e4451b7cf95c8c7837c
--- /dev/null
+++ b/Lb2D0Lz_run3/dtf_maker.py
@@ -0,0 +1,164 @@
+##############################################################################
+# (c) Copyright 2024 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+"""Configuration functions for DTF
+"""
+import Functors as F
+from Functors.math import log
+
+from FunTuple import FunctorCollection
+from FunTuple.functorcollections import Kinematics
+
+from DecayTreeFitter import DecayTreeFitter
+
+def make_basic_dtf_variables(pvs, data, DTF=None, pv_constraint=False, mass_constraint=False, particle_name=""):
+    variables = (
+        FunctorCollection(
+            {
+                "TRCHI2DOF"     : F.CHI2DOF @ F.TRACK,
+                "ETA"           : F.ETA,
+                "PHI"           : F.PHI,
+                "TRGHOSTPROB"   : F.GHOSTPROB,
+                "BPVIPCHI2"     : F.BPVIPCHI2(pvs),
+                "BPVIP"         : F.BPVIP(pvs),
+                "BPVX"          : F.BPVX(pvs),
+                "BPVY"          : F.BPVY(pvs),
+                "BPVZ"          : F.BPVZ(pvs),
+                "TX"            : F.TX,
+                "TY"            : F.TY,
+                "MINIPCHI2"     : F.MINIPCHI2(pvs),
+                "MINIP"         : F.MINIP(pvs),
+                "KEY"           : F.VALUE_OR(-1) @ F.OBJECT_KEY @ F.TRACK,
+                #"CTB"         : F.POSITION @ F.CLOSESTTOBEAM @ F.TRACK,
+                "TRACKPT"       : F.TRACK_PT,
+                "TRACKHISTORY"  : F.VALUE_OR(-1) @ F.TRACKHISTORY @ F.TRACK,
+                "QOVERP"        : F.QOVERP @ F.TRACK,
+                "NDOF"          : F.VALUE_OR(-1) @ F.NDOF @ F.TRACK,
+            }
+        )
+        + Kinematics()
+    )
+
+    if(mass_constraint):
+        if(pv_constraint): # MASS + PV
+            dtf_variables_mass_pv = FunctorCollection({ 'DTF_PV_Fix'+ particle_name + '_' + k: DTF(v) for k, v in variables.get_thor_functors().items() })
+            return dtf_variables_mass_pv
+        else: # MASS
+            dtf_variables_mass = FunctorCollection( {'DTF_Fix'+ particle_name + '_' + k: DTF(v) for k, v in variables.get_thor_functors().items()})
+        return dtf_variables_mass
+    elif(pv_constraint): # PV
+        dtf_variables_pv = FunctorCollection({ 'DTF_PV_' + k: DTF(v) for k, v in variables.get_thor_functors().items() })
+        return dtf_variables_pv
+    else: # NO MASS/PV
+        dtf_variables = FunctorCollection( {'DTF_' + k: DTF(v) for k, v in variables.get_thor_functors().items()})
+        return dtf_variables
+
+
+def make_composite_dtf_variables(pvs, data, DTF=None, pv_constraint=False, mass_constraint=False, particle_name=""):
+    variables = (
+        FunctorCollection(
+            {
+                "MAXPT": F.MAX(F.PT),
+                "MINPT": F.MIN(F.PT),
+                "SUMPT": F.SUM(F.PT),
+                "MAXP": F.MAX(F.P),
+                "MINP": F.MIN(F.P),
+                "BPVDIRA": F.BPVDIRA(pvs),
+                "VCHI2DOF": F.CHI2DOF, #CHI2VXNDOF
+                "BPVFDCHI2": F.BPVFDCHI2(pvs),
+                "BPVFD": F.BPVFD(pvs),
+                "BPVVDRHO": F.BPVVDRHO(pvs),
+                "BPVVDZ": F.BPVVDZ(pvs),
+                "BPVIPCHI2": F.BPVIPCHI2(pvs),
+                "BPVIP": F.BPVIP(pvs),
+#                "LOGBPVIPCHI2": log(F.BPVIPCHI2(pvs)),
+                "BPVLTIME": F.BPVLTIME(pvs),
+                "MAXBPVIPCHI2": F.MAX(F.BPVIPCHI2(pvs)), #MAX_
+                "MINBPVIPCHI2": F.MIN(F.BPVIPCHI2(pvs)),
+                "MAXBPVIP": F.MAX(F.BPVIP(pvs)),
+                "MINBPVIP": F.MIN(F.BPVIP(pvs)),
+                "ETA": F.ETA,
+                "PHI": F.PHI,
+                "END_VX": F.END_VX, #END_
+                "END_VY": F.END_VY,
+                "END_VZ": F.END_VZ,
+                "BPVX": F.BPVX(pvs),
+                "BPVY": F.BPVY(pvs),
+                "BPVZ": F.BPVZ(pvs),
+                "ALLPVFD"     : F.ALLPV_FD(pvs),
+                "ALLPVIP"     : F.ALLPV_IP(pvs),
+                
+            }
+        )
+        + Kinematics()
+    )
+
+    addstring = "DTF"
+    if(pv_constraint):
+            addstring += '_PV'
+    if(mass_constraint):
+            addstring += '_Fix'
+    addstring += particle_name
+
+    DTF_chi2ndof = FunctorCollection(
+            {
+                addstring+"_DTFCHI2": DTF.CHI2,
+                addstring+"_DTFNDOF": DTF.NDOF,
+                addstring+"_CTAU": DTF.CTAU,
+                addstring+"_CTAUERR": DTF.CTAUERR,
+                addstring+"_MERR": DTF.MASSERR,
+            }
+    )
+
+    if(mass_constraint):
+        if(pv_constraint): # MASS + PV
+            dtf_variables_mass_pv = FunctorCollection({ 'DTF_PV_Fix'+ particle_name + '_' + k: DTF(v) for k, v in variables.get_thor_functors().items() })
+            return dtf_variables_mass_pv+DTF_chi2ndof
+        else: # MASS
+            dtf_variables_mass = FunctorCollection( {'DTF_Fix'+ particle_name + '_' + k: DTF(v) for k, v in variables.get_thor_functors().items()})
+        return dtf_variables_mass+DTF_chi2ndof
+    elif(pv_constraint): # PV
+        dtf_variables_pv = FunctorCollection({ 'DTF_PV_' + k: DTF(v) for k, v in variables.get_thor_functors().items() })
+        return dtf_variables_pv+DTF_chi2ndof
+    else: # NO MASS/PV
+        dtf_variables = FunctorCollection( {'DTF_' + k: DTF(v) for k, v in variables.get_thor_functors().items()})
+        return dtf_variables+DTF_chi2ndof
+
+
+
+def make_dtf_variables_lb2d0lz(pvs, input_data, ptype):
+
+    if ptype not in ["basic", "composite"]:
+        Exception(f"I want \'basic\' or \'composite\'. Got {ptype}")
+
+    DTF              = DecayTreeFitter( name=f'DTF_{{hash}}'             , input_particles=input_data)
+    DTF_PV           = DecayTreeFitter( name=f'DTF_PV_{{hash}}'          , input_particles=input_data, input_pvs=pvs)
+    DTF_PV_FixD      = DecayTreeFitter( name=f'DTF_PV_FixD_{{hash}}'     , input_particles=input_data, input_pvs=pvs, mass_constraints=["D0"])
+    DTF_PV_FixLz      = DecayTreeFitter( name=f'DTF_PV_FixLz_{{hash}}'     , input_particles=input_data, input_pvs=pvs, mass_constraints=["Lambda0"])
+    DTF_PV_FixDLz      = DecayTreeFitter( name=f'DTF_PV_FixDLz_{{hash}}'     , input_particles=input_data, input_pvs=pvs, mass_constraints=[ "D0", "Lambda0"])
+    DTF_PV_FixB      = DecayTreeFitter( name=f'DTF_PV_FixB_{{hash}}'     , input_particles=input_data, input_pvs=pvs, mass_constraints=["Lambda_b0", "D0", "Lambda0"])
+
+    if ptype == "basic":
+        dtf_vars  = make_basic_dtf_variables(pvs, input_data, DTF=DTF,              pv_constraint=False, mass_constraint=False)
+        dtf_vars += make_basic_dtf_variables(pvs, input_data, DTF=DTF_PV,           pv_constraint=True,  mass_constraint=False)
+        dtf_vars += make_basic_dtf_variables(pvs, input_data, DTF=DTF_PV_FixD,      pv_constraint=True,  mass_constraint=True, particle_name="D")
+        dtf_vars += make_basic_dtf_variables(pvs, input_data, DTF=DTF_PV_FixLz,      pv_constraint=True,  mass_constraint=True, particle_name="Lz")
+        dtf_vars += make_basic_dtf_variables(pvs, input_data, DTF=DTF_PV_FixDLz,      pv_constraint=True,  mass_constraint=True, particle_name="DLz")
+        dtf_vars += make_basic_dtf_variables(pvs, input_data, DTF=DTF_PV_FixB,      pv_constraint=True,  mass_constraint=True, particle_name="B")
+        return dtf_vars
+
+    if ptype == "composite":
+        dtf_vars  = make_composite_dtf_variables(pvs, input_data, DTF=DTF,              pv_constraint=False, mass_constraint=False)
+        dtf_vars += make_composite_dtf_variables(pvs, input_data, DTF=DTF_PV,           pv_constraint=True,  mass_constraint=False)
+        dtf_vars += make_composite_dtf_variables(pvs, input_data, DTF=DTF_PV_FixD,      pv_constraint=True,  mass_constraint=True, particle_name="D")
+        dtf_vars += make_composite_dtf_variables(pvs, input_data, DTF=DTF_PV_FixLz,      pv_constraint=True,  mass_constraint=True, particle_name="Lz")
+        dtf_vars += make_composite_dtf_variables(pvs, input_data, DTF=DTF_PV_FixDLz,      pv_constraint=True,  mass_constraint=True, particle_name="DLz")
+        dtf_vars += make_composite_dtf_variables(pvs, input_data, DTF=DTF_PV_FixB,      pv_constraint=True,  mass_constraint=True, particle_name="B")
+        return dtf_vars
diff --git a/Lb2D0Lz_run3/dv_Lb2D0Lz.py b/Lb2D0Lz_run3/dv_Lb2D0Lz.py
new file mode 100644
index 0000000000000000000000000000000000000000..7edd6a6cbed6ba1ab1f5735cd2f862073d96e1a5
--- /dev/null
+++ b/Lb2D0Lz_run3/dv_Lb2D0Lz.py
@@ -0,0 +1,495 @@
+import Functors as F
+from FunTuple import FunctorCollection as FC
+from FunTuple import FunTuple_Particles as Funtuple
+from PyConf.reading import get_particles, get_pvs, get_rec_summary, get_odin
+from DaVinci.algorithms import create_lines_filter
+from DaVinci import Options, make_config
+from DaVinciMCTools import MCTruthAndBkgCat
+from FunTuple.functorcollections import MCHierarchy, MCPrimaries, MCPromptDecay, Kinematics, SelectionInfo, HltTisTos, MCVertexInfo, MCKinematics, ParticleID, EventInfo
+from DecayTreeFitter import DecayTreeFitter
+import Functors.math as fmath
+from .dtf_maker import  make_dtf_variables_lb2d0lz
+
+_basic     = "basic"
+_composite = "composite"
+
+def all_variables(pvs, ptype, nbodydecay=2):
+    """
+    function that returns dictionary of functors that work.
+    
+    functors are listed in order of https://lhcbdoc.web.cern.ch/lhcbdoc/moore/master/selection/thor_functors_reference.html#module-Functo
+    """
+    if ptype not in [_basic, _composite]:
+        Exception(f"I want {_basic} or {_composite}. Got {ptype}")
+    all_vars = FC({})
+    
+    comp  = _composite == ptype  # is composite
+    basic = _basic == ptype      # is not composite
+
+    # First import everything that comes in functorcollections
+    all_vars += Kinematics()
+    if basic:
+        all_vars += ParticleID(extra_info=True)
+    
+    if comp:  # all these require a vertex
+        all_vars.update({"BPVCORRM"   : F.BPVCORRM(pvs)})
+        all_vars.update({"BPVCORRMERR": F.BPVCORRMERR(pvs)})
+        all_vars.update({"BPVDIRA"    : F.BPVDIRA(pvs)})
+        all_vars.update({"BPVDLS"     : F.BPVDLS(pvs)})
+        all_vars.update({"BPVETA"     : F.BPVETA(pvs)})
+        all_vars.update({"BPVFD"      : F.BPVFD(pvs)})
+        all_vars.update({"BPVFDCHI2"  : F.BPVFDCHI2(pvs)})
+        all_vars.update({"BPVFDIR"    : F.BPVFDIR(pvs)})
+        all_vars.update({"BPVFDVEC"   : F.BPVFDVEC(pvs)})
+
+    all_vars.update({"BPVIP"    : F.BPVIP(pvs)})
+    all_vars.update({"BPVIPCHI2": F.BPVIPCHI2(pvs)})
+    all_vars.update({"BPVX"     : F.BPVX(pvs)})
+    all_vars.update({"BPVY"     : F.BPVY(pvs)})
+    all_vars.update({"BPVZ"     : F.BPVZ(pvs)})
+
+    if comp:  # all these require a vertex
+        all_vars.update({"ALLPV_FD": F.ALLPV_FD(pvs)})
+        all_vars.update({"ALLPV_IP": F.ALLPV_IP(pvs)})
+        all_vars.update({"BPVLTIME": F.BPVLTIME(pvs)})
+        all_vars.update({"BPVVDRHO": F.BPVVDRHO(pvs)})
+        all_vars.update({"BPVVDX"  : F.BPVVDX(pvs)})
+        all_vars.update({"BPVVDY"  : F.BPVVDY(pvs)})
+        all_vars.update({"BPVVDZ"  : F.BPVVDZ(pvs)})
+    
+    all_vars.update({"CHARGE" : F.CHARGE})
+    all_vars.update({"CHI2"   : F.CHI2})
+    all_vars.update({"CHI2DOF": F.CHI2DOF})
+
+    
+    if comp:
+        all_vars.update({"END_VRHO": F.END_VRHO})
+        all_vars.update({"END_VX"  : F.END_VX})
+        all_vars.update({"END_VY"  : F.END_VY})
+        all_vars.update({"END_VZ"  : F.END_VZ})
+    
+    all_vars.update({"ETA"         : F.ETA})
+    all_vars.update({"FOURMOMENTUM": F.FOURMOMENTUM})
+    all_vars.update({"ISBASIC"     : F.ISBASICPARTICLE})
+
+    if basic:
+        all_vars.update({"GHOSTPROB"        : F.GHOSTPROB})
+        all_vars.update({"ISMUON"           : F.ISMUON})
+        all_vars.update({"INMUON"           : F.INMUON})
+        all_vars.update({"INECAL"           : F.INECAL})
+        all_vars.update({"INHCAL"           : F.INHCAL})
+        all_vars.update({"HASBREM"          : F.HASBREM})
+        all_vars.update({"BREMENERGY"       : F.BREMENERGY})
+        all_vars.update({"BREMBENDCORR"     : F.BREMBENDCORR})
+        all_vars.update({"BREMPIDE"         : F.BREMPIDE})
+        all_vars.update({"ECALPIDE"         : F.ECALPIDE})
+        all_vars.update({"ECALPIDMU"        : F.ECALPIDMU})
+        all_vars.update({"HCALPIDE"         : F.HCALPIDE})
+        all_vars.update({"HCALPIDMU"        : F.HCALPIDMU})
+        all_vars.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
+        all_vars.update({"CLUSTERMATCH"     : F.CLUSTERMATCH_CHI2})
+        all_vars.update({"ELECTRONMATCH"    : F.ELECTRONMATCH_CHI2})
+        all_vars.update({"BREMHYPOMATCH"    : F.BREMHYPOMATCH_CHI2})
+        all_vars.update({"ELECTRONENERGY"   : F.ELECTRONENERGY})
+        all_vars.update({"BREMHYPOENERGY"   : F.BREMHYPOENERGY})
+        all_vars.update({"BREMHYPODELTAX"   : F.BREMHYPODELTAX})
+        all_vars.update({"ELECTRONID"       : F.ELECTRONID})
+        all_vars.update({"HCALEOP"          : F.HCALEOP})
+        # Note: the observables for the two functors below are (TRACK_MOM_X, TRACK_MOM_Y, TRACK_MOM_Z})
+        # and (TRACK_POS_CLOSEST_TO_BEAM_X, TRACK_POS_CLOSEST_TO_BEAM_Y, TRACK_POS_CLOSEST_TO_BEAM_Z),
+        # which is why the trailing underscore in the name is added i.e. "TRACK_MOM_" and "TRACK_POS_CLOSEST_TO_BEAM_"
+        all_vars.update({"TRACK_MOM": F.TRACK_MOMVEC})
+        #all_vars.update({"TRACK_COVARIANCE": F.TRACK_COVARIANCE @ F.TRACKSTATE @ F.TRACK})
+        #all_vars.update({"TRACK_POS_CLOSESTTOBEAM_": F.TRACK_POSVEC_CLOSESTTOBEAM})
+        #all_vars.update({"POSITION_STATEAT_FirstMeasurement_X"     : F.POSITION_X @ F.STATE_AT("FirstMeasurement")@ F.TRACK})  #NB only long tracks
+        #all_vars.update({"POSITION_STATEAT_FirstMeasurement_Y"     : F.POSITION_Y @ F.STATE_AT("FirstMeasurement")@ F.TRACK})  #NB only long tracks
+        #all_vars.update({"POSITION_STATEAT_FirstMeasurement_Z"     : F.POSITION_Z @ F.STATE_AT("FirstMeasurement")@ F.TRACK})  #NB only long tracks
+        
+        all_vars.update({"IS_ABS_ID_pi"        : F.IS_ABS_ID("pi+")})
+        all_vars.update({"IS_ID_pi"            : F.IS_ID("pi-")})
+        all_vars.update({"PDG_MASS_pi"         : F.PDG_MASS("pi+")})
+        all_vars.update({"SIGNED_DELTA_MASS_pi": F.SIGNED_DELTA_MASS("pi+")})
+        all_vars.update({"ABS_DELTA_MASS_pi"   : F.ABS_DELTA_MASS("pi+")})
+        all_vars.update({"IS_NOT_H"            : F.IS_NOT_H})
+        all_vars.update({"IS_PHOTON"           : F.IS_PHOTON})
+
+    all_vars.update({"MASS": F.MASS})
+
+    if comp:
+        all_vars.update({"MAXPT"      : F.MAX(F.PT)})
+        all_vars.update({"MAXDOCA"    : F.MAXSDOCA})
+        all_vars.update({"MAXDOCACHI2": F.MAXSDOCACHI2})
+        # the above in cut versions.
+         
+    if comp:
+        all_vars.update({"MINPT"    : F.MIN(F.PT)})
+        all_vars.update({"MINIP"    : F.MINIP(pvs)})
+        all_vars.update({"MINIPCHI2": F.MINIPCHI2(pvs)})
+    
+    if basic:
+        all_vars.update({"TRACKPT"     : F.TRACK_PT})
+        all_vars.update({"TRACKHISTORY": F.VALUE_OR(-1) @ F.TRACKHISTORY @ F.TRACK})
+        all_vars.update({"QOVERP"      : F.QOVERP @ F.TRACK})
+        all_vars.update({"NDOF"        : F.VALUE_OR(-1) @ F.NDOF @ F.TRACK})
+        all_vars.update({"NFTHITS"     : F.VALUE_OR(-1) @ F.NFTHITS @ F.TRACK})
+        all_vars.update({"NHITS"       : F.VALUE_OR(-1) @ F.NHITS @ F.TRACK})
+        all_vars.update({"NUTHITS"     : F.VALUE_OR(-1) @ F.NUTHITS @ F.TRACK})
+        all_vars.update({"NVPHITS"     : F.VALUE_OR(-1) @ F.NVPHITS @ F.TRACK})
+        all_vars.update({"TRACKHASVELO": F.VALUE_OR(-1) @ F.TRACKHASVELO @ F.TRACK})
+        all_vars.update({"TRACKHASUT"  : F.VALUE_OR(-1) @ F.TRACKHASUT @ F.TRACK})
+        #all_vars.update({"POS_COV_MATRIX": F.POS_COV_MATRIX})
+        #all_vars.update({"THREE_MOM_COV_MATRIX": F.THREE_MOM_COV_MATRIX})
+         
+    all_vars.update({"OBJECT_KEY": F.OBJECT_KEY})
+    all_vars.update({"PHI"       : F.PHI})
+    all_vars.update({"ABS_PX"    : F.ABS @ F.PX})
+    
+    all_vars.update({"REFERENCEPOINT_X": F.REFERENCEPOINT_X})
+    all_vars.update({"REFERENCEPOINT_Y": F.REFERENCEPOINT_Y})
+    all_vars.update({"REFERENCEPOINT_Z": F.REFERENCEPOINT_Z})
+
+    if comp:
+        if nbodydecay == 2:
+            all_vars.update({"DOCA"     : F.DOCA(Child1=1, Child2=2)})
+            all_vars.update({"DOCACHI2" : F.DOCACHI2(Child1=1, Child2=2)})
+            all_vars.update({"SDOCA"    : F.SDOCA(1, 2)})
+            all_vars.update({"SDOCACHI2": F.SDOCACHI2(1, 2)})
+            all_vars.update({"ALV"      : F.ALV(Child1=1, Child2=2)})
+        if nbodydecay == 3:
+            all_vars.update({"DOCA_12"     : F.DOCA(Child1=1, Child2=2)})
+            all_vars.update({"DOCA_13"     : F.DOCA(Child1=1, Child2=3)})
+            all_vars.update({"DOCA_23"     : F.DOCA(Child1=2, Child2=3)})
+            all_vars.update({"DOCACHI2_12" : F.DOCACHI2(Child1=1, Child2=2)})
+            all_vars.update({"DOCACHI2_13" : F.DOCACHI2(Child1=1, Child2=3)})
+            all_vars.update({"DOCACHI2_23" : F.DOCACHI2(Child1=2, Child2=3)})
+            all_vars.update({"SDOCA_12"    : F.SDOCA(Child1=1, Child2=2)})
+            all_vars.update({"SDOCA_13"    : F.SDOCA(Child1=1, Child2=3)})
+            all_vars.update({"SDOCA_23"    : F.SDOCA(Child1=2, Child2=3)})
+            all_vars.update({"SDOCACHI2_12": F.SDOCACHI2(Child1=1, Child2=2)})
+            all_vars.update({"SDOCACHI2_13": F.SDOCACHI2(Child1=1, Child2=3)})
+            all_vars.update({"SDOCACHI2_23": F.SDOCACHI2(Child1=2, Child2=3)})
+            all_vars.update({"MM12"        : F.SUBCOMB(Functor=F.MASS, Indices=(1, 2))})
+            all_vars.update({"MM13"        : F.SUBCOMB(Functor=F.MASS, Indices=(1, 3))})
+            all_vars.update({"MM23"        : F.SUBCOMB(Functor=F.MASS, Indices=(2, 3))})
+            all_vars.update({"ALV_12"      : F.ALV(Child1=1, Child2=2)})
+            all_vars.update({"ALV_13"      : F.ALV(Child1=1, Child2=3)})
+            all_vars.update({"ALV_23"      : F.ALV(Child1=2, Child2=3)})
+        if nbodydecay == 4:
+            all_vars.update({"DOCA_12"     : F.DOCA(Child1=1, Child2=2)})
+            all_vars.update({"DOCA_13"     : F.DOCA(Child1=1, Child2=3)})
+            all_vars.update({"DOCA_14"     : F.DOCA(Child1=1, Child2=4)})
+            all_vars.update({"DOCA_23"     : F.DOCA(Child1=2, Child2=3)})
+            all_vars.update({"DOCA_24"     : F.DOCA(Child1=2, Child2=4)})
+            all_vars.update({"DOCA_34"     : F.DOCA(Child1=3, Child2=4)})
+            all_vars.update({"DOCACHI2_12" : F.DOCACHI2(Child1=1, Child2=2)})
+            all_vars.update({"DOCACHI2_13" : F.DOCACHI2(Child1=1, Child2=3)})
+            all_vars.update({"DOCACHI2_14" : F.DOCACHI2(Child1=1, Child2=4)})
+            all_vars.update({"DOCACHI2_23" : F.DOCACHI2(Child1=2, Child2=3)})
+            all_vars.update({"DOCACHI2_24" : F.DOCACHI2(Child1=2, Child2=4)})
+            all_vars.update({"DOCACHI2_34" : F.DOCACHI2(Child1=3, Child2=4)})
+            all_vars.update({"SDOCA_12"    : F.SDOCA(Child1=1, Child2=2)})
+            all_vars.update({"SDOCA_13"    : F.SDOCA(Child1=1, Child2=3)})
+            all_vars.update({"SDOCA_14"    : F.SDOCA(Child1=1, Child2=4)})
+            all_vars.update({"SDOCA_23"    : F.SDOCA(Child1=2, Child2=3)})
+            all_vars.update({"SDOCA_24"    : F.SDOCA(Child1=2, Child2=4)})
+            all_vars.update({"SDOCA_34"    : F.SDOCA(Child1=3, Child2=4)})
+            all_vars.update({"SDOCACHI2_12": F.SDOCACHI2(Child1=1, Child2=2)})
+            all_vars.update({"SDOCACHI2_13": F.SDOCACHI2(Child1=1, Child2=3)})
+            all_vars.update({"SDOCACHI2_14": F.SDOCACHI2(Child1=1, Child2=4)})
+            all_vars.update({"SDOCACHI2_23": F.SDOCACHI2(Child1=2, Child2=3)})
+            all_vars.update({"SDOCACHI2_24": F.SDOCACHI2(Child1=2, Child2=4)})
+            all_vars.update({"SDOCACHI2_34": F.SDOCACHI2(Child1=3, Child2=4)})
+            all_vars.update({"MM12"        : F.SUBCOMB(Functor=F.MASS, Indices=(1, 2))})
+            all_vars.update({"MM13"        : F.SUBCOMB(Functor=F.MASS, Indices=(1, 3))})
+            all_vars.update({"MM14"        : F.SUBCOMB(Functor=F.MASS, Indices=(1, 4))})
+            all_vars.update({"MM23"        : F.SUBCOMB(Functor=F.MASS, Indices=(2, 3))})
+            all_vars.update({"MM24"        : F.SUBCOMB(Functor=F.MASS, Indices=(2, 4))})
+            all_vars.update({"MM34"        : F.SUBCOMB(Functor=F.MASS, Indices=(3, 4))})
+            all_vars.update({"ALV_12"      : F.ALV(Child1=1, Child2=2)})
+            all_vars.update({"ALV_13"      : F.ALV(Child1=1, Child2=3)})
+            all_vars.update({"ALV_14"      : F.ALV(Child1=1, Child2=4)})
+            all_vars.update({"ALV_23"      : F.ALV(Child1=2, Child2=3)})
+            all_vars.update({"ALV_24"      : F.ALV(Child1=2, Child2=4)})
+            all_vars.update({"ALV_34"      : F.ALV(Child1=3, Child2=4)})
+    if basic:
+        all_vars.update({"SHOWER_SHAPE": F.CALO_NEUTRAL_SHOWER_SHAPE})
+        
+    if comp:
+        all_vars.update({"SUMPT": F.SUM(F.PT)})
+        
+    if basic:
+        all_vars.update({"TX": F.TX})
+        all_vars.update({"TY": F.TY})
+        
+    print(f"### For {ptype} returning variables {all_vars.functor_dict.keys()}")
+    return all_vars
+
+def event_variables(PVs, ODIN):
+    """
+    event variables
+    """
+     
+    evt_vars = FC({})
+    evt_vars += EventInfo()
+    
+
+         
+    if ODIN:
+        evt_vars.update({"EVENTTYPE": F.EVENTTYPE(ODIN)})
+
+    evt_vars.update({"PV_SIZE": F.SIZE(PVs)})
+    
+
+         
+    print(f"### For event returning variables {evt_vars.functor_dict.keys()}")
+    return evt_vars
+
+##############################################################
+
+####   Lb->D0DstmKp
+
+##############################################################
+
+def alg_config_LbToD0Lz(options:Options):
+    name,line_data,my_filter={},{},{}
+    for tracktype in ["LL","DD"]:
+        for Dstate in ["HH","HHHH"]:
+            name[f"{tracktype}_{Dstate}"]=f"LbToD0Lz{tracktype}_D02{Dstate}"
+            line=f"SpruceB2OC_LbToLambda{tracktype}D0_D0To{Dstate}"
+            evtpath_prefix = "/Event/Spruce/"
+            line_data[f"{tracktype}_{Dstate}"] =get_particles(f"{evtpath_prefix}{line}/Particles")
+            my_filter[f"{tracktype}_{Dstate}"] = create_lines_filter(name=f"PreFilter_{line}", lines=[f"{line}"])
+
+    Hlt1_decisions = [ 
+        'Hlt1TrackMVADecision', 'Hlt1TwoTrackMVADecision', 'Hlt1D2KKDecision',
+        'Hlt1D2KPiDecision', 'Hlt1D2PiPiDecision',
+        'Hlt1DiMuonHighMassDecision', 'Hlt1DiMuonLowMassDecision',
+        'Hlt1DiMuonSoftDecision',
+        'Hlt1KsToPiPiDecision', 'Hlt1LowPtMuonDecision',
+        'Hlt1LowPtDiMuonDecision', 'Hlt1SingleHighPtMuonDecision',
+        'Hlt1TrackMuonMVADecision', "Hlt1DiMuonNoIP_SSDecision",
+        "Hlt1DiMuonDrellYan_VLowMassDecision",
+        "Hlt1DiMuonDrellYan_VLowMass_SSDecision",
+        "Hlt1DiMuonDrellYanDecision",
+        "Hlt1DiMuonDrellYan_SSDecision",
+        "Hlt1DetJpsiToMuMuPosTagLineDecision",
+        "Hlt1DetJpsiToMuMuNegTagLineDecision",
+        "Hlt1TrackElectronMVADecision",
+        "Hlt1SingleHighPtElectronDecision",
+        "Hlt1DiElectronDisplacedDecision",
+        "Hlt1SingleHighEtDecision",
+        "Hlt1DiPhotonHighMassDecision",
+        "Hlt1Pi02GammaGammaDecision",
+        "Hlt1DiElectronHighMass_SSDecision",
+        "Hlt1DiElectronHighMassDecision",
+        "Hlt1DiMuonNoIPDecision",
+    ]
+    Hlt2_decisions = ['Hlt2Topo2BodyDecision', 'Hlt2Topo3BodyDecision', 'Hlt2Topo4BodyDecision']
+
+
+    all_fields = {}
+    for tracktype in ["LL","DD"]:
+        all_fields[f"Lb2D0Lz{tracktype}_D02HH"] = {
+            'Lb':            '[Lambda_b0 -> ([D0]CC -> K- pi+) (Lambda0 -> p+ pi-) ]CC',
+#
+            'Dz':            '[Lambda_b0 -> ^([D0]CC -> K- pi+) (Lambda0 -> p+ pi-) ]CC',
+            'Lz':            '[Lambda_b0 -> ([D0]CC -> K- pi+) ^(Lambda0 -> p+ pi-) ]CC',
+#
+            'Dz_Km':         '[Lambda_b0 -> ([D0]CC -> ^K- pi+) (Lambda0 -> p+ pi-) ]CC',
+            'Dz_pip':        '[Lambda_b0 -> ([D0]CC -> K- ^pi+) (Lambda0 -> p+ pi-) ]CC',
+            'Lz_pp':         '[Lambda_b0 -> ([D0]CC -> K- pi+) (Lambda0 -> ^p+ pi-) ]CC',
+            'Lz_pim':        '[Lambda_b0 -> ([D0]CC -> K- pi+) (Lambda0 -> p+ ^pi-) ]CC',
+        }
+        all_fields[f"Lb2D0Lz{tracktype}_D02HHHH"] = {
+            'Lb':            '[Lambda_b0 -> ([D0]CC -> K- pi+ pi- pi+) (Lambda0 -> p+ pi-) ]CC',
+#
+            'Dz':            '[Lambda_b0 -> ^([D0]CC -> K- pi+ pi- pi+) (Lambda0 -> p+ pi-) ]CC',
+            'Lz':            '[Lambda_b0 -> ([D0]CC -> K- pi+ pi- pi+) ^(Lambda0 -> p+ pi-) ]CC',
+#
+            'Dz_Km':         '[Lambda_b0 -> ([D0]CC -> ^K- pi+ pi- pi+) (Lambda0 -> p+ pi-) ]CC',
+            'Dz_pip1':       '[Lambda_b0 -> ([D0]CC -> K- ^pi+ pi- pi+) (Lambda0 -> p+ pi-) ]CC',
+            'Dz_pim':        '[Lambda_b0 -> ([D0]CC -> K- pi+ ^pi- pi+) (Lambda0 -> p+ pi-) ]CC',
+            'Dz_pip2':       '[Lambda_b0 -> ([D0]CC -> K- pi+ pi- ^pi+) (Lambda0 -> p+ pi-) ]CC',
+            'Lz_pp':         '[Lambda_b0 -> ([D0]CC -> K- pi+ pi- pi+) (Lambda0 -> ^p+ pi-) ]CC',
+            'Lz_pim':        '[Lambda_b0 -> ([D0]CC -> K- pi+ pi- pi+) (Lambda0 -> p+ ^pi-) ]CC',
+        }
+    
+    # Creating v2 reconstructed vertices to be used in the following functor
+    pvs = get_pvs()
+
+    b_composite_variables = FC(
+        {
+        "ID"          : F.PARTICLE_ID,
+        "END_VCHI2DOF": F.CHI2DOF @ F.ENDVERTEX,
+        "BPVCHI2DOF"  : F.CHI2DOF @ F.BPV(pvs),
+        "END_VX_ERR":F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.ENDVERTEX,
+        "END_VY_ERR":F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.ENDVERTEX,
+        "END_VZ_ERR":F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.ENDVERTEX,
+        "BPVX_ERR": F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.BPV(pvs),
+        "BPVY_ERR": F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.BPV(pvs),
+        "BPVZ_ERR": F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.BPV(pvs),
+        "PERR": F.SQRT @ F.PERR2,
+        "PXERR": F.SQRT @ F.CALL(0,0) @ F.THREE_MOM_COV_MATRIX,
+        "PYERR": F.SQRT @ F.CALL(1,1) @ F.THREE_MOM_COV_MATRIX,
+        "PZERR": F.SQRT @ F.CALL(2,2) @ F.THREE_MOM_COV_MATRIX,
+        # B2OC generic B hadron NN Hlt2 algorithm,
+        # not planning to use it directly for B2OC EM
+        "MVA": F.MVA(
+            MVAType="SigmaNet",
+            Config={
+                "File":
+                "paramfile://data/Hlt2B2OC_B_SigmaNet_Run3-v2.json",
+                "Name":
+                "B2OC_SigmaNet_Generic",
+                "Lambda":
+                "2.0",
+                "NLayers":
+                "3",
+                "InputSize":
+                "6",
+                "Monotone_Constraints":
+                "[1,-1,-1,-1,-1,-1]",
+                "Variables":
+                "log_B_PT,B_ETA,log_B_DIRA,log_B_ENDVERTEX_CHI2,log_B_IPCHI2_OWNPV,log_B_IP_OWNPV",
+            },
+            Inputs={
+                "log_B_PT"            : fmath.log(F.PT),
+                "B_ETA"               : F.ETA,
+                "log_B_DIRA"          : fmath.log(1. + 1.e-6 - F.BPVDIRA(pvs)),
+                "log_B_ENDVERTEX_CHI2": fmath.log(F.CHI2DOF),
+                "log_B_IPCHI2_OWNPV"  : fmath.log(F.BPVIPCHI2(pvs)),
+                "log_B_IP_OWNPV"      : fmath.log(F.BPVIP(pvs)),
+            }),
+        }
+    )
+    composite_variables  = FC(
+        {
+            "ID"          : F.PARTICLE_ID,
+            "END_VCHI2DOF": F.CHI2DOF @ F.ENDVERTEX,
+            "END_VX_ERR":F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.ENDVERTEX,
+            "END_VY_ERR":F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.ENDVERTEX,
+            "END_VZ_ERR":F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.ENDVERTEX,
+            "BPVX_ERR": F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.BPV(pvs),
+            "BPVY_ERR": F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.BPV(pvs),
+            "BPVZ_ERR": F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.BPV(pvs),
+            "PERR": F.SQRT @ F.PERR2,
+            "PXERR": F.SQRT @ F.CALL(0,0) @ F.THREE_MOM_COV_MATRIX,
+            "PYERR": F.SQRT @ F.CALL(1,1) @ F.THREE_MOM_COV_MATRIX,
+            "PZERR": F.SQRT @ F.CALL(2,2) @ F.THREE_MOM_COV_MATRIX,
+        }
+    )
+    com_vars={}
+    for tracktype in ["LL","DD"]:
+        for Dstate in ["HH","HHHH"]:
+            com_vars[f"{tracktype}_{Dstate}"]=composite_variables+HltTisTos( selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=line_data[f"{tracktype}_{Dstate}"])+HltTisTos( selection_type="Hlt2", trigger_lines=Hlt2_decisions, data=line_data[f"{tracktype}_{Dstate}"])
+
+    daughter_variables = FC(
+        {
+            "ID"             : F.PARTICLE_ID,
+            "PIDK"           : F.PID_K,
+            "PIDp"           : F.PID_P,
+            "PIDe"           : F.PID_E,
+            "PIDmu"          : F.PID_MU,
+            "ProbNNp"        : F.PROBNN_P,
+            "ProbNNpi"       : F.PROBNN_PI,
+            "ProbNNk"        : F.PROBNN_K,
+        }
+    )
+    variables={}
+    for tracktype in ["LL","DD"]:
+        for Dstate in ["HH","HHHH"]:
+            variables[f"{tracktype}_{Dstate}"]={
+                "Lb"     : all_variables(pvs, _composite, 2) + b_composite_variables + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _composite),
+                "Lz"     : all_variables(pvs, _composite, 2) + composite_variables  + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _composite),
+                "Lz_pp"     : all_variables(pvs, _basic       ) + daughter_variables    + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _basic),
+                "Lz_pim"     : all_variables(pvs, _basic       ) + daughter_variables    + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _basic),
+            }
+            if Dstate=="HH":
+                variables[f"{tracktype}_{Dstate}"]["Dz"]     = all_variables(pvs, _composite, 2) + composite_variables  + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _composite)
+                variables[f"{tracktype}_{Dstate}"]["Dz_Km"]    = all_variables(pvs, _basic       ) + daughter_variables   + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _basic)
+                variables[f"{tracktype}_{Dstate}"]["Dz_pip"]       = all_variables(pvs, _basic       ) + daughter_variables   + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _basic)
+            elif Dstate=="HHHH":
+                variables[f"{tracktype}_{Dstate}"]["Dz"]     = all_variables(pvs, _composite, 4) + composite_variables  + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _composite)
+                variables[f"{tracktype}_{Dstate}"]["Dz_Km"]    = all_variables(pvs, _basic       ) + daughter_variables   + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _basic)
+                variables[f"{tracktype}_{Dstate}"]["Dz_pip1"]       = all_variables(pvs, _basic       ) + daughter_variables   + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _basic)
+                variables[f"{tracktype}_{Dstate}"]["Dz_pim"]       = all_variables(pvs, _basic       ) + daughter_variables   + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _basic)
+                variables[f"{tracktype}_{Dstate}"]["Dz_pip2"]       = all_variables(pvs, _basic       ) + daughter_variables   + make_dtf_variables_lb2d0lz(pvs, line_data[f"{tracktype}_{Dstate}"], _basic)
+            else:
+                print("expect HH or HHHH!")
+                exit()
+
+    if options.simulation:
+        # get configured "MCTruthAndBkgCatAlg" algorithm for HLT2 output
+        mctruth = MCTruthAndBkgCat(line_data[f"{tracktype}_{Dstate}"])
+        # add helper lambda that configures a functor to get truth information
+        MCTRUTH = lambda func: F.MAP_INPUT(Functor=func, Relations=mctruth.MCAssocTable)
+        trueid_bkgcat_info = {
+            # Important note: specify an invalid value for integer functors if there exists no truth info.
+            #                 The invalid value for floating point functors is set to nan.
+            "TRUEID"          : F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID),
+            "TRUEKEY"         : F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY),
+            "TRUEPT"          : MCTRUTH(F.PT),
+            "TRUEPX"          : MCTRUTH(F.PX),
+            "TRUEPY"          : MCTRUTH(F.PY),
+            "TRUEPZ"          : MCTRUTH(F.PZ),
+            "TRUEENERGY"      : MCTRUTH(F.ENERGY),
+            "TRUEP"           : MCTRUTH(F.P),
+            "TRUEFOURMOMENTUM": MCTRUTH(F.FOURMOMENTUM),
+            "BKGCAT"          : F.BKGCAT(Relations=mctruth.BkgCatTable),
+        }
+        for field in variables[f"{tracktype}_{Dstate}"].keys():
+            variables[f"{tracktype}_{Dstate}"][field] += FC(trueid_bkgcat_info)
+
+    #define event level variables
+    odin = get_odin()
+    decreports = None
+    rec_sum=get_rec_summary()
+    evt_variables = event_variables(pvs, odin) + FC({
+        "nPVs": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nPVs"),
+        "nTTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nTTracks"),
+        "nLongTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nLongTracks"),
+        "nDownstreamTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nDownstreamTracks"),
+        "nUpstreamTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nUpstreamTracks"),
+        "nVeloTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nVeloTracks"),
+        "nBackTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nBackTracks"),
+        "nRich1Hits": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nRich1Hits"),
+        "nRich2Hits": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nRich2Hits"),
+        "nVPClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nVPClusters"),
+        "nFTClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nFTClusters"),
+        "eCalTot": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"eCalTot"),
+        "hCalTot": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"hCalTot"),
+        "nEcalClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nEcalClusters"),
+        "ALLPVX": F.ALLPVX(pvs),
+        "ALLPVY": F.ALLPVY(pvs),
+        "ALLPVZ": F.ALLPVZ(pvs),
+    })
+
+    evt_variables += SelectionInfo(
+        selection_type="Hlt1", trigger_lines=Hlt1_decisions
+    )
+    evt_variables += SelectionInfo(
+        selection_type="Hlt2", trigger_lines=Hlt2_decisions
+    )
+
+
+    # define FunTuple instance
+    user_algorithms = {}
+    my_tuple={}
+    for tracktype in ["LL","DD"]:
+        for Dstate in ["HH","HHHH"]:
+            my_tuple[f"{tracktype}_{Dstate}"] = Funtuple(
+                name=f"{tracktype}_{Dstate}",
+                tuple_name="DecayTree",
+                fields=all_fields[f"Lb2D0Lz{tracktype}_D02{Dstate}"],
+                variables=variables[f"{tracktype}_{Dstate}"],
+                event_variables=evt_variables,
+                inputs=line_data[f"{tracktype}_{Dstate}"],
+                store_multiple_cand_info=True
+            )
+            user_algorithms[f"{tracktype}_{Dstate}"]= [my_filter[f"{tracktype}_{Dstate}"], my_tuple[f"{tracktype}_{Dstate}"]]
+    
+
+    return make_config(options, user_algorithms)
+
+
+
diff --git a/Lb2D0Lz_run3/info.yaml b/Lb2D0Lz_run3/info.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..94da0a598ad20f3a675a7ec946f29db2885eea3d
--- /dev/null
+++ b/Lb2D0Lz_run3/info.yaml
@@ -0,0 +1,40 @@
+defaults:
+  application: "DaVinci/v64r10@x86_64_v2-el9-clang16-opt"
+  output: DATA.ROOT
+  inform:
+    - dong.ao@cern.ch
+  wg: B2OC
+
+{%- set datasets = [
+ ('2024Data', 'MagDown', '24c2'),
+ ('2024Data', 'MagUp', '24c2'),
+ ('2024Data', 'MagUp', '24c3'),
+ ('2024Data', 'MagDown', '24c3'),
+ ('2024Data', 'MagDown', '24c4'),
+]%}
+
+
+
+{%- for evttype, polarity, campain in datasets %}
+
+Lb2D0Lz_{{ evttype }}_{{ polarity }}_{{ campain }}:
+  options:  
+    entrypoint: Lb2D0Lz_run3.dv_Lb2D0Lz:alg_config_LbToD0Lz
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
+      simulation: False
+      data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce" # for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "b2oc" # for streamed data
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-{{ polarity }}/Real Data/Sprucing{{ campain }}/90000000/B2OC.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    keep_running: true
+    n_test_lfns: 1 
+
+{%- endfor %}