diff --git a/Run3_LambdaBX3872/dv_data_B2JPSIKpi.py b/Run3_LambdaBX3872/dv_data_B2JPSIKpi.py
new file mode 100644
index 0000000000000000000000000000000000000000..4509fc40ce4934cc4a6498d5fd677953a00e34e5
--- /dev/null
+++ b/Run3_LambdaBX3872/dv_data_B2JPSIKpi.py
@@ -0,0 +1,13 @@
+import Functors as F
+from Functors.math import in_range, sqrt, pow
+
+
+from .tuplemakers.tuplemaker_all import *
+
+
+
+def entry_point(options: Options):
+
+    algs = B2JPSIKpiTupleMaker()
+
+    return make_config(options, algs)
diff --git a/Run3_LambdaBX3872/dv_data_BLambX.py b/Run3_LambdaBX3872/dv_data_BLambX.py
new file mode 100644
index 0000000000000000000000000000000000000000..976de70d07e4c01268dde9a4f54fadd1c912be1c
--- /dev/null
+++ b/Run3_LambdaBX3872/dv_data_BLambX.py
@@ -0,0 +1,15 @@
+import Functors as F
+from Functors.math import in_range, sqrt, pow
+
+
+from .tuplemakers.tuplemaker_all import *
+
+
+
+def entry_point(options: Options):
+
+    algs = B2JPSIKpiTupleMaker()
+    algs.update(LamB02JPsiKpTupleMaker())
+    algs.update(X38722JPsipipiTupleMaker())
+
+    return make_config(options, algs)
diff --git a/Run3_LambdaBX3872/dv_data_JPSImumu.py b/Run3_LambdaBX3872/dv_data_JPSImumu.py
new file mode 100644
index 0000000000000000000000000000000000000000..9af3ce05d2e6f79463983690727a8310442782a0
--- /dev/null
+++ b/Run3_LambdaBX3872/dv_data_JPSImumu.py
@@ -0,0 +1,13 @@
+import Functors as F
+from Functors.math import in_range, sqrt, pow
+
+
+from .tuplemakers.tuplemaker_all import *
+
+
+
+def entry_point(options: Options):
+
+    algs = JPSI2mumuTupleMaker()
+
+    return make_config(options, algs)
diff --git a/Run3_LambdaBX3872/dv_data_LamB02JPsiKp.py b/Run3_LambdaBX3872/dv_data_LamB02JPsiKp.py
new file mode 100644
index 0000000000000000000000000000000000000000..53566e51067a336bbf86735e29ea10b88614b7bc
--- /dev/null
+++ b/Run3_LambdaBX3872/dv_data_LamB02JPsiKp.py
@@ -0,0 +1,13 @@
+import Functors as F
+from Functors.math import in_range, sqrt, pow
+
+
+from .tuplemakers.tuplemaker_all import *
+
+
+
+def entry_point(options: Options):
+
+    algs = LamB02JPsiKpTupleMaker()
+
+    return make_config(options, algs)
diff --git a/Run3_LambdaBX3872/dv_data_X38722JPsipipi.py b/Run3_LambdaBX3872/dv_data_X38722JPsipipi.py
new file mode 100644
index 0000000000000000000000000000000000000000..98fdb7659e8442693c67a3eaa2f949160285b39d
--- /dev/null
+++ b/Run3_LambdaBX3872/dv_data_X38722JPsipipi.py
@@ -0,0 +1,13 @@
+import Functors as F
+from Functors.math import in_range, sqrt, pow
+
+
+from .tuplemakers.tuplemaker_all import *
+
+
+
+def entry_point(options: Options):
+
+    algs = X38722JPsipipiTupleMaker()
+
+    return make_config(options, algs)
diff --git a/Run3_LambdaBX3872/info.yaml b/Run3_LambdaBX3872/info.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f9be246c8019ce74e812629006b7593278a42a7d
--- /dev/null
+++ b/Run3_LambdaBX3872/info.yaml
@@ -0,0 +1,86 @@
+defaults:
+    application: "DaVinci/v64r13"
+    wg: IFT
+    inform:
+        - nicolas.schmidt@cern.ch
+
+# data configuration
+{%- set datasets = [
+  ('Collision24', 'Sprucing24c2/90000000','c2', 'IFT', 'BLambX',  'MagUp', 'Spruce', 'ift'),
+  ('Collision24', 'Sprucing24c3/90000000','c3', 'IFT', 'BLambX',  'MagUp', 'Spruce', 'ift'),
+  ('Collision24', 'Sprucing24c2/90000000','c2', 'IFT', 'BLambX',  'MagDown', 'Spruce', 'ift'),
+  ('Collision24', 'Sprucing24c3/90000000','c3', 'IFT', 'BLambX',  'MagDown', 'Spruce', 'ift'),
+]%}
+
+
+  # ('Collision24', 'Sprucing24c2/90000000','c2', 'IFT', 'X38722JPsipipi',  'MagUp', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c2/90000000','c2', 'IFT', 'B2JPSIKpi',  'MagUp', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c2/90000000','c2', 'IFT', 'LamB02JPsiKp',  'MagUp', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c3/90000000','c3', 'IFT', 'X38722JPsipipi',  'MagUp', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c3/90000000','c3', 'IFT', 'B2JPSIKpi',  'MagUp', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c3/90000000','c3', 'IFT', 'LamB02JPsiKp',  'MagUp', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c2/90000000','c2', 'IFT', 'X38722JPsipipi',  'MagDown', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c2/90000000','c2', 'IFT', 'B2JPSIKpi',  'MagDown', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c2/90000000','c2', 'IFT', 'LamB02JPsiKp',  'MagDown', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c3/90000000','c3', 'IFT', 'X38722JPsipipi',  'MagDown', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c3/90000000','c3', 'IFT', 'B2JPSIKpi',  'MagDown', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c3/90000000','c3', 'IFT', 'LamB02JPsiKp',  'MagDown', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c4/90000000','c4', 'IFT', 'X38722JPsipipi',  'MagUp', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c4/90000000','c4', 'IFT', 'B2JPSIKpi',  'MagUp', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c4/90000000','c4', 'IFT', 'LamB02JPsiKp',  'MagUp', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c4/90000000','c4', 'IFT', 'X38722JPsipipi',  'MagDown', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c4/90000000','c4', 'IFT', 'B2JPSIKpi',  'MagDown', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c4/90000000','c4', 'IFT', 'LamB02JPsiKp',  'MagDown', 'Spruce', 'ift'),
+
+# ,
+#   ('Collision24', 'Sprucing24c2/90000000','c2', 'IFT', 'LAMB2JPSIKP',  'MagUp', 'VeloClosed', 'Spruce', 'ift'),
+#   ('Collision24', 'Sprucing24c3/90000000','c3', 'IFT', 'LAMB2JPSIKP',  'MagDown', 'VeloClosed', 'Spruce', 'ift'),
+#   ('Collision24', 'Sprucing24c3/90000000','c3', 'IFT', 'LAMB2JPSIKP',  'MagUp', 'VeloClosed', 'Spruce', 'ift'),
+#   ('Collision24', 'Sprucing24c4/90000000','c4', 'IFT', 'LAMB2JPSIKP',  'MagDown', 'VeloClosed', 'Spruce', 'ift'),
+#   ('Collision24', 'Sprucing24c4/90000000','c4', 'IFT', 'LAMB2JPSIKP',  'MagUp', 'VeloClosed', 'Spruce', 'ift'),
+  # ('Collision24', 'Sprucing24c4/90000000','c4', 'BANDQ', 'X38722JPsipipi',  'MagUp', 'VeloClosed', 'Spruce', 'bandq'),
+  # ('Collision24', 'Sprucing24c4/90000000','c4', 'BANDQ', 'B2JPSIKpi',  'MagUp', 'VeloClosed', 'Spruce', 'bandq'),
+  # ('Collision24', 'Sprucing24c4/90000000','c4', 'BANDQ', 'LamB02JPsiKp',  'MagUp', 'VeloClosed', 'Spruce', 'bandq'),
+  # ('Collision24', 'Sprucing24c4/90000000','c2', 'IFT', 'JPSImumu',  'MagUp', 'Spruce', 'ift'),
+
+{%- set dv_platform_detdesc = "x86_64_v2-el9-clang16-opt" %}
+
+{%- for data, Type, typekey, wg, decay, polarity, process, stream in datasets %}
+                                                                                                                                         
+data_{{decay}}_{{wg}}_{{typekey}}_VeloClosed_WithUT_{{polarity}}:
+    application: "DaVinci/v64r13@{{dv_platform_detdesc}}"
+    input:
+      bk_query: "/LHCb/{{data}}/Beam6800GeV-VeloClosed-{{polarity}}/Real Data/{{Type}}/{{wg}}.DST"
+      dq_flags:
+        - OK
+      extended_dq_ok:
+        - SMOG2
+      smog2_state:
+        - Argon
+        - Helium
+        - Hydrogen
+        - Neon
+        - ArgonUnstable
+        - HeliumUnstable
+        - HydrogenUnstable
+        - NeonUnstable
+
+      keep_running: True 
+      n_test_lfns: 3
+    options:
+      entrypoint: Run3_LambdaBX3872.dv_data_BLambX:entry_point
+      extra_options:
+        input_type: ROOT
+        input_process: "{{process}}"
+        input_stream: "{{stream}}"
+        input_raw_format: 0.5
+        ntuple_basketsize: 4096
+        simulation: False
+        data_type: "Upgrade"
+        geometry_version: run3/2024.Q1.2-v00.00
+        conditions_version: master
+    output: Data_{{stream}}_{{data}}{{typekey}}_BLambX.root
+    # output: Data_{{stream}}_{{data}}{{typekey}}_{{decay}}.root
+    #comment 
+{%- endfor %}
+
diff --git a/Run3_LambdaBX3872/tools/make_dtf.py b/Run3_LambdaBX3872/tools/make_dtf.py
new file mode 100644
index 0000000000000000000000000000000000000000..dddfc8c4ec463ef65adfb37b1f37f44589fdbc8c
--- /dev/null
+++ b/Run3_LambdaBX3872/tools/make_dtf.py
@@ -0,0 +1,254 @@
+import Functors as F
+from Functors.math import log
+
+from FunTuple import FunctorCollection
+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 DaVinciMCTools import MCTruthAndBkgCat, MCReconstructed, MCReconstructible
+from PyConf.Algorithms import ParticleToSubcombinationsAlg
+from DecayTreeFitter import DecayTreeFitter
+
+from DaVinci.algorithms import create_lines_filter
+from PyConf.reading import get_particles
+from FunTuple import FunTuple_Particles as Funtuple
+
+
+
+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,
+                "M" : F.MASS,
+            }
+        )
+        + Kinematics()
+    )
+
+    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
+        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
+
+    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),
+                "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, ptype):
+
+    if ptype not in ["basic", "composite"]:
+        Exception(f"Need \'basic\' or \'composite\'. Got {ptype}")
+
+    from DecayTreeFitter import DecayTreeFitter
+    
+    DTF = DecayTreeFitter(
+        name=f'DTF_{{hash}}',
+        input_particles=input_data)
+
+    DTFvtx = DecayTreeFitter(
+        name=f'DTF_PV_{{hash}}',
+        input_particles=input_data,
+        input_pvs=pvs)
+
+    DTFmassJpsi = DecayTreeFitter(
+        name=f'DTF_Jpsi_{{hash}}',
+        input_particles=input_data,
+        mass_constraints=["J/psi(1S)"])
+
+    DTFvtxmassJpsi = DecayTreeFitter(
+        name=f'DTF_PV_Jpsi_{{hash}}',
+        input_particles=input_data,
+        input_pvs=pvs,
+        mass_constraints=["J/psi(1S)"])
+
+    # DTFmassJpsiX = DecayTreeFitter(
+    #     name=f'DTF_Jpsi_X3872_{{hash}}',
+    #     input_particles=input_data,
+    #     mass_constraints=["J/psi(1S)", "X_1(3872)"])
+
+    # DTFvtxmassJpsiX = DecayTreeFitter(
+    #     name=f'DTF_PV_Jpsi_X3872_{{hash}}',
+    #     input_particles=input_data,
+    #     input_pvs=pvs,
+    #     mass_constraints=["J/psi(1S)", "X_1(3872)"])
+
+    # DTFmassBcJpsi = DecayTreeFitter(
+    #     name=f'DTFmassBcJpsi_{{hash}}',
+    #     input_particles=input_data,
+    #     mass_constraints=["B_c+","J/psi(1S)"])
+
+    # DTFvtxmassBcJpsi = DecayTreeFitter(
+    #     name=f'DTFvtxmassBcJpsi_{{hash}}',
+    #     input_particles=input_data,
+    #     input_pvs=pvs,
+    #     mass_constraints=["B_c+","J/psi(1S)"])
+
+
+    if ptype == "basic":
+        dtf_vars = make_basic_dtf_variables(pvs, input_data,
+                                            DTF=DTFvtx,
+                                            pv_constraint=True,
+                                            mass_constraint=False)
+        dtf_vars += make_basic_dtf_variables(pvs, input_data,
+                                             DTF=DTFvtxmassJpsi,
+                                             pv_constraint=True,
+                                             mass_constraint=True, particle_name="Jpsi")
+        # dtf_vars += make_basic_dtf_variables(pvs, input_data,
+        #                                      DTF=DTFvtxmassJpsiX,
+        #                                      pv_constraint=True,
+        #                                      mass_constraint=True, particle_name="Jpsi_X3872")
+
+        return dtf_vars
+
+    if ptype == "composite":
+        dtf_vars = make_composite_dtf_variables(pvs, input_data,
+                                            DTF=DTFvtx,
+                                            pv_constraint=True,
+                                            mass_constraint=False)
+        dtf_vars += make_composite_dtf_variables(pvs, input_data,
+                                             DTF=DTFvtxmassJpsi,
+                                             pv_constraint=True,
+                                             mass_constraint=True, particle_name="Jpsi")
+        # dtf_vars += make_composite_dtf_variables(pvs, input_data,
+        #                                      DTF=DTFvtxmassJpsiX,
+        #                                      pv_constraint=True,
+        #                                      mass_constraint=True, particle_name="Jpsi_X3872")
+
+        return dtf_vars
+
diff --git a/Run3_LambdaBX3872/tools/tupling_maker.py b/Run3_LambdaBX3872/tools/tupling_maker.py
new file mode 100644
index 0000000000000000000000000000000000000000..ba14a77da3e169c79451413a11515d45786dbbe7
--- /dev/null
+++ b/Run3_LambdaBX3872/tools/tupling_maker.py
@@ -0,0 +1,369 @@
+from DaVinci import make_config, Options
+from DaVinci.algorithms import create_lines_filter
+
+from PyConf.reading import get_rec_summary, get_pvs
+from PyConf.reading import get_particles
+
+import FunTuple.functorcollections as FC
+import Functors as F
+from FunTuple import FunctorCollection
+
+from FunTuple import FunTuple_Event
+from FunTuple import FunTuple_Particles
+#  from .descriptor_writer import *
+
+
+#from PyConf.reading import (get_particles, get_charged_protoparticles, get_pvs, get_rec_summary, _get_unpacked)
+
+from Functors.math import in_range
+from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
+
+from RecoConf.event_filters import require_pvs
+
+from Hlt2Conf.standard_particles import get_long_track_selector, standard_protoparticle_filter
+from PyConf.Algorithms import FunctionalParticleMaker
+from PyConf.reading import get_charged_protoparticles as _make_charged_protoparticles 
+from PyConf.reading import get_odin
+
+from GaudiKernel.SystemOfUnits import MeV, picosecond, mm, GeV
+from DecayTreeFitter import DecayTreeFitter
+
+_basic = "basic"
+_composite = "composite"
+_toplevel = "toplevel"
+
+def all_variables(pvs, mctruth, ptype, candidates=None, ftAlg=None):
+
+    if ptype not in [_basic, _composite]:
+        Exception(f"I want {_basic} or {_composite}. Got {ptype}")
+    all_vars = FunctorCollection({})
+
+    comp = _composite == ptype or _toplevel == ptype  # is composite
+    basic = _basic == ptype  # is not composite
+    top = _toplevel == ptype  # the B
+
+    all_vars += FC.Kinematics() # Add some usual variables: M, P, PTXYZ, E
+
+    if basic:
+        all_vars += FC.ParticleID(extra_info=True) # Add ProbNN and PID for basic partiels
+
+    if comp:
+        all_vars.update({"ALV": F.ALV(Child1=1, Child2=2)})
+
+    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)})
+    all_vars.update({"ALLPVX": F.ALLPVX(pvs)})
+    all_vars.update({"ALLPVY": F.ALLPVY(pvs)})
+    all_vars.update({"ALLPVZ": F.ALLPVZ(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 top:  # apply this only to B
+    #    all_vars.update({"CHILD1_PT": F.CHILD(1, F.PT)})  # example of CHILD
+    #    all_vars.update({"Ds_END_VZ": F.CHILD(1, F.END_VZ)})
+    #    all_vars.update({"Delta_END_VZ_DsB0": F.CHILD(1, F.END_VZ) - F.END_VZ})
+
+    if comp:
+        #all_vars.update({"DOCA": F.SDOCA(Child1=1, Child2=2)})
+        #all_vars.update({"DOCACHI2": F.SDOCACHI2(Child1=1, Child2=2)})
+        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})
+
+    # duplicated from FC   all_vars.update({"ENERGY" : F.ENERGY})
+    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})
+        all_vars.update({"TRACK_MOM_": F.TRACK_MOMVEC})
+        all_vars.update({"TRACK_POS_CLOSESTTOBEAM_": F.TRACK_POSVEC_CLOSESTTOBEAM})
+        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})
+
+    if comp:
+        all_vars.update({"MAXPT": F.MAX(F.PT)})
+        all_vars.update({"MAXDOCA": F.MAXSDOCA})
+        all_vars.update({"MAXDOCACHI2": F.MAXSDOCACHI2})
+        #all_vars.update({"MINDOCA": F.MINSDOCA})
+        #all_vars.update({"MINDOCACHI2": F.MINSDOCACHI2})
+        # the above in cut versions.
+
+    # duplicated from FC    all_vars.update({ 'MC_MOTHER_ID' : F.VALUE_OR(0) @ mctruth(
+    # duplicated from FC        F.MC_MOTHER(1, F.PARTICLE_ID))})
+
+    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({"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:
+        all_vars.update({"SDOCA12": F.SDOCA(1, 2)})
+        all_vars.update({"SDOCA12_CHI2": F.SDOCACHI2(1, 2)})
+    if basic:
+        all_vars.update({"SHOWER_SHAPE": F.CALO_NEUTRAL_SHOWER_SHAPE})
+
+    if comp:
+        all_vars.update({"SUBCOMB12_MM": F.SUBCOMB(Functor=F.MASS, Indices=(1, 2))})
+        all_vars.update({"SUMPT": F.SUM(F.PT)})
+    if top:
+        all_vars.update({"SDOCA13": F.SDOCA(1, 3)})
+        all_vars.update({"SDOCA13_CHI2": F.SDOCACHI2(1, 3)})
+        all_vars.update({"SDOCA23": F.SDOCA(2, 3)})
+        all_vars.update({"SDOCA23_CHI2": F.SDOCACHI2(2, 3)})
+        all_vars.update({"SUBCOMB13_MM": F.SUBCOMB(Functor=F.MASS, Indices=(1, 3))})
+        all_vars.update({"SUBCOMB23_MM": F.SUBCOMB(Functor=F.MASS, Indices=(2, 3))})
+
+    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 tistos_variables(Hlt1_decisions, Hlt2_decisions, data, isturbo):
+    tistos_vars = FunctorCollection({})
+    tistos_vars += FC.HltTisTos( selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=data)
+    if not isturbo:
+        tistos_vars += FC.HltTisTos( selection_type="Hlt2", trigger_lines=Hlt2_decisions, data=data)
+    return tistos_vars
+
+def event_variables(PVs, ODIN, decreports, rec_sum, hlt1_lines, sprucing_lines):
+    """
+    event variables
+    """
+
+    ## Some empty summaries removed
+    evt_vars = FunctorCollection({
+        "nPVs": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nPVs"),
+        "nTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nTracks"),
+        "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"),
+        "nGhosts": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nGhosts"),
+        "nRich1Hits": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nRich1Hits"),
+        "nRich2Hits": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nRich2Hits"),
+        #"nVeloClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nVeloClusters"),
+        "nVPClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nVPClusters"),
+        #"nITClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nITClusters"),
+        #"nTTClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nTTClusters"),
+        "nUTClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nUTClusters"),
+        #"nOTClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nOTClusters"),
+        "nFTClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nFTClusters"),
+        #"nSPDhits": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nSPDhits"),
+        "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"),
+        #"nMuonCoordsS0": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nMuonCoordsS0"),
+        #"nMuonCoordsS1": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nMuonCoordsS1"),
+        #"nMuonCoordsS2": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nMuonCoordsS2"),
+        #"nMuonCoordsS3": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nMuonCoordsS3"),
+        #"nMuonCoordsS4": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nMuonCoordsS4"),
+        #"nMuonTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nMuonTracks"),
+        "ALLPVX": F.ALLPVX(PVs),
+        "ALLPVY": F.ALLPVY(PVs),
+        "ALLPVZ": F.ALLPVZ(PVs),
+        })
+    evt_vars += FC.EventInfo()
+    evt_vars += FC.SMOGInfo()
+    evt_vars += FC.SelectionInfo( selection_type="Hlt1", trigger_lines=hlt1_lines)                                               
+    evt_vars += FC.SelectionInfo( selection_type="Hlt2", trigger_lines=sprucing_lines)
+    # duplicated from FC    if ODIN:
+    # duplicated from FC        evt_vars.update({ 'BUNCHCROSSING_ID' : F.BUNCHCROSSING_ID(ODIN)})
+    # duplicated from FC        evt_vars.update({ 'BUNCHCROSSING_TYPE' : F.BUNCHCROSSING_TYPE(ODIN)})
+
+    if decreports:
+        evt_vars.update(
+                {
+                    "DECISIONS": F.DECISIONS(
+                        Lines=[bd2dsk_line + "Decision"], DecReports=decreports
+                        )
+                    }
+                )
+        evt_vars.update(
+                {
+                    "DECREPORTS_FILTER": F.DECREPORTS_FILTER(
+                        Lines=[bd2dsk_line + "Decision"], DecReports=decreports
+                        )
+                    }
+                )
+
+    if ODIN:
+        evt_vars.update({"EVENTTYPE": F.EVENTTYPE(ODIN)})
+
+    # duplicated from FC        evt_vars.update({ 'GPSTIME' : F.GPSTIME(ODIN)})
+    # duplicated from FC        evt_vars.update({ 'ODINTCK' : F.ODINTCK(ODIN)})
+
+    evt_vars.update({"PV_SIZE": F.SIZE(PVs)})
+    # duplicated from FC        evt_vars.update({ 'GPSTIME' : F.GPSTIME(ODIN)})
+    # duplicated from FC        evt_vars.update({ 'ODINTCK' : F.ODINTCK(ODIN)})
+
+    if decreports:
+        evt_vars.update({"TCK": F.TCK(decreports)})
+
+    print(f"### For event returning variables {evt_vars.functor_dict.keys()}")
+    return evt_vars
+
+#  def candidate_variables(pvs, particles):
+#      abbrs = default_names(particles)
+#      names = all_particles(particles)
+#      variables_B = {abbr: all_variables(pvs, None, particle_df["type"][name]) for abbr, name in zip(abbrs, names)}
+#      return variables_B
+#  from DecayTreeFitter import DecayTreeFitter
+#  def make_dtf_variables(pvs, data, particles, pv_constraint=False, mass_constraints=[]):
+#
+#      abbrs = default_names(particles)
+#      names = all_particles(particles)
+#
+#      if pv_constraint: dtf_name = "DTF_PV_"
+#      else: dtf_name = "DTF_"
+#      dtf_name += "".join(f"{par}_" for par in particle_df["abbr"][mass_constraints])
+#
+#      DTF = DecayTreeFitter(
+#              name = f"{dtf_name}DecayTreeFitter",
+#              input_particles = data,
+#              input_pvs = (pv_constraint and pvs),
+#              mass_constraints = mass_constraints,
+#              )
+#
+#      dtf_dict = {}
+#
+#      shared_variables = FunctorCollection(
+#                  {   "ETA": F.ETA,
+#                      "PHI": F.PHI,
+#                      "BPVIPCHI2": F.BPVIPCHI2(pvs),
+#                      "BPVIP": F.BPVIP(pvs),
+#                      "BPVX": F.BPVX(pvs),
+#                      "BPVY": F.BPVY(pvs),
+#                      "BPVZ": F.BPVZ(pvs),
+#                      }
+#                  ) + FC.Kinematics()
+#
+#      dtf_quality_variables = FunctorCollection( {
+#              dtf_name+"_DTFCHI2": DTF.CHI2,
+#              dtf_name+"_DTFNDOF": DTF.NDOF,
+#              dtf_name+"_CTAU": DTF.CTAU,
+#              dtf_name+"_CTAUERR": DTF.CTAUERR,
+#              dtf_name+"_MERR": DTF.MASSERR,
+#              }
+#          )
+#
+#      #make branches
+#      for abbr, name in zip(abbrs, names):
+#          is_basic = particle_df["type"][name]
+#          if is_basic:
+#              orig_variables = shared_variables + FunctorCollection(
+#                      {   "TX"          : F.TX,
+#                          "TY"          : F.TY,
+#                          "MINIPCHI2"   : F.MINIPCHI2(pvs),
+#                          "MINIP"       : F.MINIP(pvs),
+#                          "KEY"         : F.VALUE_OR(-1) @ F.OBJECT_KEY @ F.TRACK,
+#                          "TRGHOSTPROB": F.GHOSTPROB,
+#                          "TRACKPT": F.TRACK_PT,
+#                          "TRACKHISTORY": F.VALUE_OR(-1) @ F.TRACKHISTORY @ F.TRACK,
+#                          "QOVERP": F.QOVERP @ F.TRACK,
+#                          "TRCHI2DOF": F.CHI2DOF @ F.TRACK,
+#                          "NDOF": F.VALUE_OR(-1) @ F.NDOF @ F.TRACK,
+#                          }
+#                      )
+#          else:
+#              orig_variables = shared_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),
+#                      "CHI2DOF": F.CHI2DOF, #CHI2VXNDOF
+#                      "BPVFDCHI2": F.BPVFDCHI2(pvs),
+#                      "BPVFD": F.BPVFD(pvs),
+#                      "BPVVDRHO": F.BPVVDRHO(pvs),
+#                      "BPVVDZ": F.BPVVDZ(pvs),
+#                      "BPVLTIME": F.BPVLTIME(pvs),
+#                      "END_VX": F.END_VX, #END_
+#                      "END_VY": F.END_VY,
+#                      "END_VZ": F.END_VZ,
+#                      }
+#                  )
+#              orig_variables += dtf_quality_variables
+#
+#          dtf_variables = FunctorCollection({ dtf_name + expr: DTF(func) for expr, func in orig_variables.get_thor_functors().items() })
+#          dtf_dict.update( {abbr: dtf_variables} )
+#
+#      return dtf_dict
+#
+#
diff --git a/Run3_LambdaBX3872/tuplemakers/tuplemaker_all.py b/Run3_LambdaBX3872/tuplemakers/tuplemaker_all.py
new file mode 100644
index 0000000000000000000000000000000000000000..57fccf15c96e50f2093de8b9bb3b8aed5a2ea266
--- /dev/null
+++ b/Run3_LambdaBX3872/tuplemakers/tuplemaker_all.py
@@ -0,0 +1,382 @@
+import Functors as F
+from Functors.math import in_range, sqrt, pow
+
+from ..tools.tupling_maker import *
+from ..tools.make_dtf import *
+
+from PyConf.reading import get_pvs, get_rec_summary, get_particles, get_odin
+
+from Hlt2Conf.standard_particles import make_long_pions, make_long_kaons, make_long_protons
+from Hlt2Conf.algorithms_thor import ParticleFilter, ParticleCombiner
+
+from GaudiKernel.SystemOfUnits import MeV, mm
+
+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
+
+Hlt2_decisions = [ "Hlt2IFTFull_SMOG2Jpsi2MuMuDecision", "Hlt2IFTFull_SMOG2LowDiMuonDecision",
+                "Hlt2IFTFull_SMOG2Jpsi2MuMuSSDecision", "Hlt2IFTFull_SMOG2LowDiMuonSSDecision",
+                "Hlt2IFTFull_SMOG2GECPassthroughDecision",
+                "Hlt2IFTFull_SMOG2Passthrough_PV_in_SMOG2Decision",
+                "Hlt2IFTFull_SMOG2MBPassthroughDecision"
+    ]
+Hlt2_TISTOS = [
+        "Hlt2IFTFull_SMOG2LowDiMuon",
+        "Hlt2IFTFull_SMOG2LowDiMuonSS",
+        "Hlt2IFTFull_SMOG2Jpsi2MuMu",
+        "Hlt2IFTFull_SMOG2Jpsi2MuMuSS"]
+
+
+def X38722JPsipipiTupleMaker():
+
+    # sprucing_line = 'SpruceIFT_SMOG2Jpsi2MuMu' #'SpruceBandQ_JpsiToMuMuDetached'
+    sprucing_line = 'SpruceIFT_SMOG2Jpsi2MuMu' #'SpruceBandQ_JpsiToMuMuDetached'
+    Jpsi_spruce = get_particles(f"/Event/Spruce/{sprucing_line}/Particles")
+    # Jpsi_spruce = get_particles(f"/Event/Particles")
+
+    rec_sum = get_rec_summary()
+    v2_pvs = get_pvs()
+    odin = get_odin()
+    decreports = None
+
+    DaughterCutPi = F.require_all(F.MINIPCHI2(get_pvs()) > 4., F.PT > 150*MeV, F.PROBNN_PI > 0.2, F.GHOSTPROB < 0.3)
+    DaughterCutJpsi = F.require_all(in_range(3000.*MeV, F.MASS, 3200.*MeV))
+    
+
+    long_pions = make_long_pions()
+
+    pions = ParticleFilter(long_pions, Cut=F.FILTER(DaughterCutPi))
+    Jpsi = ParticleFilter(Jpsi_spruce, Cut=F.FILTER(DaughterCutJpsi))
+
+
+    B2XKp = ParticleCombiner(
+            [Jpsi, pions, pions],
+            DecayDescriptor="[X_1(3872) -> J/psi(1S) pi+ pi-]cc",
+            name="X38722JPsipipi_line_validation_{hash}",
+            # CombinationCut=F.require_all(in_range(3000.*MeV, F.MASS, 5000.*MeV)),
+            # CompositeCut=F.require_all(F.BPVDIRA(get_pvs()) > 0.995,
+            #                            F.CHI2 < 50, 
+            #                            sqrt(pow(F.BPVVDX(get_pvs()), 2) 
+            #                                 + pow(F.BPVVDY(get_pvs()), 2) 
+            #                                 + pow(F.BPVVDZ(get_pvs()), 2)) > 1.5*mm, 
+            #                            in_range(3000.*MeV, F.MASS, 5000.*MeV)),
+            )
+
+    comp_particles = ["X3872", "Jpsi"]
+    basic_particles = ["mup_Jpsi", "mum_Jpsi", "pip", "pim"]
+   
+    X38722JPsipipi_Descriptor = {
+            "X3872" : '[X_1(3872) -> (J/psi(1S) -> mu+ mu-) pi+ pi-]CC',
+            "Jpsi" : '[X_1(3872) -> ^(J/psi(1S) -> mu+ mu-) pi+ pi-]CC',
+            "mup_Jpsi" : '[X_1(3872) -> (J/psi(1S) -> ^mu+ mu-) pi+ pi-]CC',
+            "mum_Jpsi" : '[X_1(3872) -> (J/psi(1S) -> mu+ ^mu-) pi+ pi-]CC',
+            "pip" : '[X_1(3872) -> (J/psi(1S) -> mu+ mu-) ^pi+ pi-]CC',
+            "pim" : '[X_1(3872) -> (J/psi(1S) -> mu+ mu-) pi+ ^pi-]CC',
+            } 
+
+    X38722JPsipipi_Vars = {
+            "X3872": all_variables(v2_pvs, None, "toplevel"),
+            "Jpsi": all_variables(v2_pvs, None, "composite"),
+            "mup_Jpsi": all_variables(v2_pvs, None, "basic"),
+            "mum_Jpsi": all_variables(v2_pvs, None, "basic"),
+            "pip": all_variables(v2_pvs, None, "basic"),
+            "pim": all_variables(v2_pvs, None, "basic"),
+            }
+
+
+    line_prefilter = create_lines_filter(name=f"PreFilter_{sprucing_line}_{hash}", lines=[sprucing_line])
+    evt_vars = event_variables(v2_pvs, odin, decreports, rec_sum, Hlt1_decisions, Hlt2_decisions)
+    tistos_vars = tistos_variables(Hlt1_decisions, Hlt2_TISTOS, B2XKp, False)
+
+    for particle in comp_particles:
+        X38722JPsipipi_Vars[particle] += tistos_vars
+        X38722JPsipipi_Vars[particle] += make_dtf_variables(v2_pvs, B2XKp, "composite")
+    for particle in basic_particles:
+        X38722JPsipipi_Vars[particle] += make_dtf_variables(v2_pvs, B2XKp, "basic")
+
+    X38722JPsipipi_Tuple = FunTuple_Particles(name="X38722JPsipipi", 
+                                          tuple_name="DecayTree", 
+                                          fields=X38722JPsipipi_Descriptor,
+                                          variables=X38722JPsipipi_Vars, 
+                                          inputs=B2XKp, 
+                                          event_variables=evt_vars,
+                                          store_multiple_cand_info=True,
+                                          store_run_event_numbers=True)
+
+    algs = {f"X38722JPsipipi_Tuple": [ X38722JPsipipi_Tuple, line_prefilter ],}
+
+    return algs
+
+
+
+def LamB02JPsiKpTupleMaker():
+
+    # sprucing_line = 'SpruceIFT_SMOG2Jpsi2MuMu' #'SpruceBandQ_JpsiToMuMuDetached'
+    # sprucing_line = 'Hlt2IFTTurbo_SMOG2DisplacedDiMuon' #'SpruceBandQ_JpsiToMuMuDetached'
+    # sprucing_line = 'Hlt2IFTTurbo_SMOG2DisplacedDiMuon' #'SpruceBandQ_JpsiToMuMuDetached'
+    sprucing_line = 'SpruceIFT_SMOG2Jpsi2MuMu' #'SpruceBandQ_JpsiToMuMuDetached'
+    Jpsi_spruce = get_particles(f"/Event/Spruce/{sprucing_line}/Particles")
+    # Jpsi_spruce = get_particles(f"/Event/HLT2/{sprucing_line}/Particles")
+    # Jpsi_spruce = get_particles(f"/Event/Particles")
+
+    rec_sum = get_rec_summary()
+    v2_pvs = get_pvs()
+    odin = get_odin()
+    decreports = None
+
+    DaughterCutK = F.require_all(F.MINIPCHI2(get_pvs()) > 4., F.PT > 150*MeV, F.PROBNN_K > 0.2, F.GHOSTPROB < 0.3)
+    DaughterCutP = F.require_all(F.MINIPCHI2(get_pvs()) > 4., F.PT > 150*MeV, F.PROBNN_P > 0.2, F.GHOSTPROB < 0.3)
+    DaughterCutJpsi = F.require_all(in_range(3000.*MeV, F.MASS, 3200.*MeV))
+    
+
+    long_kaons = make_long_kaons()
+    long_protons = make_long_protons()
+
+    kaons = ParticleFilter(long_kaons, Cut=F.FILTER(DaughterCutK))
+    protons = ParticleFilter(long_protons, Cut=F.FILTER(DaughterCutP))
+    Jpsi = ParticleFilter(Jpsi_spruce, Cut=F.FILTER(DaughterCutJpsi))
+
+    # X2Jpsipipi = ParticleCombiner(
+    #         [Jpsi, pions, pions], ## component
+    #         DecayDescriptor="[J/psi -> mu+ mu-]cc", ## decay descriptor  
+    #         name="JpsiToMuMu_Detached_line_validation_{hash}",
+    #         CombinationCut=F.require_all(in_range(3300.*MeV, F.MASS, 4000.*MeV)),
+    #         CompositeCut=F.require_all(in_range(3500.*MeV, F.MASS, 4000.*MeV)),
+    #         )
+
+    Lb2JPsiKp = ParticleCombiner(
+            [Jpsi, kaons, protons],
+            DecayDescriptor="[Lambda_b0 -> J/psi(1S) K- p+]cc",
+            name="Lamb02JPsiKp_line_validation_{hash}",
+            # CombinationCut=F.require_all(in_range(4500.*MeV, F.MASS, 6500.*MeV)),
+            # CompositeCut=F.require_all(F.BPVDIRA(get_pvs()) > 0.995,
+            #                            F.CHI2 < 50, 
+            #                            sqrt(pow(F.BPVVDX(get_pvs()), 2) 
+            #                                 + pow(F.BPVVDY(get_pvs()), 2) 
+            #                                 + pow(F.BPVVDZ(get_pvs()), 2)) > 1.5*mm, 
+            #                            in_range(4500.*MeV, F.MASS, 6500.*MeV)),
+            )
+
+    comp_particles = ["Lambda_b0", "Jpsi"]
+    basic_particles = ["mup_Jpsi", "mum_Jpsi", "Km", "pp"]
+   
+    LamB02JPsiKp_Descriptor = {
+            "Lambda_b0" : '[Lambda_b0 -> (J/psi(1S) -> mu+ mu-) K- p+]CC',
+            "Jpsi" : '[Lambda_b0 -> ^(J/psi(1S) -> mu+ mu-) K- p+]CC',
+            "mup_Jpsi" : '[Lambda_b0 -> (J/psi(1S) -> ^mu+ mu-) K- p+]CC',
+            "mum_Jpsi" : '[Lambda_b0 -> (J/psi(1S) -> mu+ ^mu-) K- p+]CC',
+            "Km" : '[Lambda_b0 -> (J/psi(1S) -> mu+ mu-) ^K- p+]CC',
+            "pp" : '[Lambda_b0 -> (J/psi(1S) -> mu+ mu-) K- ^p+]CC',
+            } 
+
+    LamB02JPsiKp_Vars = {
+            "Lambda_b0": all_variables(v2_pvs, None, "toplevel"),
+            "Jpsi": all_variables(v2_pvs, None, "composite"),
+            "mup_Jpsi": all_variables(v2_pvs, None, "basic"),
+            "mum_Jpsi": all_variables(v2_pvs, None, "basic"),
+            "Km": all_variables(v2_pvs, None, "basic"),
+            "pp": all_variables(v2_pvs, None, "basic"),
+            }
+
+
+    line_prefilter = create_lines_filter(name=f"PreFilter_{sprucing_line}_{hash}", lines=[sprucing_line])
+    evt_vars = event_variables(v2_pvs, odin, decreports, rec_sum, Hlt1_decisions, Hlt2_decisions)
+    tistos_vars = tistos_variables(Hlt1_decisions, Hlt2_TISTOS, Lb2JPsiKp, False)
+
+    for particle in comp_particles:
+        LamB02JPsiKp_Vars[particle] += tistos_vars
+        LamB02JPsiKp_Vars[particle] += make_dtf_variables(v2_pvs, Lb2JPsiKp, "composite")
+    for particle in basic_particles:
+        LamB02JPsiKp_Vars[particle] += make_dtf_variables(v2_pvs, Lb2JPsiKp, "basic")
+
+    LamB02JPsiKp_Tuple = FunTuple_Particles(name="Lamb02JPSIKmPp", 
+                                          tuple_name="DecayTree", 
+                                          fields=LamB02JPsiKp_Descriptor,
+                                          variables=LamB02JPsiKp_Vars, 
+                                          inputs=Lb2JPsiKp, 
+                                          event_variables=evt_vars,
+                                          store_multiple_cand_info=True,
+                                          store_run_event_numbers=True)
+
+    algs = {f"Lamb02JPSIKmPp_Tuple": [ LamB02JPsiKp_Tuple, line_prefilter ],}
+
+    return algs
+
+
+
+def B2JPSIKpiTupleMaker():
+
+    # sprucing_line = 'SpruceIFT_SMOG2Jpsi2MuMu' #'SpruceBandQ_JpsiToMuMuDetached'
+    sprucing_line = 'SpruceIFT_SMOG2Jpsi2MuMu' #'SpruceBandQ_JpsiToMuMuDetached'
+    Jpsi_spruce = get_particles(f"/Event/Spruce/{sprucing_line}/Particles")
+    # Jpsi_spruce = get_particles(f"/Event/Particles")
+
+    rec_sum = get_rec_summary()
+    v2_pvs = get_pvs()
+    odin = get_odin()
+    decreports = None
+
+    DaughterCutK = F.require_all(F.MINIPCHI2(get_pvs()) > 4., F.PT > 150*MeV, F.PROBNN_K > 0.2, F.GHOSTPROB < 0.3)
+    DaughterCutPi = F.require_all(F.MINIPCHI2(get_pvs()) > 4., F.PT > 150*MeV, F.PROBNN_PI > 0.2, F.GHOSTPROB < 0.3)
+    DaughterCutJpsi = F.require_all(in_range(3000.*MeV, F.MASS, 3200.*MeV))
+    
+
+    long_kaons = make_long_kaons()
+    long_pions = make_long_pions()
+
+    kaons = ParticleFilter(long_kaons, Cut=F.FILTER(DaughterCutK))
+    pions = ParticleFilter(long_pions, Cut=F.FILTER(DaughterCutPi))
+    Jpsi = ParticleFilter(Jpsi_spruce, Cut=F.FILTER(DaughterCutJpsi))
+
+    # X2Jpsipipi = ParticleCombiner(
+    #         [Jpsi, pions, pions], ## component
+    #         DecayDescriptor="[J/psi -> mu+ mu-]cc", ## decay descriptor  
+    #         name="JpsiToMuMu_Detached_line_validation_{hash}",
+    #         CombinationCut=F.require_all(in_range(3300.*MeV, F.MASS, 4000.*MeV)),
+    #         CompositeCut=F.require_all(in_range(3500.*MeV, F.MASS, 4000.*MeV)),
+    #         )
+
+    B2XKpi = ParticleCombiner(
+            [Jpsi, kaons, pions],
+            DecayDescriptor="[B0 -> J/psi(1S) K+ pi-]cc",
+            name="B02JPsiKpi_line_validation_{hash}",
+            # CombinationCut=F.require_all(in_range(4500.*MeV, F.MASS, 6000*MeV)),
+            # CompositeCut=F.require_all(F.BPVDIRA(get_pvs()) > 0.995,
+            #                            F.CHI2 < 50, 
+            #                            sqrt(pow(F.BPVVDX(get_pvs()), 2) 
+            #                                 + pow(F.BPVVDY(get_pvs()), 2) 
+            #                                 + pow(F.BPVVDZ(get_pvs()), 2)) > 1.5*mm, 
+            #                            in_range(4500.*MeV, F.MASS, 6000*MeV)),
+            )
+
+    comp_particles = ["B0", "Jpsi"]
+    basic_particles = ["mup_Jpsi", "mum_Jpsi", "Kp", "pim"]
+   
+    B2JPSIKpi_Descriptor = {
+            "B0" : '[B0 -> (J/psi(1S) -> mu+ mu-) K+ pi-]CC',
+            "Jpsi" : '[B0 -> ^(J/psi(1S) -> mu+ mu-) K+ pi-]CC',
+            "mup_Jpsi" : '[B0 -> (J/psi(1S) -> ^mu+ mu-) K+ pi-]CC',
+            "mum_Jpsi" : '[B0 -> (J/psi(1S) -> mu+ ^mu-) K+ pi-]CC',
+            "Kp" : '[B0 -> (J/psi(1S) -> mu+ mu-) ^K+ pi-]CC',
+            "pim" : '[B0 -> (J/psi(1S) -> mu+ mu-) K+ ^pi-]CC',
+            } 
+
+    B2JPSIKpi_Vars = {
+            "B0": all_variables(v2_pvs, None, "toplevel"),
+            "Jpsi": all_variables(v2_pvs, None, "composite"),
+            "mup_Jpsi": all_variables(v2_pvs, None, "basic"),
+            "mum_Jpsi": all_variables(v2_pvs, None, "basic"),
+            "Kp": all_variables(v2_pvs, None, "basic"),
+            "pim": all_variables(v2_pvs, None, "basic"),
+            }
+
+    # hlt1_trigger_lines = [ 'Hlt1TrackMVADecision',
+    #                        'Hlt1TwoTrackMVADecision',
+    #                        'Hlt1D2KKDecision',
+    #                        'Hlt1D2KPiDecision', 
+    #                        'Hlt1D2PiPiDecision',
+    #                        'Hlt1DiMuonHighMassDecision', 
+    #                        'Hlt1DiMuonLowMassDecision',
+    #                        'Hlt1DiMuonSoftDecision',
+    #                        'Hlt1KsToPiPiDecision',
+    #                        'Hlt1LowPtMuonDecision',
+    #                        'Hlt1LowPtDiMuonDecision',
+    #                        'Hlt1SingleHighPtMuonDecision',
+    #                        'Hlt1TrackMuonMVADecision']
+
+
+    line_prefilter = create_lines_filter(name=f"PreFilter_{sprucing_line}_{hash}", lines=[sprucing_line])
+    evt_vars = event_variables(v2_pvs, odin, decreports, rec_sum, Hlt1_decisions, Hlt2_decisions)
+    tistos_vars = tistos_variables(Hlt1_decisions, Hlt2_TISTOS, B2XKpi, False)
+    # evt_vars = event_variables(v2_pvs, odin, decreports, rec_sum, hlt1_trigger_lines, [sprucing_line])
+    # tistos_vars = tistos_variables(hlt1_trigger_lines, ["Hlt2Topo2BodyDecision", "Hlt2Topo3BodyDecision", "Hlt2_JpsiToMuMuDetachedFullDecision", "Hlt2_Psi2SToMuMuDetachedFull"], Jpsi, False)
+
+    for particle in comp_particles:
+        B2JPSIKpi_Vars[particle] += tistos_vars
+        B2JPSIKpi_Vars[particle] += make_dtf_variables(v2_pvs, B2XKpi, "composite")
+    for particle in basic_particles:
+        B2JPSIKpi_Vars[particle] += make_dtf_variables(v2_pvs, B2XKpi, "basic")
+
+    B2JPSIKpi_Tuple = FunTuple_Particles(name="B02JPSIKpPim", 
+                                          tuple_name="DecayTree", 
+                                          fields=B2JPSIKpi_Descriptor,
+                                          variables=B2JPSIKpi_Vars, 
+                                          inputs=B2XKpi, 
+                                          event_variables=evt_vars,
+                                          store_multiple_cand_info=True,
+                                          store_run_event_numbers=True)
+
+    algs = {f"B02JPSIKpPim_Tuple": [ B2JPSIKpi_Tuple, line_prefilter ],}
+
+    return algs
+
+def JPSI2mumuTupleMaker():
+
+    sprucing_line = 'SpruceIFT_SMOG2Jpsi2MuMu' #'SpruceBandQ_JpsiToMuMuDetached'
+    Jpsi_spruce = get_particles(f"/Event/Spruce/{sprucing_line}/Particles")
+
+    rec_sum = get_rec_summary()
+    v2_pvs = get_pvs()
+    odin = get_odin()
+    decreports = None
+
+    comp_particles = ["Jpsi"]
+    basic_particles = ["mup", "mum"]
+   
+
+    jpsi_decaydescriptor = {
+        "Jpsi": "[J/psi(1S) -> mu+ mu-]CC",
+        "mup": "[J/psi(1S) -> ^mu+ mu-]CC",
+        "mum": "[J/psi(1S) -> mu+ ^mu-]CC",
+    }
+
+    B2JPSIKpi_Vars = {
+            "Jpsi": all_variables(v2_pvs, None, "composite"),
+            "mup": all_variables(v2_pvs, None, "basic"),
+            "mum": all_variables(v2_pvs, None, "basic"),
+            }
+
+
+
+    line_prefilter = create_lines_filter(name=f"PreFilter_{sprucing_line}_{hash}", lines=[sprucing_line])
+
+    evt_vars = event_variables(v2_pvs, odin, decreports, rec_sum, Hlt1_decisions, Hlt2_decisions)
+    tistos_vars = tistos_variables(Hlt1_decisions, Hlt2_TISTOS, Jpsi_spruce, False)
+
+    for particle in comp_particles:
+        B2JPSIKpi_Vars[particle] += tistos_vars
+        B2JPSIKpi_Vars[particle] += make_dtf_variables(v2_pvs, Jpsi_spruce, "composite")
+    for particle in basic_particles:
+        B2JPSIKpi_Vars[particle] += make_dtf_variables(v2_pvs, Jpsi_spruce, "basic")
+
+    JPSI_Tuple = FunTuple_Particles(name="JPSIMUMU", 
+                                          tuple_name="DecayTree", 
+                                          fields=jpsi_decaydescriptor,
+                                          variables=B2JPSIKpi_Vars, 
+                                          inputs=Jpsi_spruce, 
+                                          event_variables=evt_vars,
+                                          store_multiple_cand_info=True,
+                                          store_run_event_numbers=True)
+
+    algs = {f"JPSImumu_Tuple": [ JPSI_Tuple, line_prefilter ],}
+
+    return algs
+
+
+    
\ No newline at end of file