diff --git a/BuToD0H_D0ToKsHH_Run3/dv_BuToD0H_D0ToKsHH.py b/BuToD0H_D0ToKsHH_Run3/dv_BuToD0H_D0ToKsHH.py
new file mode 100644
index 0000000000000000000000000000000000000000..abb26aeb5a0e16266f878b66bd48d5d2f85c7055
--- /dev/null
+++ b/BuToD0H_D0ToKsHH_Run3/dv_BuToD0H_D0ToKsHH.py
@@ -0,0 +1,616 @@
+import os
+import Functors as F
+from FunTuple import FunTuple_Particles as Funtuple
+import FunTuple.functorcollections as FC
+import Functors as F
+from FunTuple import FunctorCollection
+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 (
+    HltTisTos,
+    Kinematics,
+    MCHierarchy,
+    MCKinematics,
+    EventInfo,
+    LHCInfo,
+    SelectionInfo,
+    ParticleIsolation
+)
+
+from DecayTreeFitter import DecayTreeFitter
+import Functors.math as fmath
+
+
+def alg_config_Bu2D0H_D02KsHH(options:Options):
+    Hlt1_decisions = [
+        "Hlt1TrackMVADecision", "Hlt1TwoTrackMVADecision", 
+        "Hlt1DownstreamKsToPiPiDecision", "Hlt1DownstreamPromptKsToPiPiDecision",
+        "Hlt1DownstreamD2KshhDecision", "Hlt1KsToPiPiDecision", "Hlt1KsToPiPiDoubleMuonMisIDDecision",
+        "Hlt1TwoTrackKsDecision", "Hlt1D2KshhDecision",
+        "Hlt1PassthroughDecision", "Hlt1TAEPassthroughDecision", "Hlt1GECPassthroughDecision",
+        "Hlt1GlobalDecision", "Hlt1PhysDecision"
+    ]
+    Hlt2_decisions = [
+        "Hlt2Topo2Body",
+        "Hlt2Topo3Body",
+        "Hlt2B2OC_BuToD0Pi_D0ToKsLLHH",
+        "Hlt2B2OC_BuToD0Pi_D0ToKsDDHH",
+        "Hlt2B2OC_BuToD0K_D0ToKsLLHH",
+        "Hlt2B2OC_BuToD0K_D0ToKsDDHH",
+    ]
+    user_algorithms = {}
+    for bac in ("Pi", "K"):
+        for mode in ("LL", "DD"):
+            line = f"Hlt2B2OC_BuToD0{bac}_D0ToKs{mode}HH"
+            line_data = get_particles(f"/Event/Turbo/{line}/Particles")
+            my_filter = create_lines_filter(f"Hlt2Line_Filter_{line}", lines=[f"{line}"])
+            Bac = "pi" if bac == "Pi" else "K"
+
+            all_fields = {}
+            for hp in ['pi', 'K']:
+                for hm in ['pi', 'K']:
+                    all_fields[f'Bu2D0{Bac}p_D02KS{mode}{hp}p{hm}m'] = {
+                        "Bu"    : f"B+ ->  (D0 ->  (KS0 ->  pi+  pi-)  {hp}+  {hm}-)  {Bac}+",
+                        "D0"    : f"B+ -> ^(D0 ->  (KS0 ->  pi+  pi-)  {hp}+  {hm}-)  {Bac}+",
+                        "Bac"   : f"B+ ->  (D0 ->  (KS0 ->  pi+  pi-)  {hp}+  {hm}-) ^{Bac}+",
+                        "KS"    : f"B+ ->  (D0 -> ^(KS0 ->  pi+  pi-)  {hp}+  {hm}-)  {Bac}+",
+                        "D0_hp" : f"B+ ->  (D0 ->  (KS0 ->  pi+  pi-) ^{hp}+  {hm}-)  {Bac}+",
+                        "D0_hm" : f"B+ ->  (D0 ->  (KS0 ->  pi+  pi-)  {hp}+ ^{hm}-)  {Bac}+",
+                        "KS_pip": f"B+ ->  (D0 ->  (KS0 -> ^pi+  pi-)  {hp}+  {hm}-)  {Bac}+",
+                        "KS_pim": f"B+ ->  (D0 ->  (KS0 ->  pi+ ^pi-)  {hp}+  {hm}-)  {Bac}+",
+                    }
+                    all_fields[f'Bu2D0{Bac}m_D02KS{mode}{hp}p{hm}m'] = {
+                        "Bu"    : f"B- ->  (D0 ->  (KS0 ->  pi+  pi-)  {hp}+  {hm}-)  {Bac}-",
+                        "D0"    : f"B- -> ^(D0 ->  (KS0 ->  pi+  pi-)  {hp}+  {hm}-)  {Bac}-",
+                        "Bac"   : f"B- ->  (D0 ->  (KS0 ->  pi+  pi-)  {hp}+  {hm}-) ^{Bac}-",
+                        "KS"    : f"B- ->  (D0 -> ^(KS0 ->  pi+  pi-)  {hp}+  {hm}-)  {Bac}-",
+                        "D0_hp" : f"B- ->  (D0 ->  (KS0 ->  pi+  pi-) ^{hp}+  {hm}-)  {Bac}-",
+                        "D0_hm" : f"B- ->  (D0 ->  (KS0 ->  pi+  pi-)  {hp}+ ^{hm}-)  {Bac}-",
+                        "KS_pip": f"B- ->  (D0 ->  (KS0 -> ^pi+  pi-)  {hp}+  {hm}-)  {Bac}-",
+                        "KS_pim": f"B- ->  (D0 ->  (KS0 ->  pi+ ^pi-)  {hp}+  {hm}-)  {Bac}-",
+                    }
+
+            # Creating v2 reconstructed vertices to be used in the following functor
+            v2_pvs = get_pvs()
+
+            # Mass constraints
+            DTF_MassFitConsD   = DecayTreeFitter(name=f"DTF_MassFitConsD_{line}", input_particles=line_data, mass_constraints=["D0"])
+            DTF_MassFitConsKS  = DecayTreeFitter(name=f"DTF_MassFitConsKS_{line}", input_particles=line_data, mass_constraints=["KS0"])
+            DTF_MassFitConsDKS = DecayTreeFitter(name=f"DTF_MassFitConsDKS_{line}", input_particles=line_data, mass_constraints=["D0", "KS0"])
+            # PV constraints
+            DTF_PV = DecayTreeFitter(name=f"PVFit_{line}", input_particles=line_data, input_pvs=v2_pvs)
+            # PV and mass constraints
+            DTF_MassFitConsDAndPV   = DecayTreeFitter(name=f"DTF_MassFitConsDAndPV_{line}", input_particles=line_data, mass_constraints=["D0"], input_pvs=v2_pvs)
+            DTF_MassFitConsKSAndPV  = DecayTreeFitter(name=f"DTF_MassFitConsKSAndPV_{line}", input_particles=line_data, mass_constraints=["KS0"], input_pvs=v2_pvs)
+            DTF_MassFitConsDKSAndPV = DecayTreeFitter(name=f"DTF_MassFitConsDKSAndPV_{line}", input_particles=line_data, mass_constraints=["D0", "KS0"], input_pvs=v2_pvs)
+
+            # define helper functors
+            get_child = F.CHILD(1, F.FORWARDARG0) # change here the index of the child
+            get_SV =  F.ENDVERTEX @ F.FORWARDARG0
+            get_SV_pos = F.TOLINALG @ F.POSITION @ get_SV # only if composite (i.e. has vertex)
+            get_child_endvtx_pos = F.ENDVERTEX_POS  @ get_child
+            get_fdvec_child = get_child_endvtx_pos - get_SV_pos
+
+            # define observables
+            IP_wrt_SV = F.IP.bind(get_SV_pos , get_child)
+            IPCHI2_wrt_SV = F.IPCHI2.bind(get_SV , get_child) # only if child is composite (i.e. has vertex)
+            FD_wrt_SV = F.MAGNITUDE @ get_fdvec_child
+            FDCHI2_wrt_SV = F.VTX_FDCHI2.bind(get_SV, get_child)
+
+            def get_variables(par=''):
+                if par in ['Bac', 'D0_hp', 'D0_hm', 'KS_pip', 'KS_pim']: is_basic = True
+                else: is_basic = False
+                all_vars = FunctorCollection({})
+                all_vars += FC.Kinematics()
+                if is_basic:
+                    all_vars += FC.ParticleID(extra_info=True)
+                    all_vars.update({"GHOSTPROB": F.VALUE_OR(-1) @ F.GHOSTPROB})
+                    all_vars.update({"ISMUON": F.VALUE_OR(-1) @ F.ISMUON})
+                    all_vars.update({"INMUON": F.VALUE_OR(-1) @ F.INMUON})
+                    all_vars.update({"INECAL": F.VALUE_OR(-1) @ F.INECAL})
+                    all_vars.update({"INHCAL": F.VALUE_OR(-1) @ F.INHCAL})
+                    all_vars.update({"HASBREM": F.VALUE_OR(-1) @ F.HASBREM})
+                    all_vars.update({"BREMENERGY": F.VALUE_OR(-1) @ F.BREMENERGY})
+                    all_vars.update({"BREMBENDCORR": F.VALUE_OR(-1) @ F.BREMBENDCORR})
+                    all_vars.update({"BREMPIDE": F.VALUE_OR(-1) @ F.BREMPIDE})
+                    all_vars.update({"ECALPIDE": F.VALUE_OR(-1) @ F.ECALPIDE})
+                    all_vars.update({"ECALPIDMU": F.VALUE_OR(-1) @ F.ECALPIDMU})
+                    all_vars.update({"HCALPIDE": F.VALUE_OR(-1) @ F.HCALPIDE})
+                    all_vars.update({"HCALPIDMU": F.VALUE_OR(-1) @ F.HCALPIDMU})
+                    all_vars.update({"ELECTRONSHOWEREOP": F.VALUE_OR(-1) @ F.ELECTRONSHOWEREOP})
+                    all_vars.update({"CLUSTERMATCH": F.VALUE_OR(-1) @ F.CLUSTERMATCH_CHI2})
+                    all_vars.update({"ELECTRONMATCH": F.VALUE_OR(-1) @ F.ELECTRONMATCH_CHI2})
+                    all_vars.update({"BREMHYPOMATCH": F.VALUE_OR(-1) @ F.BREMHYPOMATCH_CHI2})
+                    all_vars.update({"ELECTRONENERGY": F.VALUE_OR(-1) @ F.ELECTRONENERGY})
+                    all_vars.update({"BREMHYPOENERGY": F.VALUE_OR(-1) @ F.BREMHYPOENERGY})
+                    all_vars.update({"BREMHYPODELTAX": F.VALUE_OR(-1) @ F.BREMHYPODELTAX})
+                    all_vars.update({"ELECTRONID": F.VALUE_OR(-1) @ F.ELECTRONID})
+                    all_vars.update({"HCALEOP": F.VALUE_OR(-1) @ F.HCALEOP})
+                    all_vars.update({"TRACK_MOM_": F.TRACK_MOMVEC})
+                    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.VALUE_OR(-1) @ F.IS_NOT_H})
+                    all_vars.update({"IS_PHOTON": F.VALUE_OR(-1) @ F.IS_PHOTON})
+                    all_vars.update({"TRACKPT": F.TRACK_PT})
+                    all_vars.update({"TRACKTYPE": F.VALUE_OR(-1) @ F.TRACKTYPE @ F.TRACK})
+                    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({"PPHASRICH": F.VALUE_OR(-1) @ F.PPHASRICH @ F.PROTOPARTICLE})
+                    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({"SHOWER_SHAPE": F.VALUE_OR(-1) @ F.CALO_NEUTRAL_SHOWER_SHAPE})
+                    all_vars.update({"TX": F.TX})
+                    all_vars.update({"TY": F.TY})
+                    all_vars.update({"TRACK_VCHI2DOF": F.CHI2DOF @ F.TRACK})
+                if not is_basic:
+                    all_vars.update({"BPVDIRA": F.BPVDIRA(v2_pvs)})
+                    all_vars.update({"BPVDLS": F.BPVDLS(v2_pvs)})
+                    all_vars.update({"BPVETA": F.BPVETA(v2_pvs)})
+                    all_vars.update({"BPVFD": F.BPVFD(v2_pvs)})
+                    all_vars.update({"BPVFDCHI2": F.BPVFDCHI2(v2_pvs)})
+                    all_vars.update({"BPVFDIR": F.BPVFDIR(v2_pvs)})
+                    all_vars.update({"BPVFDVEC": F.BPVFDVEC(v2_pvs)})
+                    all_vars.update({"ALLPV_FD": F.ALLPV_FD(v2_pvs)})
+                    all_vars.update({"ALLPV_IP": F.ALLPV_IP(v2_pvs)})
+                    all_vars.update({"BPVLTIME": F.BPVLTIME(v2_pvs)})
+                    all_vars.update({"BPVVDRHO": F.BPVVDRHO(v2_pvs)})
+                    all_vars.update({"BPVVDX": F.BPVVDX(v2_pvs)})
+                    all_vars.update({"BPVVDY": F.BPVVDY(v2_pvs)})
+                    all_vars.update({"BPVVDZ": F.BPVVDZ(v2_pvs)})
+                    all_vars.update({"OWNPVDIRA": F.OWNPVDIRA})
+                    all_vars.update({"OWNPVDLS": F.OWNPVDLS})
+                    all_vars.update({"OWNPVETA": F.OWNPVETA})
+                    all_vars.update({"OWNPVFD": F.OWNPVFD})
+                    all_vars.update({"OWNPVFDCHI2": F.OWNPVFDCHI2})
+                    all_vars.update({"OWNPVFDIR": F.OWNPVFDIR})
+                    all_vars.update({"OWNPVFDVEC": F.OWNPVFDVEC})
+                    all_vars.update({"OWNPVLTIME": F.OWNPVLTIME})
+                    all_vars.update({"OWNPVVDRHO": F.OWNPVVDRHO})
+                    all_vars.update({"OWNPVVDX": F.OWNPVVDX})
+                    all_vars.update({"OWNPVVDY": F.OWNPVVDY})
+                    all_vars.update({"OWNPVVDZ": F.OWNPVVDZ})
+                    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({"END_VZ_ERR":F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.ENDVERTEX}),
+                    all_vars.update({"END_VY_ERR":F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.ENDVERTEX}),
+                    all_vars.update({"END_VX_ERR":F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.ENDVERTEX}),
+                    all_vars.update({"MAXPT": F.MAX(F.PT)})
+                    all_vars.update({"MINPT": F.MIN(F.PT)})
+                    all_vars.update({"SUMPT": F.SUM(F.PT)})
+                    all_vars.update({"MAXDOCA": F.MAXDOCA})
+                    all_vars.update({"MAXDOCACHI2": F.MAXDOCACHI2})
+                    all_vars.update({"MAXSDOCA": F.MAXSDOCA})
+                    all_vars.update({"MAXSDOCACHI2": F.MAXSDOCACHI2})
+                    all_vars.update({"END_VCHI2DOF": F.CHI2DOF @ F.ENDVERTEX})
+                if par in ['Bu', 'KS']:
+                    all_vars.update({"DOCA12": F.DOCA(1, 2)})
+                    all_vars.update({"DOCA12CHI2": F.DOCACHI2(1, 2)})
+                    all_vars.update({"SDOCA12": F.SDOCA(1, 2)})
+                    all_vars.update({"SDOCA12CHI2": F.SDOCACHI2(1, 2)})
+                elif par == 'D0':
+                    all_vars.update({"DOCA12": F.DOCA(1, 2)})
+                    all_vars.update({"DOCA13": F.DOCA(1, 3)})
+                    all_vars.update({"DOCA23": F.DOCA(2, 3)})
+                    all_vars.update({"DOCA12CHI2": F.DOCACHI2(1, 2)})
+                    all_vars.update({"DOCA13CHI2": F.DOCACHI2(1, 3)})
+                    all_vars.update({"DOCA23CHI2": F.DOCACHI2(2, 3)})
+                    all_vars.update({"SDOCA12": F.SDOCA(1, 2)})
+                    all_vars.update({"SDOCA13": F.SDOCA(1, 3)})
+                    all_vars.update({"SDOCA23": F.SDOCA(2, 3)})
+                    all_vars.update({"SDOCA12CHI2": F.SDOCACHI2(1, 2)})
+                    all_vars.update({"SDOCA13CHI2": F.SDOCACHI2(1, 3)})
+                    all_vars.update({"SDOCA23CHI2": F.SDOCACHI2(2, 3)})
+
+                all_vars.update({"BPVIP": F.BPVIP(v2_pvs)})
+                all_vars.update({"BPVIPCHI2": F.BPVIPCHI2(v2_pvs)})
+                all_vars.update({"BPVX": F.BPVX(v2_pvs)})
+                all_vars.update({"BPVY": F.BPVY(v2_pvs)})
+                all_vars.update({"BPVZ": F.BPVZ(v2_pvs)})
+                all_vars.update({"BPVZ_ERR": F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.BPV(v2_pvs)}),
+                all_vars.update({"BPVY_ERR": F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.BPV(v2_pvs)}),
+                all_vars.update({"BPVX_ERR": F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.BPV(v2_pvs)}),
+                all_vars.update({"BPVCHI2DOF": F.CHI2DOF @ F.BPV(v2_pvs)})
+                all_vars.update({"OWNPVIP": F.OWNPVIP})
+                all_vars.update({"OWNPVIPCHI2": F.OWNPVIPCHI2})
+                all_vars.update({"OWNPVX": F.OWNPVX})
+                all_vars.update({"OWNPVY": F.OWNPVY})
+                all_vars.update({"OWNPVZ": F.OWNPVZ})
+                all_vars.update({"OWNPVZ_ERR": F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.OWNPV}),
+                all_vars.update({"OWNPVY_ERR": F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.OWNPV}),
+                all_vars.update({"OWNPVX_ERR": F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.OWNPV}),
+                all_vars.update({"OWNPVCHI2DOF": F.CHI2DOF @ F.OWNPV})
+                all_vars.update({"ALLPVX": F.ALLPVX(v2_pvs)})
+                all_vars.update({"ALLPVY": F.ALLPVY(v2_pvs)})
+                all_vars.update({"ALLPVZ": F.ALLPVZ(v2_pvs)})
+                all_vars.update({"CHARGE": F.CHARGE})
+                all_vars.update({"CHI2": F.CHI2})
+                all_vars.update({"CHI2DOF": F.CHI2DOF})
+                all_vars.update({"ETA": F.ETA})
+                all_vars.update({"FOURMOMENTUM": F.FOURMOMENTUM})
+                all_vars.update({"ISBASIC": F.ISBASICPARTICLE})
+                all_vars.update({"MINIP": F.MINIP(v2_pvs)})
+                all_vars.update({"MINIPCHI2": F.MINIPCHI2(v2_pvs)})
+                all_vars.update({"OBJECT_KEY": F.OBJECT_KEY})
+                all_vars.update({"PHI": F.PHI})
+                all_vars.update({"REFERENCEPOINT_X": F.REFERENCEPOINT_X})
+                all_vars.update({"REFERENCEPOINT_Y": F.REFERENCEPOINT_Y})
+                all_vars.update({"REFERENCEPOINT_Z": F.REFERENCEPOINT_Z})
+
+                print(f"### For {par} returning variables {all_vars.functor_dict.keys()}")
+                return all_vars
+
+            def get_full_dtf_variables(par=''):
+                # full list of variables to be computed with D, KS and  PV con
+                if par in ['Bac', 'D0_hp', 'D0_hm', 'KS_pip', 'KS_pim']: is_basic = True
+                else: is_basic = False
+                basic_vars = FunctorCollection({})
+                basic_vars += FC.Kinematics()
+                if is_basic:
+                    basic_vars.update({"TX": F.TX})
+                    basic_vars.update({"TY": F.TY})
+                if not is_basic:
+                    basic_vars.update({"BPVDIRA": F.BPVDIRA(v2_pvs)})
+                    basic_vars.update({"BPVDLS": F.BPVDLS(v2_pvs)})
+                    basic_vars.update({"BPVETA": F.BPVETA(v2_pvs)})
+                    basic_vars.update({"BPVFD": F.BPVFD(v2_pvs)})
+                    basic_vars.update({"BPVFDCHI2": F.BPVFDCHI2(v2_pvs)})
+                    basic_vars.update({"BPVFDIR": F.BPVFDIR(v2_pvs)})
+                    basic_vars.update({"BPVFDVEC": F.BPVFDVEC(v2_pvs)})
+                    basic_vars.update({"BPVLTIME": F.BPVLTIME(v2_pvs)})
+                    basic_vars.update({"BPVVDRHO": F.BPVVDRHO(v2_pvs)})
+                    basic_vars.update({"BPVVDX": F.BPVVDX(v2_pvs)})
+                    basic_vars.update({"BPVVDY": F.BPVVDY(v2_pvs)})
+                    basic_vars.update({"BPVVDZ": F.BPVVDZ(v2_pvs)})
+                    basic_vars.update({"OWNPVDIRA": F.OWNPVDIRA})
+                    basic_vars.update({"OWNPVDLS": F.OWNPVDLS})
+                    basic_vars.update({"OWNPVETA": F.OWNPVETA})
+                    basic_vars.update({"OWNPVFD": F.OWNPVFD})
+                    basic_vars.update({"OWNPVFDCHI2": F.OWNPVFDCHI2})
+                    basic_vars.update({"OWNPVFDIR": F.OWNPVFDIR})
+                    basic_vars.update({"OWNPVFDVEC": F.OWNPVFDVEC})
+                    basic_vars.update({"OWNPVLTIME": F.OWNPVLTIME})
+                    basic_vars.update({"OWNPVVDRHO": F.OWNPVVDRHO})
+                    basic_vars.update({"OWNPVVDX": F.OWNPVVDX})
+                    basic_vars.update({"OWNPVVDY": F.OWNPVVDY})
+                    basic_vars.update({"OWNPVVDZ": F.OWNPVVDZ})
+                    basic_vars.update({"ALLPV_FD": F.ALLPV_FD(v2_pvs)})
+                    basic_vars.update({"ALLPV_IP": F.ALLPV_IP(v2_pvs)})
+                    basic_vars.update({"END_VRHO": F.END_VRHO})
+                    basic_vars.update({"END_VX": F.END_VX})
+                    basic_vars.update({"END_VY": F.END_VY})
+                    basic_vars.update({"END_VZ": F.END_VZ})
+                    basic_vars.update({"END_VZ_ERR":F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.ENDVERTEX}),
+                    basic_vars.update({"END_VY_ERR":F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.ENDVERTEX}),
+                    basic_vars.update({"END_VX_ERR":F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.ENDVERTEX}),
+                    basic_vars.update({"MAXPT": F.MAX(F.PT)})
+                    basic_vars.update({"MINPT": F.MIN(F.PT)})
+                    basic_vars.update({"SUMPT": F.SUM(F.PT)})
+                    basic_vars.update({"MAXDOCA": F.MAXDOCA})
+                    basic_vars.update({"MAXDOCACHI2": F.MAXDOCACHI2})
+                    basic_vars.update({"MAXSDOCA": F.MAXSDOCA})
+                    basic_vars.update({"MAXSDOCACHI2": F.MAXSDOCACHI2})
+                    basic_vars.update({"END_VCHI2DOF": F.CHI2DOF @ F.ENDVERTEX})
+                if par in ['Bu', 'KS']:
+                    basic_vars.update({"DOCA12": F.DOCA(1, 2)})
+                    basic_vars.update({"DOCA12CHI2": F.DOCACHI2(1, 2)})
+                    basic_vars.update({"SDOCA12": F.SDOCA(1, 2)})
+                    basic_vars.update({"SDOCA12CHI2": F.SDOCACHI2(1, 2)})
+                elif par == 'D0':
+                    basic_vars.update({"DOCA12": F.DOCA(1, 2)})
+                    basic_vars.update({"DOCA13": F.DOCA(1, 3)})
+                    basic_vars.update({"DOCA23": F.DOCA(2, 3)})
+                    basic_vars.update({"DOCA12CHI2": F.DOCACHI2(1, 2)})
+                    basic_vars.update({"DOCA13CHI2": F.DOCACHI2(1, 3)})
+                    basic_vars.update({"DOCA23CHI2": F.DOCACHI2(2, 3)})
+                    basic_vars.update({"SDOCA12": F.SDOCA(1, 2)})
+                    basic_vars.update({"SDOCA13": F.SDOCA(1, 3)})
+                    basic_vars.update({"SDOCA23": F.SDOCA(2, 3)})
+                    basic_vars.update({"SDOCA12CHI2": F.SDOCACHI2(1, 2)})
+                    basic_vars.update({"SDOCA13CHI2": F.SDOCACHI2(1, 3)})
+                    basic_vars.update({"SDOCA23CHI2": F.SDOCACHI2(2, 3)})
+                basic_vars.update({"BPVIP": F.BPVIP(v2_pvs)})
+                basic_vars.update({"BPVIPCHI2": F.BPVIPCHI2(v2_pvs)})
+                basic_vars.update({"BPVX": F.BPVX(v2_pvs)})
+                basic_vars.update({"BPVY": F.BPVY(v2_pvs)})
+                basic_vars.update({"BPVZ": F.BPVZ(v2_pvs)})
+                basic_vars.update({"BPVZ_ERR": F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.BPV(v2_pvs)}),
+                basic_vars.update({"BPVY_ERR": F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.BPV(v2_pvs)}),
+                basic_vars.update({"BPVX_ERR": F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.BPV(v2_pvs)}),
+                basic_vars.update({"BPVCHI2DOF": F.CHI2DOF @ F.BPV(v2_pvs)})
+                basic_vars.update({"OWNPVIP": F.OWNPVIP})
+                basic_vars.update({"OWNPVIPCHI2": F.OWNPVIPCHI2})
+                basic_vars.update({"OWNPVX": F.OWNPVX})
+                basic_vars.update({"OWNPVY": F.OWNPVY})
+                basic_vars.update({"OWNPVZ": F.OWNPVZ})
+                basic_vars.update({"OWNPVZ_ERR": F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.OWNPV}),
+                basic_vars.update({"OWNPVY_ERR": F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.OWNPV}),
+                basic_vars.update({"OWNPVX_ERR": F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.OWNPV}),
+                basic_vars.update({"OWNPVCHI2DOF": F.CHI2DOF @ F.OWNPV})
+                basic_vars.update({"CHI2": F.CHI2})
+                basic_vars.update({"CHI2DOF": F.CHI2DOF})
+                basic_vars.update({"ETA": F.ETA})
+                basic_vars.update({"FOURMOMENTUM": F.FOURMOMENTUM})
+                basic_vars.update({"MINIP": F.MINIP(v2_pvs)})
+                basic_vars.update({"MINIPCHI2": F.MINIPCHI2(v2_pvs)})
+                basic_vars.update({"PHI": F.PHI})
+
+                all_vars = FunctorCollection({})
+                if not is_basic: # add DTF quality variables
+                    all_vars.update({"DTF_CHI2_DKSAndPVcon": DTF_MassFitConsDKSAndPV.CHI2})
+                    all_vars.update({"DTF_NDOF_DKSAndPVcon": DTF_MassFitConsDKSAndPV.NDOF})
+                    all_vars.update({"DTF_CTAU_DKSAndPVcon": DTF_MassFitConsDKSAndPV.CTAU})
+                    all_vars.update({"DTF_CTAUERR_DKSAndPVcon": DTF_MassFitConsDKSAndPV.CTAUERR})
+                    all_vars.update({"DTF_MERR_DKSAndPVcon": DTF_MassFitConsDKSAndPV.MASSERR})
+                if par == "Bu":
+                    all_vars += FunctorCollection({"CHILD1_IPwrtSV": IP_wrt_SV, "CHILD1_IPCHI2wrtSV": IPCHI2_wrt_SV, "CHILD1_FDwrtSV": FD_wrt_SV, "CHILD1_FDCHI2wrtSV": FDCHI2_wrt_SV})
+
+                all_vars += FunctorCollection({f'{k}_DKSAndPVcon': DTF_MassFitConsDKSAndPV(v) for k, v in basic_vars.get_thor_functors().items()})
+
+                return all_vars
+
+            def get_part_dtf_variables(par=''):
+                # reduced list of variables to be computed with part of constraints 
+                if par in ['Bac', 'D0_hp', 'D0_hm', 'KS_pip', 'KS_pim']: is_basic = True
+                else: is_basic = False
+                basic_vars = FunctorCollection({})
+                basic_vars += FC.Kinematics()
+                if not is_basic:
+                    basic_vars.update({"OWNPVDIRA": F.OWNPVDIRA})
+                    basic_vars.update({"OWNPVDLS": F.OWNPVDLS})
+                    basic_vars.update({"OWNPVETA": F.OWNPVETA})
+                    basic_vars.update({"OWNPVFD": F.OWNPVFD})
+                    basic_vars.update({"OWNPVFDCHI2": F.OWNPVFDCHI2})
+                    basic_vars.update({"OWNPVFDIR": F.OWNPVFDIR})
+                    basic_vars.update({"OWNPVFDVEC": F.OWNPVFDVEC})
+                    basic_vars.update({"OWNPVLTIME": F.OWNPVLTIME})
+                    basic_vars.update({"OWNPVVDRHO": F.OWNPVVDRHO})
+                    basic_vars.update({"OWNPVVDX": F.OWNPVVDX})
+                    basic_vars.update({"OWNPVVDY": F.OWNPVVDY})
+                    basic_vars.update({"OWNPVVDZ": F.OWNPVVDZ})
+                    basic_vars.update({"END_VRHO": F.END_VRHO})
+                    basic_vars.update({"END_VX": F.END_VX})
+                    basic_vars.update({"END_VY": F.END_VY})
+                    basic_vars.update({"END_VZ": F.END_VZ})
+                    basic_vars.update({"END_VZ_ERR":F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.ENDVERTEX}),
+                    basic_vars.update({"END_VY_ERR":F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.ENDVERTEX}),
+                    basic_vars.update({"END_VX_ERR":F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.ENDVERTEX}),
+                    basic_vars.update({"END_VCHI2DOF": F.CHI2DOF @ F.ENDVERTEX})
+                basic_vars.update({"OWNPVIP": F.OWNPVIP})
+                basic_vars.update({"OWNPVIPCHI2": F.OWNPVIPCHI2})
+                basic_vars.update({"OWNPVX": F.OWNPVX})
+                basic_vars.update({"OWNPVY": F.OWNPVY})
+                basic_vars.update({"OWNPVZ": F.OWNPVZ})
+                basic_vars.update({"OWNPVZ_ERR": F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.OWNPV}),
+                basic_vars.update({"OWNPVY_ERR": F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.OWNPV}),
+                basic_vars.update({"OWNPVX_ERR": F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.OWNPV}),
+                basic_vars.update({"OWNPVCHI2DOF": F.CHI2DOF @ F.OWNPV})
+                basic_vars.update({"CHI2": F.CHI2})
+                basic_vars.update({"CHI2DOF": F.CHI2DOF})
+                basic_vars.update({"ETA": F.ETA})
+                basic_vars.update({"FOURMOMENTUM": F.FOURMOMENTUM})
+                basic_vars.update({"MINIP": F.MINIP(v2_pvs)})
+                basic_vars.update({"MINIPCHI2": F.MINIPCHI2(v2_pvs)})
+                basic_vars.update({"PHI": F.PHI})
+
+                all_vars = FunctorCollection({})
+                if not is_basic: # add DTF quality variables
+                    all_vars.update({"DTF_CHI2_DCon": DTF_MassFitConsD.CHI2})
+                    all_vars.update({"DTF_NDOF_DCon": DTF_MassFitConsD.NDOF})
+                    all_vars.update({"DTF_CHI2_KScon": DTF_MassFitConsKS.CHI2})
+                    all_vars.update({"DTF_NDOF_KScon": DTF_MassFitConsKS.NDOF})
+                    all_vars.update({"DTF_CHI2_DKScon": DTF_MassFitConsDKS.CHI2})
+                    all_vars.update({"DTF_NDOF_DKScon": DTF_MassFitConsDKS.NDOF})
+                    all_vars.update({"DTF_CHI2_PVFit": DTF_PV.CHI2})
+                    all_vars.update({"DTF_NDOF_PVFit": DTF_PV.NDOF})
+                    all_vars.update({"DTF_CHI2_DAndPVcon": DTF_MassFitConsDAndPV.CHI2})
+                    all_vars.update({"DTF_NDOF_DAndPVcon": DTF_MassFitConsDAndPV.NDOF})
+                    all_vars.update({"DTF_CHI2_KSAndPVcon": DTF_MassFitConsKSAndPV.CHI2})
+                    all_vars.update({"DTF_NDOF_KSAndPVcon": DTF_MassFitConsKSAndPV.NDOF})
+
+                all_vars += FunctorCollection({f'{k}_Dcon': DTF_MassFitConsD(v) for k, v in basic_vars.get_thor_functors().items()})
+                all_vars += FunctorCollection({f'{k}_KScon': DTF_MassFitConsKS(v) for k, v in basic_vars.get_thor_functors().items()})
+                all_vars += FunctorCollection({f'{k}_DKScon': DTF_MassFitConsDKS(v) for k, v in basic_vars.get_thor_functors().items()})
+                all_vars += FunctorCollection({f'{k}_PVFit': DTF_PV(v) for k, v in basic_vars.get_thor_functors().items()})
+                all_vars += FunctorCollection({f'{k}_DAndPVcon': DTF_MassFitConsDAndPV(v) for k, v in basic_vars.get_thor_functors().items()})
+                all_vars += FunctorCollection({f'{k}_KSAndPVcon': DTF_MassFitConsKSAndPV(v) for k, v in basic_vars.get_thor_functors().items()})
+
+                return all_vars
+
+            def get_trueid_bkgcat_info(data, name):
+                MC_TRUTH = MCTruthAndBkgCat(data, name=name)
+                MCMOTHER_ID = lambda n: F.VALUE_OR(0) @ MC_TRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
+                MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MC_TRUTH(F.MC_MOTHER(n, F.OBJECT_KEY))
+
+                trueid_bkgcat_info = FunctorCollection(
+                    {
+                        "TRUEID": F.VALUE_OR(0) @ MC_TRUTH(F.PARTICLE_ID),
+                        "TRUEKEY": F.VALUE_OR(-1) @ MC_TRUTH(F.OBJECT_KEY),
+                        "TRUEPT": MC_TRUTH(F.PT),
+                        "TRUEPX": MC_TRUTH(F.PX),
+                        "TRUEPY": MC_TRUTH(F.PY),
+                        "TRUEPZ": MC_TRUTH(F.PZ),
+                        "TRUEENERGY": MC_TRUTH(F.ENERGY),
+                        "TRUEP": MC_TRUTH(F.P),
+                        "TRUEM": MC_TRUTH(F.MASS),
+                        "TRUEETA": MC_TRUTH(F.ETA),
+                        "TRUEPHI": MC_TRUTH(F.PHI),
+                        "TRUEFOURMOMENTUM": MC_TRUTH(F.FOURMOMENTUM),
+                        "MC_MOTHER_ID": MCMOTHER_ID(1),
+                        "MC_MOTHER_KEY": MCMOTHER_KEY(1),
+                        "MC_GD_MOTHER_ID": MCMOTHER_ID(2),
+                        "MC_GD_MOTHER_KEY": MCMOTHER_KEY(2),
+                        "MC_GD_GD_MOTHER_ID": MCMOTHER_ID(3),
+                        "MC_GD_GD_MOTHER_KEY": MCMOTHER_KEY(3),
+                        "TRUEORIGIN_VX": MC_TRUTH(F.ORIGIN_VX),
+                        "TRUEORIGIN_VY": MC_TRUTH(F.ORIGIN_VY),
+                        "TRUEORIGIN_VZ": MC_TRUTH(F.ORIGIN_VZ),
+                        "TRUEEND_VX": MC_TRUTH(F.END_VX),
+                        "TRUEEND_VY": MC_TRUTH(F.END_VY),
+                        "TRUEEND_VZ": MC_TRUTH(F.END_VZ),
+                        "BKGCAT": MC_TRUTH.BkgCat
+                    }
+                )
+                return trueid_bkgcat_info
+
+            tistos_vars = FunctorCollection({})
+            tistos_vars += FC.HltTisTos(selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=line_data)
+            # tistos_vars += FC.HltTisTos(selection_type="Hlt2", trigger_lines=Hlt2_decisions, data=line_data)
+            print(f"### Tistos variables {tistos_vars.functor_dict.keys()}")
+
+            odin = get_odin()
+            rec_sum = get_rec_summary()
+            evt_vars = FunctorCollection({
+                "RUNNUMBER": F.RUNNUMBER(odin),
+                "EVENTNUMBER": F.EVENTNUMBER(odin),
+                "EVENTTYPE": F.EVENTTYPE(odin),
+                "PV_SIZE": F.SIZE(v2_pvs),
+                "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"),
+                "nVPClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nVPClusters"),
+                "nUTClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nUTClusters"),
+                "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(v2_pvs),
+                "ALLPVY": F.ALLPVY(v2_pvs),
+                "ALLPVZ": F.ALLPVZ(v2_pvs),
+            })
+            evt_vars += FC.EventInfo()
+            evt_vars += FC.LHCInfo(extra_info=True)
+            evt_vars += FC.SelectionInfo(selection_type="Hlt1", trigger_lines=Hlt1_decisions)
+            evt_vars += FC.SelectionInfo(selection_type="Hlt2", trigger_lines=Hlt2_decisions)
+            print(f"### Event variables {evt_vars.functor_dict.keys()}")
+
+            b_mva_vars = FunctorCollection({
+                "MVA_v0": F.MVA(
+                    MVAType="SigmaNet",
+                    Config={
+                        "File":
+                        "paramfile://data/Hlt2B2OC_B_SigmaNet_Run3.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. - F.BPVDIRA(v2_pvs)),
+                        "log_B_ENDVERTEX_CHI2": fmath.log(F.CHI2DOF),
+                        "log_B_IPCHI2_OWNPV": fmath.log(F.BPVIPCHI2(v2_pvs)),
+                        "log_B_IP_OWNPV": fmath.log(F.BPVIP(v2_pvs)),
+                    }
+                ),
+                "MVA_v1": F.MVA(
+                    MVAType="SigmaNet",
+                    Config={
+                        "File":
+                        "paramfile://data/Hlt2B2OC_B_SigmaNet_Run3-v1.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. - F.BPVDIRA(v2_pvs)),
+                        "log_B_ENDVERTEX_CHI2": fmath.log(F.CHI2DOF),
+                        "log_B_IPCHI2_OWNPV": fmath.log(F.BPVIPCHI2(v2_pvs)),
+                        "log_B_IP_OWNPV": fmath.log(F.BPVIP(v2_pvs)),
+                    }
+                ),
+                "MVA_v2": 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(v2_pvs)),
+                        "log_B_ENDVERTEX_CHI2": fmath.log(F.CHI2DOF),
+                        "log_B_IPCHI2_OWNPV": fmath.log(F.BPVIPCHI2(v2_pvs)),
+                        "log_B_IP_OWNPV": fmath.log(F.BPVIP(v2_pvs)),
+                    }
+                ),
+            })
+
+            particles = ['Bu', 'D0', 'Bac', 'KS', 'D0_hp', 'D0_hm', 'KS_pip', 'KS_pim']
+            variables = {par: get_variables(par) + get_full_dtf_variables(par) + get_part_dtf_variables(par) + tistos_vars for par in particles}
+            variables['Bu'] += b_mva_vars
+
+            if options.simulation:
+                # get configured "MCTruthAndBkgCatAlg" algorithm for HLT2 output
+                # add helper lambda that configures a functor to get truth information
+
+                trueid_bkgcat_info = get_trueid_bkgcat_info(line_data, name=f'MCTruthAndBkgCat_{line}')
+                for field in variables.keys():
+                    variables[field] += trueid_bkgcat_info
+
+            # define FunTuple instance
+            my_tuples = {}
+            for name, fields in all_fields.items():
+                my_tuples[name] = Funtuple(
+                    name=name,
+                    tuple_name="DecayTree",
+                    fields=fields,
+                    variables=variables,
+                    event_variables=evt_vars,
+                    inputs=line_data,
+                    store_multiple_cand_info=True
+                )
+            user_algorithms.update({
+                f"Alg_{name}": [my_filter, my_tuple] for name, my_tuple in my_tuples.items()
+            })
+
+    return make_config(options, user_algorithms)
\ No newline at end of file
diff --git a/BuToD0H_D0ToKsHH_Run3/info.yaml b/BuToD0H_D0ToKsHH_Run3/info.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3c2ea327be32854d7ca6942ce887ab38d9677a95
--- /dev/null
+++ b/BuToD0H_D0ToKsHH_Run3/info.yaml
@@ -0,0 +1,43 @@
+defaults:
+  application: "DaVinci/v65r1@x86_64_v2-el9-clang16-opt"
+  output: DATA.ROOT
+  inform:
+    - marcelo.bovill@cern.ch
+    - shunan.zhang@cern.ch
+  wg: B2OC
+
+{%- set datasets = [
+  ('s24c1_md_excl_ut',      0, 297124, 'Sprucing24x', '-Excl-UT', 'Down'),
+  ('s24c2_md_excl_ut', 298748, 301278, 'Sprucing24x', '-Excl-UT', 'Down'),
+  ('s24c1_mu_excl_ut', 295256, 296630, 'Sprucing24x', '-Excl-UT', 'Up'),
+  ('s24c2_mu_excl_ut', 301325, 304604, 'Sprucing24x', '-Excl-UT', 'Up'),
+  ('s24c2_mu', 301325, 304604, 'Sprucing24x', '', 'Up'),
+  ('s24c3_mu', 304648, 305739, 'Sprucing24x', '', 'Up'),
+  ('s24c4_mu', 308104, 308540, 'Sprucing24x', '', 'Up'),
+  ('s24c2_md', 297132, 301278, 'Sprucing24x', '', 'Down'),
+  ('s24c3_md', 305802, 307544, 'Sprucing24x', '', 'Down'),
+  ('s24c4_md', 307589, 308098, 'Sprucing24x', '', 'Down'),
+]%}
+{%- for name, start_run, end_run, version, condition, polarity in datasets %}
+Bu2D0H_D02KsHH_{{ name }}_{{ version }}_{{ polarity }}{{ condition }}:
+  options:
+    entrypoint: BuToD0H_D0ToKsHH_Run3.dv_BuToD0H_D0ToKsHH:alg_config_Bu2D0H_D02KsHH
+    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/trunk
+      conditions_version: master
+      input_process: "TurboSpruce" # for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "b2oc" # for streamed data
+  input:
+    bk_query: "/validation/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}{{ condition }}/Real Data/{{ version }}/94000000/B2OC.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    start_run: {{ start_run }}
+    end_run: {{ end_run }}
+    keep_running: true
+    n_test_lfns: 5 
+{%- endfor %}