diff --git a/Run3_LcD0_SMOG2/Run3_LcD0_SMOG2.py b/Run3_LcD0_SMOG2/Run3_LcD0_SMOG2.py
new file mode 100644
index 0000000000000000000000000000000000000000..db3252796c159ff5af2710c689f440111b9765f0
--- /dev/null
+++ b/Run3_LcD0_SMOG2/Run3_LcD0_SMOG2.py
@@ -0,0 +1,346 @@
+from DaVinci import Options, make_config
+from DaVinci.algorithms import create_lines_filter
+from PyConf.reading import get_particles, get_pvs, get_rec_summary
+from Hlt2Conf.algorithms_thor import ParticleFilter, ParticleCombiner
+from Hlt2Conf.standard_particles import *
+# from Hlt2Conf.utils import get_dtf_variables
+from Functors.math import in_range, sqrt, pow
+# from Hlt2Conf.lines.ift.builders.smog2_builders import (
+#     make_smog2_common_particles,
+#     make_smog2_prefilters,
+# )
+
+# from ..tools.tupling_maker import *
+# from ..tools.make_dtf import *
+import Functors as F
+from FunTuple import FunctorCollection 
+import FunTuple.functorcollections as FC
+from FunTuple import FunTuple_Particles as Funtuple
+import Functors.math as fmath
+from GaudiKernel.SystemOfUnits import MeV, mm, picosecond, ps
+from FunTuple.functorcollections import (
+    MCHierarchy,
+    MCPromptDecay,
+    Kinematics,
+    SelectionInfo,
+    HltTisTos,
+    MCVertexInfo,
+    MCKinematics,
+    ParticleID, #wrong variables PID_PI = 0, PROBNN_D = nan
+    EventInfo,
+    LHCInfo,
+    ParticleIsolation,
+    MCPrimaries,
+    MCReconstructed,
+    MCReconstructible,
+)
+from DecayTreeFitter import DecayTreeFitter
+import sys
+
+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),
+                "M" : F.MASS,
+                
+            }
+        )
+        + Kinematics()
+    )
+
+    addstring = "DTF"
+    if(pv_constraint):
+            addstring += '_PV'
+    if(mass_constraint):
+            addstring += '_M'
+    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_'+ 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_'+ 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(pvs, input_data, constrain, constrainPDG):
+    from DecayTreeFitter import DecayTreeFitter
+
+    DTFvtxmassConstrain = DecayTreeFitter(
+        name=f'DTF_PV_Constrain_{{hash}}',
+        input_particles=input_data,
+        input_pvs=pvs,
+        mass_constraints=[constrainPDG])
+
+
+    dtf_vars = make_composite_dtf_variables(pvs, input_data,
+                                            DTF=DTFvtxmassConstrain,
+                                            pv_constraint=True,
+                                            mass_constraint=True, particle_name=constrain)
+    return dtf_vars
+
+
+def main(options: Options):
+
+    hlt1lines_muon = [ "Hlt1SMOG2SingleMuonDecision", "Hlt1SMOG2DiMuonHighMassDecision"]
+    hlt1lines_BE = [ "Hlt1SMOG2BENoBiasDecision", "Hlt1SMOG2PassThroughLowMult5Decision", "Hlt1SMOG2BELowMultElectronsDecision"]
+    hlt1lines_MB = [ "Hlt1SMOG2MinimumBiasDecision", "Hlt1PassthroughPVinSMOG2Decision"]
+        
+    hlt1lines_track = [ "Hlt1SMOG2SingleTrackHighPtDecision", "Hlt1SMOG2SingleTrackVeryHighPtDecision", "Hlt1SMOG22BodyGenericDecision", "Hlt1SMOG22BodyGenericPromptDecision"]
+    hlt1lines_hadron = [ "Hlt1SMOG2etacToppDecision", "Hlt1SMOG2D2KpiDecision"]
+    hlt1lines_longlived = [ "Hlt1SMOG2L0ToppiDecision", "Hlt1SMOG2KsTopipiDecision"]
+    hlt1lines_pp = [ "Hlt1TrackMVADecision", "Hlt1TrackMuonMVADecision", "Hlt1TwoTrackMVADecision"]
+
+    hlt1lines = []
+    hlt1lines += hlt1lines_muon
+    hlt1lines += hlt1lines_BE
+    hlt1lines += hlt1lines_MB
+    hlt1lines += hlt1lines_track
+    hlt1lines += hlt1lines_hadron
+    hlt1lines += hlt1lines_longlived
+    hlt1lines += hlt1lines_pp
+    Hlt1_decisions = hlt1lines
+
+    names = [ "D0Kpi",
+              "LcpKpi",
+    ]
+
+    full_line_list = { "D0Kpi":'SpruceIFT_SMOG2D02KPi', #no persistent reco
+                       "LcpKpi":'SpruceIFT_SMOG2LcTopKPi',
+    }
+    parts = { 'D0Kpi':["D0", "Km", "pip"], 
+              'LcpKpi':["Lc", "pp", "Km", "pip"],
+              }
+    
+    fields = { 'D0Kpi':{"D0": "[D0 -> K- pi+]CC",
+                                       "Km": "[D0 ->^K- pi+]CC",
+                                       "pip": "[D0 -> K- ^pi+]CC",
+                                       },
+                'LcpKpi':{"Lc": "[Lambda_c+ -> p+ K- pi+]CC",
+                                       "pp": "[Lambda_c+ -> ^p+ K- pi+]CC",
+                                       "Km": "[Lambda_c+ -> p+ ^K- pi+]CC",
+                                       "pip": "[Lambda_c+ -> p+ K- ^pi+]CC",
+                                       },
+              }
+
+    v2_pvs      = get_pvs()
+    rec_summary = get_rec_summary()
+    all_variables = FunctorCollection({ 'ID': F.PARTICLE_ID, 
+                                        'KEY': F.OBJECT_KEY, 
+                                        'CHARGE': F.CHARGE, 
+                                        'PT': F.PT, 
+                                        'PX': F.PX, 
+                                        'PY': F.PY,
+                                        'PZ': F.PZ,
+                                        'ETA': F.ETA,
+                                        'PHI': F.PHI,
+                                        'YSTAR':0.5*fmath.log( (F.ENERGY+F.PZ)/(F.ENERGY-F.PZ))-4.79,
+                                        'Y':0.5*fmath.log( (F.ENERGY+F.PZ)/(F.ENERGY-F.PZ)),
+                                        'MASS':F.MASS, 
+                                        'ENERGY': F.ENERGY,
+                                        'P': F.P,
+                                        'FOURMOMENTUM': F.FOURMOMENTUM,
+                                        'CHI2': F.CHI2, 
+                                        'CHI2DOF': F.CHI2DOF,
+                                        'B_PV_Z':F.BPVZ(v2_pvs),
+                                        'B_PV_X':F.BPVX(v2_pvs),
+                                        'B_PV_Y':F.BPVY(v2_pvs),
+                                        'BPVIP': F.BPVIP(v2_pvs),
+                                        'BPVIPCHI2': F.BPVIPCHI2(v2_pvs),
+                                        'nBestPVTracks':    F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.SIZE_OF @ F.PVTRACKS @ F.BPV(v2_pvs),
+                                        'nBestPVbackTracks':    F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.COUNT_IF( F.TRACKISVELOBACKWARD ) @ F.PVTRACKS @ F.BPV(v2_pvs),
+                                        })
+
+    parent_variables = FunctorCollection({ 'DOCA': F.DOCA(Child1=1, Child2=2), 
+                                           'DOCACHI2': F.DOCACHI2(Child1=1, Child2=2),
+                                           'SDOCA': F.SDOCA(Child1=1, Child2=2), 
+                                           'SDOCACHI2': F.SDOCACHI2(Child1=1, Child2=2),
+                                           'END_VX': F.END_VX, 
+                                           'END_VY': F.END_VY, 
+                                           'END_VZ': F.END_VZ, 
+                                           'END_VRHO': F.END_VRHO,
+                                           'BPVFDCHI2': F.BPVFDCHI2(v2_pvs),
+                                           'BPVLTIME': F.BPVLTIME(v2_pvs),
+                                           'BPVFD': F.BPVFD(v2_pvs), 
+                                           'BPVDIRA': F.BPVDIRA(v2_pvs),
+                                           })
+    
+    children_variables = FunctorCollection({ 'PIDE':F.PID_E, 
+                                             'PIDK':F.PID_K, 
+                                             'PIDMU':F.PID_MU, 
+                                             'PIDP':F.PID_P, 
+                                             'PIDPI':F.PID_PI,
+                                             'PROBNNE':F.PROBNN_E, 
+                                             'PROBNNK':F.PROBNN_K, 
+                                             'PROBNNMU':F.PROBNN_MU, 
+                                             'PROBNNP':F.PROBNN_P, 
+                                             'PROBNNPI':F.PROBNN_PI,
+                                             'PROBNNGHOST':F.PROBNN_GHOST, 
+                                             'PROBNND':F.PROBNN_D, 
+                                             'GHOSTPROB':F.GHOSTPROB, 
+                                             'ISMUON':F.ISMUON,
+                                             'IS_NOT_H': F.IS_NOT_H, 
+                                             'IS_PHOTON': F.IS_PHOTON,
+                                             'TRACK_NVPHITS':F.VALUE_OR(-1) @ F.NVPHITS @ F.TRACK,
+                                             'TRACK_NFTHITS':F.VALUE_OR(-1) @ F.NFTHITS @ F.TRACK,
+                                             'TRACK_NUTHITS':F.VALUE_OR(-1) @ F.NUTHITS @ F.TRACK,
+                                             "TRACK_POS_CLOSESTTOBEAM_X": F.POSITION_X @ F.STATE_AT("ClosestToBeam") @ F.TRACK,
+                                             "TRACK_POS_CLOSESTTOBEAM_Y": F.POSITION_Y @ F.STATE_AT("ClosestToBeam") @ F.TRACK,
+                                             "TRACK_POS_CLOSESTTOBEAM_Z": F.POSITION_Z @ F.STATE_AT("ClosestToBeam") @ F.TRACK,
+                                             })
+    
+    evt_vars = FunctorCollection(
+        {   "FILLNUMBER":   F.VALUE_OR(-1) @ F.FILL_NUMBER,
+            "nLongTracks":  F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks"),
+            'nUpTracks':    F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nUpstreamTracks"),
+            'nDownTracks':  F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nDownstreamTracks"),
+            'nBackTracks':  F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nBackTracks"),
+            "nVeloTracks":  F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nVeloTracks"),
+            "nMuonTracks":  F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nMuonTracks"),
+            "nTracks":      F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks"),
+            "nTTracks":     F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTTracks"), 
+
+            "nVeloClusters":F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nVeloClusters"),
+            "nVPClusters":  F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nVPClusters"),
+            "nFTClusters":  F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nFTClusters"),
+            "nRich1Hits":   F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nRich1Hits"),
+            "nRich2Hits":   F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nRich2Hits"),
+            "eCalTot":      F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "eCalTot"),
+            "hCalTot":      F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "hCalTot"),
+            "nEcalClusters":F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nEcalClusters"),
+            "nMuonCoordsS0":F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nMuonCoordsS0"),
+            "nMuonCoordsS1":F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nMuonCoordsS1"),
+            "nMuonCoordsS2":F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nMuonCoordsS2"),
+            "nMuonCoordsS3":F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nMuonCoordsS3"),
+            "nMuonCoordsS4":F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nMuonCoordsS4"),
+            
+            "nPVs":              F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs"),
+            "PVZ[nPV]":          F.VALUE_OR(-1) @ F.ALLPVZ(v2_pvs),
+            "PVX[nPV]":          F.VALUE_OR(-1) @ F.ALLPVX(v2_pvs),
+            "PVY[nPV]":          F.VALUE_OR(-1) @ F.ALLPVY(v2_pvs),
+            "ALLPVX_ERR[nPV]":   F.VALUE_OR(-1) @ F.MAP(F.SQRT @ F.CALL(0, 0) @ F.POS_COV_MATRIX) @ F.TES(v2_pvs),
+            "ALLPVY_ERR[nPV]":   F.VALUE_OR(-1) @ F.MAP(F.SQRT @ F.CALL(1, 1) @ F.POS_COV_MATRIX) @ F.TES(v2_pvs),
+            "ALLPVZ_ERR[nPV]":   F.VALUE_OR(-1) @ F.MAP(F.SQRT @ F.CALL(2, 2) @ F.POS_COV_MATRIX) @ F.TES(v2_pvs),
+            "PVCHI2NDOF[nPV]":   F.VALUE_OR(-1) @ F.MAP( F.CHI2DOF ) @ F.TES(v2_pvs),
+            "PVCHI2[nPV]":       F.VALUE_OR(-1) @ F.MAP( F.CHI2 ) @ F.TES(v2_pvs),
+            "PVNDOF[nPV]":       F.VALUE_OR(-1) @ F.MAP( F.NDOF ) @ F.TES(v2_pvs),
+            'nPVTracks[nPV]':    F.VALUE_OR(-1) @ F.MAP( F.CAST_TO_INT @ F.SIZE_OF @ F.PVTRACKS ) @ F.TES(v2_pvs),
+            'nPVbackTracks[nPV]':F.VALUE_OR(-1) @ F.MAP( F.CAST_TO_INT @ F.COUNT_IF( F.TRACKISVELOBACKWARD ) @ F.PVTRACKS ) @ F.TES(v2_pvs),
+        }
+    )
+
+    evt_vars += FC.EventInfo()
+    evt_vars += FC.SMOGInfo()
+    evt_vars += FC.SelectionInfo( selection_type="Hlt1", trigger_lines=Hlt1_decisions ) # hlt1 trigger decisions
+
+    d_input_data, d_variables, d_mytuple = {},{},{}
+
+    for line in names:
+        d_input_data[line] = get_particles('/Event/Spruce/'+full_line_list[line]+'/Particles') #CharmPions/Particles
+        # input_data_tuple = d_input_data[line]
+        # long_muons = make_long_muons()
+        # long_pions = make_long_pions()
+        # long_protons = make_long_protons()
+        # long_kaons = make_long_kaons()
+        # long_rich_pions = make_has_rich_long_pions()
+        # long_rich_kaons = make_has_rich_long_kaons()
+        # long_rich_protons = make_has_rich_long_protons()
+        if line == "D0Kpi":
+            D0Spruced = ParticleFilter(d_input_data[line], Cut=F.FILTER(F.require_all(
+                in_range(1800.*MeV, F.MASS, 1940.*MeV),
+                F.BPVDIRA(get_pvs()) > 0.999,
+                F.CHI2DOF < 50)
+            ))
+            output_data_tuple = D0Spruced
+        if line == "LcpKpi":
+            LcSpruced = ParticleFilter(d_input_data[line], Cut=F.FILTER(F.require_all(
+                in_range(2000.*MeV, F.MASS, 2550.*MeV),
+                F.BPVDIRA(get_pvs()) > 0.999,
+                F.CHI2DOF < 50)
+            ))
+            output_data_tuple = LcSpruced
+
+        TisTos_variables = FC.HltTisTos( selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=output_data_tuple )
+
+        d_variables[line] = { parts[line][0]:all_variables+TisTos_variables+parent_variables }
+
+        for ichildren in range( 1, len(parts[line]) ): 
+            d_variables[line][parts[line][ichildren]] = all_variables+TisTos_variables+children_variables
+
+
+        d_mytuple[line] = Funtuple( line, 
+                                    'DecayFunTuple',
+                                    fields=fields[line], 
+                                    variables=d_variables[line], 
+                                    event_variables=evt_vars, 
+                                    inputs=output_data_tuple,
+                                    store_multiple_cand_info=True )
+
+    alg_list = []
+    for line in names: alg_list += [ d_mytuple[line] ]
+
+    config = make_config( options, alg_list ) 
+    return config
+
+
+
+
+
diff --git a/Run3_LcD0_SMOG2/info.yaml b/Run3_LcD0_SMOG2/info.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..27eba146c2be16d393037ef05433e4120bf1c7d2
--- /dev/null
+++ b/Run3_LcD0_SMOG2/info.yaml
@@ -0,0 +1,49 @@
+defaults:
+  inform:
+    - nicolas.schmidt@cern.ch
+  wg: IFT
+
+# data configuration
+{%- set datasets = [
+  ('Collision24', 'Sprucing24c2/90000000','c2', 'MagUp'),
+  ('Collision24', 'Sprucing24c3/90000000','c3', 'MagUp'),
+  ('Collision24', 'Sprucing24c4/90000000','c4', 'MagUp'),
+  ('Collision24', 'Sprucing24c2/90000000','c2', 'MagDown'),
+  ('Collision24', 'Sprucing24c3/90000000','c3', 'MagDown'),
+]%}
+
+{%- for data, Type, typekey, polarity in datasets %}
+
+SMOG2_2024__{{typekey}}_{{polarity}}_Spruce:
+  application: DaVinci/v64r14@x86_64_v2-el9-clang16-opt
+  input:
+    bk_query: "/LHCb/{{data}}/Beam6800GeV-VeloClosed-{{polarity}}/Real Data/{{Type}}/IFT.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    smog2_state:
+      - Argon
+      - Helium
+      - Hydrogen
+      - Neon
+      - ArgonUnstable
+      - HeliumUnstable
+      - HydrogenUnstable
+      - NeonUnstable
+    keep_running: True
+    n_test_lfns: 2
+  output: OHF_SMOG2_{{data}}{{typekey}}.root
+  options:
+    entrypoint: Run3_LcD0_SMOG2.Run3_LcD0_SMOG2:main
+    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" 
+      input_stream: "ift"
+
+{%- endfor %}
+