From b1d808fcd5bb87d7c69bba0b2f9e02be84968a72 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <chinghua@lxplus710.cern.ch>
Date: Thu, 15 Feb 2024 13:40:12 +0100
Subject: [PATCH 01/57] Add D02KK MC production for starterkit

---
 D02HH_Practice/README.md         |  1 +
 D02HH_Practice/info.yaml         | 14 ++++++++++++
 D02HH_Practice/ntuple_options.py | 38 ++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+)
 create mode 100644 D02HH_Practice/README.md
 create mode 100644 D02HH_Practice/info.yaml
 create mode 100755 D02HH_Practice/ntuple_options.py

diff --git a/D02HH_Practice/README.md b/D02HH_Practice/README.md
new file mode 100644
index 0000000000..518eb21598
--- /dev/null
+++ b/D02HH_Practice/README.md
@@ -0,0 +1 @@
+I want weed
diff --git a/D02HH_Practice/info.yaml b/D02HH_Practice/info.yaml
new file mode 100644
index 0000000000..510dce396d
--- /dev/null
+++ b/D02HH_Practice/info.yaml
@@ -0,0 +1,14 @@
+defaults:
+    application: DaVinci/v46r10
+    wg: Charm
+    automatically_configure: yes
+    turbo: no
+    inform:
+        - chinghua@cern.ch
+    options:
+        - ntuple_options.py
+    output: D02KK.ROOT
+
+2016_MagDown_PromptMC_D02KK:
+    input:
+        bk_query: "/MC/2016/Beam6500GeV-2016-MagDown-Nu1.6-25ns-Pythia8/Sim09c/Trig0x6138160F/Reco16/Turbo03/Stripping28r1NoPrescalingFlagged/27163002/ALLSTREAMS.DST"
diff --git a/D02HH_Practice/ntuple_options.py b/D02HH_Practice/ntuple_options.py
new file mode 100755
index 0000000000..0297e5cc85
--- /dev/null
+++ b/D02HH_Practice/ntuple_options.py
@@ -0,0 +1,38 @@
+from Configurables import DecayTreeTuple
+
+## Specify the stream and stripping line
+stream = "AllStreams"
+line   = "D2hhPromptDst2D2KKLine"
+
+## We create the DecayTreeTuple object, and indicate the Input 
+## (i.e., the TES location where the desired candidates may be)
+## as well as the decay descriptor
+dtt = DecayTreeTuple("TupleDstToD0pi_D0ToKK")
+dtt.Inputs = ["/Event/{0}/Phys/{1}/Particles".format(stream, line)]
+dtt.Decay  = "[D*(2010)+ -> (D0 -> K- K+) pi+]CC"
+
+from Configurables import DaVinci
+
+DaVinci().UserAlgorithms += [dtt]
+
+# In general, thanks to using the automatically_configure setting, you don't need what's below so it can be removed
+"""
+DaVinci().InputType       = "DST"
+DaVinci().TupleFile       = "DVntuple.root"
+DaVinci().PrintFreq       = 1000
+DaVinci().DataType        = "2016"
+DaVinci().Simulation      = True
+DaVinci().Lumi            = not DaVinci().Simulation
+DaVinci().EvtMax          = -1
+DaVinci().CondDBtag       = "sim-20170721-2-vc-md100"
+DaVinci().DDDBtag         = "dddb-20170721-3"
+"""
+
+# The Analysis Productions software automatically finds a valid remote file to test on so we can drop this bit
+"""
+from GaudiConf import IOHelper
+
+IOHelper().inputFiles([
+	"./00070793_00000001_7.AllStreams.dst"
+], clear=True)
+"""
\ No newline at end of file
-- 
GitLab


From 7bfcaf775f07203a40d312225c8f26270fdbb3ef Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <chinghua@lxplus710.cern.ch>
Date: Thu, 15 Feb 2024 13:50:51 +0100
Subject: [PATCH 02/57] test

---
 D02HH_Practice/README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/D02HH_Practice/README.md b/D02HH_Practice/README.md
index 518eb21598..cc34fb0b7a 100644
--- a/D02HH_Practice/README.md
+++ b/D02HH_Practice/README.md
@@ -1 +1 @@
-I want weed
+I want weed XDDDD
-- 
GitLab


From b5cb213ea22c8fd13517218df27df0b2e65c5128 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <chinghua@lxplus710.cern.ch>
Date: Thu, 15 Feb 2024 14:10:52 +0100
Subject: [PATCH 03/57] test check

---
 D02HH_Practice/info.yaml | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/D02HH_Practice/info.yaml b/D02HH_Practice/info.yaml
index 510dce396d..dbe57daefb 100644
--- a/D02HH_Practice/info.yaml
+++ b/D02HH_Practice/info.yaml
@@ -8,7 +8,31 @@ defaults:
     options:
         - ntuple_options.py
     output: D02KK.ROOT
+checks:
+    histogram:
+        type: range
+        expression: Dst_2010_plus_M
+        limits:
+            min: 1900
+            max: 2300
+        blind_ranges:
+            min: 2000
+            max: 2020
+    histogram_fail:
+        type: range
+        expression: Dst_2010_plus_M
+        limits:
+            min: 0
+            max: 10
+    at_least_50_entries:
+        type: num_entries
+        tree_pattern: TupleDstToD0pi_D0ToKK/DecayTree
+        count: 50
 
 2016_MagDown_PromptMC_D02KK:
     input:
         bk_query: "/MC/2016/Beam6500GeV-2016-MagDown-Nu1.6-25ns-Pythia8/Sim09c/Trig0x6138160F/Reco16/Turbo03/Stripping28r1NoPrescalingFlagged/27163002/ALLSTREAMS.DST"
+    checks:
+        - histogram
+        - histogram_fail
+        - at_least_50_entries
-- 
GitLab


From 103ceab929520ca10b1667e20d0ac87626eb0503 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 11:39:24 +0200
Subject: [PATCH 04/57] Add RDstar_taue production for 2024 data checking

---
 RDstar_taue_2024data/info.yaml  |  43 +++++
 RDstar_taue_2024data/run_Dzl.py | 311 ++++++++++++++++++++++++++++++++
 2 files changed, 354 insertions(+)
 create mode 100644 RDstar_taue_2024data/info.yaml
 create mode 100644 RDstar_taue_2024data/run_Dzl.py

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
new file mode 100644
index 0000000000..2681a0a72b
--- /dev/null
+++ b/RDstar_taue_2024data/info.yaml
@@ -0,0 +1,43 @@
+checks:
+  hist_Sb_M:
+    type: range
+    expression: Sb_M
+    limits:
+      min: 2_000 
+      max: 8_000 
+    n_bins: 100 
+
+defaults:
+  application: "DaVinci/v64r4"
+  output: DATA.ROOT
+  options:
+    entrypoint: RDstar_taue_2024data.run_Dzl:main
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
+      simulation: False
+      data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "sl" # for streamed data
+      evt_max: 1000
+  inform:
+    - ching-hua.li@cern.ch
+  wg: SL
+
+{%- set datasets = [
+ ('2024Data', 'Down'),
+]%}
+{%- for evttype, polarity in datasets %}
+RDstar_taue_{{ evttype }}_{{ polarity }}:
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    keep_running: true
+    n_test_lfns: 1 
+  checks:
+   - hist_Sb_M
+{%- endfor %}
diff --git a/RDstar_taue_2024data/run_Dzl.py b/RDstar_taue_2024data/run_Dzl.py
new file mode 100644
index 0000000000..56c3ea074d
--- /dev/null
+++ b/RDstar_taue_2024data/run_Dzl.py
@@ -0,0 +1,311 @@
+import sys,os,math
+from PyConf.reading import get_pvs, get_rec_summary, get_particles
+import Functors as F
+from FunTuple import FunctorCollection
+from FunTuple import FunTuple_Particles as Funtuple
+from DaVinci.algorithms import create_lines_filter
+from DaVinci import Options,make_config
+import FunTuple.functorcollections as FC
+from DaVinciMCTools import MCTruthAndBkgCat
+from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Functors.grammar import Functor
+from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
+
+_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
+_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
+_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
+#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
+#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
+ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
+#MCNEUTRINO = F.FIND_MCDECAY("[ Lambda_b0 => Lambda_c+ mu- ^nu_mu~ ]CC")
+
+TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
+#MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(1, F.PARTICLE_ID)) == id)
+#GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(2, F.PARTICLE_ID)) == id)
+#GD_GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(3, F.PARTICLE_ID)) == id)
+
+def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
+	if do_truth_matching == True :
+		#filter B keeping only true D0 and true leptons
+		MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
+		Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
+		lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
+		Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
+		lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
+		cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
+		signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
+	else : signal_B = B
+
+	#combine to make [B*0 -> B*- pi+]cc
+	Bst_1 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_1_{lepton}',
+		DecayDescriptor='[B0 -> B- pi+]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#combine to make [B*0 -> B*- pi-]cc
+	Bst_2 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_2_{lepton}',
+		DecayDescriptor='[B0 -> B- pi-]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#merge the two Bst candidates
+	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
+	return Bst
+
+def get_functors(MCTRUTH, v2_pvs, rec_summary):
+	#define common variables for all fields (composite and basic)
+	vars_common  = FunctorCollection()
+	#all pvs: ip, ipchi2. The PV positions are stored in event variables
+	vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
+	vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
+	#best pv: x, y, z, ip, ipchi2
+	vars_common['BPV_X']          = F.BPVX(v2_pvs)
+	vars_common['BPV_Y']          = F.BPVY(v2_pvs)
+	vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
+	vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
+	vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
+	vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
+	vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
+	#particle id, key, truekey. The trueid is stored in MCHierarchy
+	vars_common['ID']            = F.PARTICLE_ID
+	vars_common['KEY']           = F.OBJECT_KEY
+	#get charge, min ip and min ipchi2
+	vars_common['CHARGE']        = F.CHARGE
+	vars_common['MINIP']         = F.MINIP(v2_pvs)
+	vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
+	#reco kinematics
+	vars_common += FC.Kinematics()
+	vars_common['ETA']           = F.ETA
+	vars_common['PHI']           = F.PHI
+	if MCTRUTH != 'None':
+		#mc vars
+		vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
+		vars_common['TRUEETA'] = MCTRUTH(F.ETA)
+		vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
+		#type of the origin vertex
+		vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
+		##mc truth hierarchy (done seperately)
+		#vars_common += FC.MCHierarchy(mctruth_alg = MCTRUTH)
+		#make some helper functions
+		MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
+		MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
+		vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
+		vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
+		vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
+		for i in range(2,14):
+		  prefix = "MC_GD_MOTHER_{}".format(i)
+		  vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
+		  vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
+
+	#variables for composite particles
+	vars_composite  = FunctorCollection()
+	#end vertex position and end vertex chi2
+	vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
+	vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
+	vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
+	#all pvs: dira, fd, fdchi2
+	vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
+	vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
+	vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
+	vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
+	vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
+	#best pv: dira, fd, fdchi2, corrm, ltime, dls
+	vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
+	vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
+	vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
+	vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
+	vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
+	vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
+	#mc composite vertex information
+
+	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
+	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
+	# only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
+	# the DOCA/DOCACHI2 see below.
+	vars_composite['MAX_DOCA'] = F.MAXDOCA
+	vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
+	vars_composite['MAX_SDOCA'] = F.MAXSDOCA
+	vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
+
+	#variables for Lb field
+	var_B  = FunctorCollection()
+	#var_B['TRUENU_PX'] = MCTRUTH(F.PX @ MCNEUTRINO)
+	#var_B['TRUENU_PY'] = MCTRUTH(F.PY @ MCNEUTRINO)
+	#var_B['TRUENU_PZ'] = MCTRUTH(F.PZ @ MCNEUTRINO)
+	#var_B['TRUENU_ENERGY'] = MCTRUTH(F.ENERGY @ MCNEUTRINO)
+	###Bkg category
+	##var_B["BKGCAT"] = MCTRUTH.BkgCat
+
+	#variables for basics
+	vars_basic  = FunctorCollection()
+	vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
+	vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
+	vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
+	vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
+	vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
+	vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
+	vars_basic['GHOSTPROB'] = F.GHOSTPROB
+	vars_basic['PIDpi'] = F.PID_PI
+	vars_basic['PIDk']  = F.PID_K
+	vars_basic['PIDp']  = F.PID_P
+	vars_basic['PIDe']  = F.PID_E
+	vars_basic['PIDmu'] = F.PID_MU
+	if MCTRUTH != 'None':
+		vars_basic['TRUEORIGINVERTEX_X'] = MCTRUTH(F.ORIGIN_VX)
+		vars_basic['TRUEORIGINVERTEX_Y'] = MCTRUTH(F.ORIGIN_VY)
+		vars_basic['TRUEORIGINVERTEX_Z'] = MCTRUTH(F.ORIGIN_VZ)
+
+	#variables for event
+	evt_vars = FunctorCollection()
+	#evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
+	#evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
+	#evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
+	#evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
+	#evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
+	evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
+	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
+	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
+
+	#return all functors
+	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars)
+	return functors
+
+def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
+	#get functors
+	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
+	vars_common = functors[0]
+	vars_composite = functors[1]
+	var_B = functors[2]
+	vars_basic = functors[3]
+	evt_vars = functors[4]
+
+	#variables for Sb field
+	vars_Bst  = FunctorCollection()
+	B_child   = F.CHILD(1, F.FORWARDARG0)
+	Epi_child = F.CHILD(2, F.FORWARDARG0)
+	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+	#diff in vtx chi2 with and without extra particle
+	vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
+	#IP and IPChi2 of extra particle wrt to Sb end vertex
+	vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	#IP and IPChi2 of extra particle wrt to Lb end vertex
+	vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+	#angle between extra particle and Lb
+	vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+	#diff in fd chi2 with and without extra particle
+	vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
+	vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+	#IP chi2 of extra particle wrt PV and SV of Sb
+	vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	#IP chi2 of extra particle wrt PV and SV of Bb
+	vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+	#DOCA and DOCACHI2 b/w Lb and extra particle
+	vars_Bst['DOCA12']       = F.DOCA(1, 2)
+	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+	#vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
+	#vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
+	#DOCACHI2 of extra particle wrt to mother i.e. Sb
+	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
+	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+
+	#define fields
+	fields = {}
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  e-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^e-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  e-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  e-) [pi+]CC]CC'
+
+	#add variables
+	variables = {}
+	variables["ALL"] = vars_common
+	variables["Sb"]  = vars_composite + vars_Bst
+	variables["Lb"]  = vars_composite + var_B
+	variables["Lc"]  = vars_composite
+	variables["Lep"] = vars_basic
+	variables["Epi"] = vars_basic
+	variables["Km"] = vars_basic
+	variables["pip"] = vars_basic
+
+	#define tuple
+	my_tuple = Funtuple(
+		name=f"Tuple_{lepton}",
+		tuple_name="DecayTree",
+		fields=fields,
+		variables=variables,
+		inputs=Bst)
+
+	return my_tuple
+
+def get_extra_pions():
+	"""
+	Note this function in DaVinci requires:
+	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
+	and it's related LHCb, DaVinci and Rec MRs
+	"""
+	long_pions = make_has_rich_long_pions()
+	up_pions = make_has_rich_up_pions()
+	down_pions = make_has_rich_down_pions()
+	return ParticleContainersMerger([long_pions, up_pions, down_pions],
+									name='Pions_combiner')
+
+#def main(options):
+def main(options: Options):
+	line_name   = ['SpruceSLB_BuToD0ENu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu']
+
+	#define filer
+	my_filter_e = create_lines_filter(name="Filter_e", lines=[line_name[0]])
+	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
+
+	#get data and extra particles
+	lb_e = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
+	extra_particles = get_extra_pions()
+
+	#get v2_pvs and rec_summary
+	v2_pvs  = get_pvs()
+	rec_summary = get_rec_summary()
+	hadron_candidate_id = 421
+	#make sb candidate
+	Bst_e = make_Bst(lb_e, extra_particles,'e',hadron_candidate_id,v2_pvs,False)
+	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
+	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+
+
+	tuple_file_e = tuple_Bst(Bst_e,'e', 'None', v2_pvs, rec_summary)
+	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
+
+	#define algorithms
+	user_algorithms = {}
+	user_algorithms['Alg_e'] = [my_filter_e, tuple_file_e]
+	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
+
+	return make_config(options, user_algorithms)
-- 
GitLab


From 282823d1b1372b4cbc352b59c5431a3eedb101ba Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 11:58:24 +0200
Subject: [PATCH 05/57] Remove D02HH_Practice

---
 D02HH_Practice/README.md         |  1 -
 D02HH_Practice/info.yaml         | 38 --------------------------------
 D02HH_Practice/ntuple_options.py | 38 --------------------------------
 3 files changed, 77 deletions(-)
 delete mode 100644 D02HH_Practice/README.md
 delete mode 100644 D02HH_Practice/info.yaml
 delete mode 100755 D02HH_Practice/ntuple_options.py

diff --git a/D02HH_Practice/README.md b/D02HH_Practice/README.md
deleted file mode 100644
index cc34fb0b7a..0000000000
--- a/D02HH_Practice/README.md
+++ /dev/null
@@ -1 +0,0 @@
-I want weed XDDDD
diff --git a/D02HH_Practice/info.yaml b/D02HH_Practice/info.yaml
deleted file mode 100644
index dbe57daefb..0000000000
--- a/D02HH_Practice/info.yaml
+++ /dev/null
@@ -1,38 +0,0 @@
-defaults:
-    application: DaVinci/v46r10
-    wg: Charm
-    automatically_configure: yes
-    turbo: no
-    inform:
-        - chinghua@cern.ch
-    options:
-        - ntuple_options.py
-    output: D02KK.ROOT
-checks:
-    histogram:
-        type: range
-        expression: Dst_2010_plus_M
-        limits:
-            min: 1900
-            max: 2300
-        blind_ranges:
-            min: 2000
-            max: 2020
-    histogram_fail:
-        type: range
-        expression: Dst_2010_plus_M
-        limits:
-            min: 0
-            max: 10
-    at_least_50_entries:
-        type: num_entries
-        tree_pattern: TupleDstToD0pi_D0ToKK/DecayTree
-        count: 50
-
-2016_MagDown_PromptMC_D02KK:
-    input:
-        bk_query: "/MC/2016/Beam6500GeV-2016-MagDown-Nu1.6-25ns-Pythia8/Sim09c/Trig0x6138160F/Reco16/Turbo03/Stripping28r1NoPrescalingFlagged/27163002/ALLSTREAMS.DST"
-    checks:
-        - histogram
-        - histogram_fail
-        - at_least_50_entries
diff --git a/D02HH_Practice/ntuple_options.py b/D02HH_Practice/ntuple_options.py
deleted file mode 100755
index 0297e5cc85..0000000000
--- a/D02HH_Practice/ntuple_options.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from Configurables import DecayTreeTuple
-
-## Specify the stream and stripping line
-stream = "AllStreams"
-line   = "D2hhPromptDst2D2KKLine"
-
-## We create the DecayTreeTuple object, and indicate the Input 
-## (i.e., the TES location where the desired candidates may be)
-## as well as the decay descriptor
-dtt = DecayTreeTuple("TupleDstToD0pi_D0ToKK")
-dtt.Inputs = ["/Event/{0}/Phys/{1}/Particles".format(stream, line)]
-dtt.Decay  = "[D*(2010)+ -> (D0 -> K- K+) pi+]CC"
-
-from Configurables import DaVinci
-
-DaVinci().UserAlgorithms += [dtt]
-
-# In general, thanks to using the automatically_configure setting, you don't need what's below so it can be removed
-"""
-DaVinci().InputType       = "DST"
-DaVinci().TupleFile       = "DVntuple.root"
-DaVinci().PrintFreq       = 1000
-DaVinci().DataType        = "2016"
-DaVinci().Simulation      = True
-DaVinci().Lumi            = not DaVinci().Simulation
-DaVinci().EvtMax          = -1
-DaVinci().CondDBtag       = "sim-20170721-2-vc-md100"
-DaVinci().DDDBtag         = "dddb-20170721-3"
-"""
-
-# The Analysis Productions software automatically finds a valid remote file to test on so we can drop this bit
-"""
-from GaudiConf import IOHelper
-
-IOHelper().inputFiles([
-	"./00070793_00000001_7.AllStreams.dst"
-], clear=True)
-"""
\ No newline at end of file
-- 
GitLab


From 50dc7fcc7789aecfd50f50a164adf4fc561a1b49 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 12:02:11 +0200
Subject: [PATCH 06/57] Fix info.yaml

---
 RDstar_taue_2024data/info.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
index 2681a0a72b..49eb72ae27 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/RDstar_taue_2024data/info.yaml
@@ -21,7 +21,7 @@ defaults:
       conditions_version: master
       input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
       input_stream: "sl" # for streamed data
-      evt_max: 1000
+      #evt_max: 1000
   inform:
     - ching-hua.li@cern.ch
   wg: SL
-- 
GitLab


From 9c1cf33fab3bcf8d5f9c85cc5ba0efcbe56fe30a Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 13:17:33 +0200
Subject: [PATCH 07/57] add Brems variables

---
 RDstar_taue_2024data/info.yaml  |  6 +++---
 RDstar_taue_2024data/run_Dzl.py | 34 ++++++++++++++++++++++++++++-----
 2 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
index 49eb72ae27..808f8ee379 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/RDstar_taue_2024data/info.yaml
@@ -1,7 +1,7 @@
 checks:
-  hist_Sb_M:
+  hist:
     type: range
-    expression: Sb_M
+    expression: Lb_M
     limits:
       min: 2_000 
       max: 8_000 
@@ -39,5 +39,5 @@ RDstar_taue_{{ evttype }}_{{ polarity }}:
     keep_running: true
     n_test_lfns: 1 
   checks:
-   - hist_Sb_M
+   - hist
 {%- endfor %}
diff --git a/RDstar_taue_2024data/run_Dzl.py b/RDstar_taue_2024data/run_Dzl.py
index 56c3ea074d..24107c0c61 100644
--- a/RDstar_taue_2024data/run_Dzl.py
+++ b/RDstar_taue_2024data/run_Dzl.py
@@ -188,8 +188,31 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
 	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
 
+	vars_brems = FunctorCollection({})
+	vars_brems.update({"HASBREM": F.HASBREM})
+	#vars_brems.update({"HASBREMADDED": F.HASBREMADDED})
+	vars_brems.update({"BREMENERGY": F.BREMENERGY})
+	vars_brems.update({"BREMBENDCORR": F.BREMBENDCORR})
+	vars_brems.update({"BREMPIDE": F.BREMPIDE})
+	vars_brems.update({"ECALPIDE": F.ECALPIDE})
+	vars_brems.update({"ECALPIDMU": F.ECALPIDMU})
+	vars_brems.update({"HCALPIDE": F.HCALPIDE})
+	vars_brems.update({"HCALPIDMU": F.HCALPIDMU})
+	vars_brems.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
+	vars_brems.update({"ELECTRONSHOWERDLL": F.ELECTRONSHOWERDLL})
+	vars_brems.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2})
+	vars_brems.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2})
+	vars_brems.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2})
+	vars_brems.update({"ELECTRONENERGY": F.ELECTRONENERGY})
+	vars_brems.update({"BREMHYPOENERGY": F.BREMHYPOENERGY})
+	vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
+	#vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
+	vars_brems.update({"INBREM": F.INBREM})
+	vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
+	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
+
 	#return all functors
-	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars)
+	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars,vars_brems)
 	return functors
 
 def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
@@ -200,6 +223,7 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	var_B = functors[2]
 	vars_basic = functors[3]
 	evt_vars = functors[4]
+	vars_brems = functors[5]
 
 	#variables for Sb field
 	vars_Bst  = FunctorCollection()
@@ -250,10 +274,10 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	variables["Sb"]  = vars_composite + vars_Bst
 	variables["Lb"]  = vars_composite + var_B
 	variables["Lc"]  = vars_composite
-	variables["Lep"] = vars_basic
-	variables["Epi"] = vars_basic
-	variables["Km"] = vars_basic
-	variables["pip"] = vars_basic
+	variables["Lep"] = vars_basic + vars_brems
+	variables["Epi"] = vars_basic + vars_brems
+	variables["Km"] = vars_basic + vars_brems
+	variables["pip"] = vars_basic + vars_brems
 
 	#define tuple
 	my_tuple = Funtuple(
-- 
GitLab


From 0d4930ad4ce95927ff52fc71698b692216e82732 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 15:54:20 +0200
Subject: [PATCH 08/57] Fix info.yaml

---
 RDstar_taue_2024data/info.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
index 808f8ee379..0651abb089 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/RDstar_taue_2024data/info.yaml
@@ -16,7 +16,7 @@ defaults:
       input_raw_format: 0.5
       input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
       simulation: False
-      data_type: "Upgrade"
+      #data_type: "Upgrade"
       geometry_version: run3/2024.Q1.2-v00.00
       conditions_version: master
       input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
-- 
GitLab


From 5664720ad90b134a2a0b8c05ca947ec25745b09e Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Thu, 9 May 2024 13:54:03 +0200
Subject: [PATCH 09/57] Add info.yaml and run_Dzl.py

---
 .../info.yaml                                 | 12 +++----
 .../run_Dzl.py                                | 31 +++++++++++--------
 2 files changed, 24 insertions(+), 19 deletions(-)
 rename {RDstar_taue_2024data => SL_mu_nu_D0toKpi_2024_data}/info.yaml (83%)
 rename {RDstar_taue_2024data => SL_mu_nu_D0toKpi_2024_data}/run_Dzl.py (91%)

diff --git a/RDstar_taue_2024data/info.yaml b/SL_mu_nu_D0toKpi_2024_data/info.yaml
similarity index 83%
rename from RDstar_taue_2024data/info.yaml
rename to SL_mu_nu_D0toKpi_2024_data/info.yaml
index 0651abb089..6192c47c82 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/SL_mu_nu_D0toKpi_2024_data/info.yaml
@@ -1,17 +1,17 @@
 checks:
   hist:
     type: range
-    expression: Lb_M
+    expression: Sb_Delta_M
     limits:
-      min: 2_000 
-      max: 8_000 
-    n_bins: 100 
+      min: 130
+      max: 200 
+    n_bins: 70 
 
 defaults:
   application: "DaVinci/v64r4"
   output: DATA.ROOT
   options:
-    entrypoint: RDstar_taue_2024data.run_Dzl:main
+    entrypoint: SL_mu_nu_D0toKpi_2024_data.run_Dzl:main
     extra_options:
       input_raw_format: 0.5
       input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
@@ -30,7 +30,7 @@ defaults:
  ('2024Data', 'Down'),
 ]%}
 {%- for evttype, polarity in datasets %}
-RDstar_taue_{{ evttype }}_{{ polarity }}:
+b0_dstp_muon_and_taumu_{{ evttype }}_{{ polarity }}:
   input:
     bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
     dq_flags:
diff --git a/RDstar_taue_2024data/run_Dzl.py b/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
similarity index 91%
rename from RDstar_taue_2024data/run_Dzl.py
rename to SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
index 24107c0c61..0f0491375b 100644
--- a/RDstar_taue_2024data/run_Dzl.py
+++ b/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
@@ -228,6 +228,7 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	#variables for Sb field
 	vars_Bst  = FunctorCollection()
 	B_child   = F.CHILD(1, F.FORWARDARG0)
+	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
 	Epi_child = F.CHILD(2, F.FORWARDARG0)
 	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
 	#diff in vtx chi2 with and without extra particle
@@ -257,16 +258,20 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	#DOCACHI2 of extra particle wrt to mother i.e. Sb
 	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
 	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+	#vars_Bst['Dstar_M'] = F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))
+	#vars_Bst['D0_M'] = F.MASS @ (F.FOURMOMENTUM @ D0_child)
+	#vars_Bst['test_id'] = F.PARTICLE_ID @ D0_child
+	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
 
 	#define fields
 	fields = {}
-	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
-	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
-	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  e-)  [pi+]CC]CC'
-	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^e-)  [pi+]CC]CC'
-	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-) ^[pi+]CC]CC'
-	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  e-) [pi+]CC]CC'
-	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  e-) [pi+]CC]CC'
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  mu-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  mu-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  mu-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^mu-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  mu-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  mu-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  mu-) [pi+]CC]CC'
 
 	#add variables
 	variables = {}
@@ -303,14 +308,14 @@ def get_extra_pions():
 
 #def main(options):
 def main(options: Options):
-	line_name   = ['SpruceSLB_BuToD0ENu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu']
+	line_name   = ['SpruceSLB_BuToD0MuNu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu']
 
 	#define filer
-	my_filter_e = create_lines_filter(name="Filter_e", lines=[line_name[0]])
+	my_filter_mu = create_lines_filter(name="Filter_mu", lines=[line_name[0]])
 	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
 
 	#get data and extra particles
-	lb_e = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_mu = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
 	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
 	extra_particles = get_extra_pions()
 
@@ -319,17 +324,17 @@ def main(options: Options):
 	rec_summary = get_rec_summary()
 	hadron_candidate_id = 421
 	#make sb candidate
-	Bst_e = make_Bst(lb_e, extra_particles,'e',hadron_candidate_id,v2_pvs,False)
+	Bst_mu = make_Bst(lb_mu, extra_particles,'mu',hadron_candidate_id,v2_pvs,False)
 	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
 	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
 
 
-	tuple_file_e = tuple_Bst(Bst_e,'e', 'None', v2_pvs, rec_summary)
+	tuple_file_mu = tuple_Bst(Bst_mu,'mu', 'None', v2_pvs, rec_summary)
 	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
 
 	#define algorithms
 	user_algorithms = {}
-	user_algorithms['Alg_e'] = [my_filter_e, tuple_file_e]
+	user_algorithms['Alg_mu'] = [my_filter_mu, tuple_file_mu]
 	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
 
 	return make_config(options, user_algorithms)
-- 
GitLab


From ea6815408de350f57d4671b4d059ab4c8219f4b9 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <chinghua@lxplus710.cern.ch>
Date: Thu, 15 Feb 2024 13:40:12 +0100
Subject: [PATCH 10/57] Add D02KK MC production for starterkit

---
 D02HH_Practice/README.md         |  1 +
 D02HH_Practice/info.yaml         | 14 ++++++++++++
 D02HH_Practice/ntuple_options.py | 38 ++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+)
 create mode 100644 D02HH_Practice/README.md
 create mode 100644 D02HH_Practice/info.yaml
 create mode 100755 D02HH_Practice/ntuple_options.py

diff --git a/D02HH_Practice/README.md b/D02HH_Practice/README.md
new file mode 100644
index 0000000000..518eb21598
--- /dev/null
+++ b/D02HH_Practice/README.md
@@ -0,0 +1 @@
+I want weed
diff --git a/D02HH_Practice/info.yaml b/D02HH_Practice/info.yaml
new file mode 100644
index 0000000000..510dce396d
--- /dev/null
+++ b/D02HH_Practice/info.yaml
@@ -0,0 +1,14 @@
+defaults:
+    application: DaVinci/v46r10
+    wg: Charm
+    automatically_configure: yes
+    turbo: no
+    inform:
+        - chinghua@cern.ch
+    options:
+        - ntuple_options.py
+    output: D02KK.ROOT
+
+2016_MagDown_PromptMC_D02KK:
+    input:
+        bk_query: "/MC/2016/Beam6500GeV-2016-MagDown-Nu1.6-25ns-Pythia8/Sim09c/Trig0x6138160F/Reco16/Turbo03/Stripping28r1NoPrescalingFlagged/27163002/ALLSTREAMS.DST"
diff --git a/D02HH_Practice/ntuple_options.py b/D02HH_Practice/ntuple_options.py
new file mode 100755
index 0000000000..0297e5cc85
--- /dev/null
+++ b/D02HH_Practice/ntuple_options.py
@@ -0,0 +1,38 @@
+from Configurables import DecayTreeTuple
+
+## Specify the stream and stripping line
+stream = "AllStreams"
+line   = "D2hhPromptDst2D2KKLine"
+
+## We create the DecayTreeTuple object, and indicate the Input 
+## (i.e., the TES location where the desired candidates may be)
+## as well as the decay descriptor
+dtt = DecayTreeTuple("TupleDstToD0pi_D0ToKK")
+dtt.Inputs = ["/Event/{0}/Phys/{1}/Particles".format(stream, line)]
+dtt.Decay  = "[D*(2010)+ -> (D0 -> K- K+) pi+]CC"
+
+from Configurables import DaVinci
+
+DaVinci().UserAlgorithms += [dtt]
+
+# In general, thanks to using the automatically_configure setting, you don't need what's below so it can be removed
+"""
+DaVinci().InputType       = "DST"
+DaVinci().TupleFile       = "DVntuple.root"
+DaVinci().PrintFreq       = 1000
+DaVinci().DataType        = "2016"
+DaVinci().Simulation      = True
+DaVinci().Lumi            = not DaVinci().Simulation
+DaVinci().EvtMax          = -1
+DaVinci().CondDBtag       = "sim-20170721-2-vc-md100"
+DaVinci().DDDBtag         = "dddb-20170721-3"
+"""
+
+# The Analysis Productions software automatically finds a valid remote file to test on so we can drop this bit
+"""
+from GaudiConf import IOHelper
+
+IOHelper().inputFiles([
+	"./00070793_00000001_7.AllStreams.dst"
+], clear=True)
+"""
\ No newline at end of file
-- 
GitLab


From a46bbf0725fb82e3f577b4133c04ebfa05ae7796 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <chinghua@lxplus710.cern.ch>
Date: Thu, 15 Feb 2024 13:50:51 +0100
Subject: [PATCH 11/57] test

---
 D02HH_Practice/README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/D02HH_Practice/README.md b/D02HH_Practice/README.md
index 518eb21598..cc34fb0b7a 100644
--- a/D02HH_Practice/README.md
+++ b/D02HH_Practice/README.md
@@ -1 +1 @@
-I want weed
+I want weed XDDDD
-- 
GitLab


From c57ccaa2a9dad21d826c635b9a69bb869a312a4c Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <chinghua@lxplus710.cern.ch>
Date: Thu, 15 Feb 2024 14:10:52 +0100
Subject: [PATCH 12/57] test check

---
 D02HH_Practice/info.yaml | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/D02HH_Practice/info.yaml b/D02HH_Practice/info.yaml
index 510dce396d..dbe57daefb 100644
--- a/D02HH_Practice/info.yaml
+++ b/D02HH_Practice/info.yaml
@@ -8,7 +8,31 @@ defaults:
     options:
         - ntuple_options.py
     output: D02KK.ROOT
+checks:
+    histogram:
+        type: range
+        expression: Dst_2010_plus_M
+        limits:
+            min: 1900
+            max: 2300
+        blind_ranges:
+            min: 2000
+            max: 2020
+    histogram_fail:
+        type: range
+        expression: Dst_2010_plus_M
+        limits:
+            min: 0
+            max: 10
+    at_least_50_entries:
+        type: num_entries
+        tree_pattern: TupleDstToD0pi_D0ToKK/DecayTree
+        count: 50
 
 2016_MagDown_PromptMC_D02KK:
     input:
         bk_query: "/MC/2016/Beam6500GeV-2016-MagDown-Nu1.6-25ns-Pythia8/Sim09c/Trig0x6138160F/Reco16/Turbo03/Stripping28r1NoPrescalingFlagged/27163002/ALLSTREAMS.DST"
+    checks:
+        - histogram
+        - histogram_fail
+        - at_least_50_entries
-- 
GitLab


From 7d1376a0107adfd9749c13f3af5880c5d9188c75 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 11:39:24 +0200
Subject: [PATCH 13/57] Add RDstar_taue production for 2024 data checking

---
 RDstar_taue_2024data/info.yaml  |  43 +++++
 RDstar_taue_2024data/run_Dzl.py | 311 ++++++++++++++++++++++++++++++++
 2 files changed, 354 insertions(+)
 create mode 100644 RDstar_taue_2024data/info.yaml
 create mode 100644 RDstar_taue_2024data/run_Dzl.py

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
new file mode 100644
index 0000000000..2681a0a72b
--- /dev/null
+++ b/RDstar_taue_2024data/info.yaml
@@ -0,0 +1,43 @@
+checks:
+  hist_Sb_M:
+    type: range
+    expression: Sb_M
+    limits:
+      min: 2_000 
+      max: 8_000 
+    n_bins: 100 
+
+defaults:
+  application: "DaVinci/v64r4"
+  output: DATA.ROOT
+  options:
+    entrypoint: RDstar_taue_2024data.run_Dzl:main
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
+      simulation: False
+      data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "sl" # for streamed data
+      evt_max: 1000
+  inform:
+    - ching-hua.li@cern.ch
+  wg: SL
+
+{%- set datasets = [
+ ('2024Data', 'Down'),
+]%}
+{%- for evttype, polarity in datasets %}
+RDstar_taue_{{ evttype }}_{{ polarity }}:
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    keep_running: true
+    n_test_lfns: 1 
+  checks:
+   - hist_Sb_M
+{%- endfor %}
diff --git a/RDstar_taue_2024data/run_Dzl.py b/RDstar_taue_2024data/run_Dzl.py
new file mode 100644
index 0000000000..56c3ea074d
--- /dev/null
+++ b/RDstar_taue_2024data/run_Dzl.py
@@ -0,0 +1,311 @@
+import sys,os,math
+from PyConf.reading import get_pvs, get_rec_summary, get_particles
+import Functors as F
+from FunTuple import FunctorCollection
+from FunTuple import FunTuple_Particles as Funtuple
+from DaVinci.algorithms import create_lines_filter
+from DaVinci import Options,make_config
+import FunTuple.functorcollections as FC
+from DaVinciMCTools import MCTruthAndBkgCat
+from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Functors.grammar import Functor
+from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
+
+_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
+_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
+_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
+#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
+#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
+ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
+#MCNEUTRINO = F.FIND_MCDECAY("[ Lambda_b0 => Lambda_c+ mu- ^nu_mu~ ]CC")
+
+TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
+#MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(1, F.PARTICLE_ID)) == id)
+#GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(2, F.PARTICLE_ID)) == id)
+#GD_GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(3, F.PARTICLE_ID)) == id)
+
+def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
+	if do_truth_matching == True :
+		#filter B keeping only true D0 and true leptons
+		MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
+		Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
+		lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
+		Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
+		lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
+		cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
+		signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
+	else : signal_B = B
+
+	#combine to make [B*0 -> B*- pi+]cc
+	Bst_1 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_1_{lepton}',
+		DecayDescriptor='[B0 -> B- pi+]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#combine to make [B*0 -> B*- pi-]cc
+	Bst_2 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_2_{lepton}',
+		DecayDescriptor='[B0 -> B- pi-]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#merge the two Bst candidates
+	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
+	return Bst
+
+def get_functors(MCTRUTH, v2_pvs, rec_summary):
+	#define common variables for all fields (composite and basic)
+	vars_common  = FunctorCollection()
+	#all pvs: ip, ipchi2. The PV positions are stored in event variables
+	vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
+	vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
+	#best pv: x, y, z, ip, ipchi2
+	vars_common['BPV_X']          = F.BPVX(v2_pvs)
+	vars_common['BPV_Y']          = F.BPVY(v2_pvs)
+	vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
+	vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
+	vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
+	vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
+	vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
+	#particle id, key, truekey. The trueid is stored in MCHierarchy
+	vars_common['ID']            = F.PARTICLE_ID
+	vars_common['KEY']           = F.OBJECT_KEY
+	#get charge, min ip and min ipchi2
+	vars_common['CHARGE']        = F.CHARGE
+	vars_common['MINIP']         = F.MINIP(v2_pvs)
+	vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
+	#reco kinematics
+	vars_common += FC.Kinematics()
+	vars_common['ETA']           = F.ETA
+	vars_common['PHI']           = F.PHI
+	if MCTRUTH != 'None':
+		#mc vars
+		vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
+		vars_common['TRUEETA'] = MCTRUTH(F.ETA)
+		vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
+		#type of the origin vertex
+		vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
+		##mc truth hierarchy (done seperately)
+		#vars_common += FC.MCHierarchy(mctruth_alg = MCTRUTH)
+		#make some helper functions
+		MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
+		MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
+		vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
+		vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
+		vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
+		for i in range(2,14):
+		  prefix = "MC_GD_MOTHER_{}".format(i)
+		  vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
+		  vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
+
+	#variables for composite particles
+	vars_composite  = FunctorCollection()
+	#end vertex position and end vertex chi2
+	vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
+	vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
+	vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
+	#all pvs: dira, fd, fdchi2
+	vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
+	vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
+	vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
+	vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
+	vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
+	#best pv: dira, fd, fdchi2, corrm, ltime, dls
+	vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
+	vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
+	vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
+	vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
+	vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
+	vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
+	#mc composite vertex information
+
+	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
+	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
+	# only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
+	# the DOCA/DOCACHI2 see below.
+	vars_composite['MAX_DOCA'] = F.MAXDOCA
+	vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
+	vars_composite['MAX_SDOCA'] = F.MAXSDOCA
+	vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
+
+	#variables for Lb field
+	var_B  = FunctorCollection()
+	#var_B['TRUENU_PX'] = MCTRUTH(F.PX @ MCNEUTRINO)
+	#var_B['TRUENU_PY'] = MCTRUTH(F.PY @ MCNEUTRINO)
+	#var_B['TRUENU_PZ'] = MCTRUTH(F.PZ @ MCNEUTRINO)
+	#var_B['TRUENU_ENERGY'] = MCTRUTH(F.ENERGY @ MCNEUTRINO)
+	###Bkg category
+	##var_B["BKGCAT"] = MCTRUTH.BkgCat
+
+	#variables for basics
+	vars_basic  = FunctorCollection()
+	vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
+	vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
+	vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
+	vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
+	vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
+	vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
+	vars_basic['GHOSTPROB'] = F.GHOSTPROB
+	vars_basic['PIDpi'] = F.PID_PI
+	vars_basic['PIDk']  = F.PID_K
+	vars_basic['PIDp']  = F.PID_P
+	vars_basic['PIDe']  = F.PID_E
+	vars_basic['PIDmu'] = F.PID_MU
+	if MCTRUTH != 'None':
+		vars_basic['TRUEORIGINVERTEX_X'] = MCTRUTH(F.ORIGIN_VX)
+		vars_basic['TRUEORIGINVERTEX_Y'] = MCTRUTH(F.ORIGIN_VY)
+		vars_basic['TRUEORIGINVERTEX_Z'] = MCTRUTH(F.ORIGIN_VZ)
+
+	#variables for event
+	evt_vars = FunctorCollection()
+	#evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
+	#evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
+	#evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
+	#evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
+	#evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
+	evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
+	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
+	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
+
+	#return all functors
+	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars)
+	return functors
+
+def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
+	#get functors
+	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
+	vars_common = functors[0]
+	vars_composite = functors[1]
+	var_B = functors[2]
+	vars_basic = functors[3]
+	evt_vars = functors[4]
+
+	#variables for Sb field
+	vars_Bst  = FunctorCollection()
+	B_child   = F.CHILD(1, F.FORWARDARG0)
+	Epi_child = F.CHILD(2, F.FORWARDARG0)
+	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+	#diff in vtx chi2 with and without extra particle
+	vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
+	#IP and IPChi2 of extra particle wrt to Sb end vertex
+	vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	#IP and IPChi2 of extra particle wrt to Lb end vertex
+	vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+	#angle between extra particle and Lb
+	vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+	#diff in fd chi2 with and without extra particle
+	vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
+	vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+	#IP chi2 of extra particle wrt PV and SV of Sb
+	vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	#IP chi2 of extra particle wrt PV and SV of Bb
+	vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+	#DOCA and DOCACHI2 b/w Lb and extra particle
+	vars_Bst['DOCA12']       = F.DOCA(1, 2)
+	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+	#vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
+	#vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
+	#DOCACHI2 of extra particle wrt to mother i.e. Sb
+	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
+	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+
+	#define fields
+	fields = {}
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  e-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^e-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  e-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  e-) [pi+]CC]CC'
+
+	#add variables
+	variables = {}
+	variables["ALL"] = vars_common
+	variables["Sb"]  = vars_composite + vars_Bst
+	variables["Lb"]  = vars_composite + var_B
+	variables["Lc"]  = vars_composite
+	variables["Lep"] = vars_basic
+	variables["Epi"] = vars_basic
+	variables["Km"] = vars_basic
+	variables["pip"] = vars_basic
+
+	#define tuple
+	my_tuple = Funtuple(
+		name=f"Tuple_{lepton}",
+		tuple_name="DecayTree",
+		fields=fields,
+		variables=variables,
+		inputs=Bst)
+
+	return my_tuple
+
+def get_extra_pions():
+	"""
+	Note this function in DaVinci requires:
+	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
+	and it's related LHCb, DaVinci and Rec MRs
+	"""
+	long_pions = make_has_rich_long_pions()
+	up_pions = make_has_rich_up_pions()
+	down_pions = make_has_rich_down_pions()
+	return ParticleContainersMerger([long_pions, up_pions, down_pions],
+									name='Pions_combiner')
+
+#def main(options):
+def main(options: Options):
+	line_name   = ['SpruceSLB_BuToD0ENu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu']
+
+	#define filer
+	my_filter_e = create_lines_filter(name="Filter_e", lines=[line_name[0]])
+	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
+
+	#get data and extra particles
+	lb_e = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
+	extra_particles = get_extra_pions()
+
+	#get v2_pvs and rec_summary
+	v2_pvs  = get_pvs()
+	rec_summary = get_rec_summary()
+	hadron_candidate_id = 421
+	#make sb candidate
+	Bst_e = make_Bst(lb_e, extra_particles,'e',hadron_candidate_id,v2_pvs,False)
+	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
+	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+
+
+	tuple_file_e = tuple_Bst(Bst_e,'e', 'None', v2_pvs, rec_summary)
+	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
+
+	#define algorithms
+	user_algorithms = {}
+	user_algorithms['Alg_e'] = [my_filter_e, tuple_file_e]
+	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
+
+	return make_config(options, user_algorithms)
-- 
GitLab


From 43973ff1ff8b60f4029d6f4fc374fbe1844d1c1f Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 11:58:24 +0200
Subject: [PATCH 14/57] Remove D02HH_Practice

---
 D02HH_Practice/README.md         |  1 -
 D02HH_Practice/info.yaml         | 38 --------------------------------
 D02HH_Practice/ntuple_options.py | 38 --------------------------------
 3 files changed, 77 deletions(-)
 delete mode 100644 D02HH_Practice/README.md
 delete mode 100644 D02HH_Practice/info.yaml
 delete mode 100755 D02HH_Practice/ntuple_options.py

diff --git a/D02HH_Practice/README.md b/D02HH_Practice/README.md
deleted file mode 100644
index cc34fb0b7a..0000000000
--- a/D02HH_Practice/README.md
+++ /dev/null
@@ -1 +0,0 @@
-I want weed XDDDD
diff --git a/D02HH_Practice/info.yaml b/D02HH_Practice/info.yaml
deleted file mode 100644
index dbe57daefb..0000000000
--- a/D02HH_Practice/info.yaml
+++ /dev/null
@@ -1,38 +0,0 @@
-defaults:
-    application: DaVinci/v46r10
-    wg: Charm
-    automatically_configure: yes
-    turbo: no
-    inform:
-        - chinghua@cern.ch
-    options:
-        - ntuple_options.py
-    output: D02KK.ROOT
-checks:
-    histogram:
-        type: range
-        expression: Dst_2010_plus_M
-        limits:
-            min: 1900
-            max: 2300
-        blind_ranges:
-            min: 2000
-            max: 2020
-    histogram_fail:
-        type: range
-        expression: Dst_2010_plus_M
-        limits:
-            min: 0
-            max: 10
-    at_least_50_entries:
-        type: num_entries
-        tree_pattern: TupleDstToD0pi_D0ToKK/DecayTree
-        count: 50
-
-2016_MagDown_PromptMC_D02KK:
-    input:
-        bk_query: "/MC/2016/Beam6500GeV-2016-MagDown-Nu1.6-25ns-Pythia8/Sim09c/Trig0x6138160F/Reco16/Turbo03/Stripping28r1NoPrescalingFlagged/27163002/ALLSTREAMS.DST"
-    checks:
-        - histogram
-        - histogram_fail
-        - at_least_50_entries
diff --git a/D02HH_Practice/ntuple_options.py b/D02HH_Practice/ntuple_options.py
deleted file mode 100755
index 0297e5cc85..0000000000
--- a/D02HH_Practice/ntuple_options.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from Configurables import DecayTreeTuple
-
-## Specify the stream and stripping line
-stream = "AllStreams"
-line   = "D2hhPromptDst2D2KKLine"
-
-## We create the DecayTreeTuple object, and indicate the Input 
-## (i.e., the TES location where the desired candidates may be)
-## as well as the decay descriptor
-dtt = DecayTreeTuple("TupleDstToD0pi_D0ToKK")
-dtt.Inputs = ["/Event/{0}/Phys/{1}/Particles".format(stream, line)]
-dtt.Decay  = "[D*(2010)+ -> (D0 -> K- K+) pi+]CC"
-
-from Configurables import DaVinci
-
-DaVinci().UserAlgorithms += [dtt]
-
-# In general, thanks to using the automatically_configure setting, you don't need what's below so it can be removed
-"""
-DaVinci().InputType       = "DST"
-DaVinci().TupleFile       = "DVntuple.root"
-DaVinci().PrintFreq       = 1000
-DaVinci().DataType        = "2016"
-DaVinci().Simulation      = True
-DaVinci().Lumi            = not DaVinci().Simulation
-DaVinci().EvtMax          = -1
-DaVinci().CondDBtag       = "sim-20170721-2-vc-md100"
-DaVinci().DDDBtag         = "dddb-20170721-3"
-"""
-
-# The Analysis Productions software automatically finds a valid remote file to test on so we can drop this bit
-"""
-from GaudiConf import IOHelper
-
-IOHelper().inputFiles([
-	"./00070793_00000001_7.AllStreams.dst"
-], clear=True)
-"""
\ No newline at end of file
-- 
GitLab


From b5d648f89203b647ecd7739970c6ecd4b03a36c8 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 12:02:11 +0200
Subject: [PATCH 15/57] Fix info.yaml

---
 RDstar_taue_2024data/info.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
index 2681a0a72b..49eb72ae27 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/RDstar_taue_2024data/info.yaml
@@ -21,7 +21,7 @@ defaults:
       conditions_version: master
       input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
       input_stream: "sl" # for streamed data
-      evt_max: 1000
+      #evt_max: 1000
   inform:
     - ching-hua.li@cern.ch
   wg: SL
-- 
GitLab


From fa3cc070535567c335b5472f104eb01695a5f3cf Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 13:17:33 +0200
Subject: [PATCH 16/57] add Brems variables

---
 RDstar_taue_2024data/info.yaml  |  6 +++---
 RDstar_taue_2024data/run_Dzl.py | 34 ++++++++++++++++++++++++++++-----
 2 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
index 49eb72ae27..808f8ee379 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/RDstar_taue_2024data/info.yaml
@@ -1,7 +1,7 @@
 checks:
-  hist_Sb_M:
+  hist:
     type: range
-    expression: Sb_M
+    expression: Lb_M
     limits:
       min: 2_000 
       max: 8_000 
@@ -39,5 +39,5 @@ RDstar_taue_{{ evttype }}_{{ polarity }}:
     keep_running: true
     n_test_lfns: 1 
   checks:
-   - hist_Sb_M
+   - hist
 {%- endfor %}
diff --git a/RDstar_taue_2024data/run_Dzl.py b/RDstar_taue_2024data/run_Dzl.py
index 56c3ea074d..24107c0c61 100644
--- a/RDstar_taue_2024data/run_Dzl.py
+++ b/RDstar_taue_2024data/run_Dzl.py
@@ -188,8 +188,31 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
 	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
 
+	vars_brems = FunctorCollection({})
+	vars_brems.update({"HASBREM": F.HASBREM})
+	#vars_brems.update({"HASBREMADDED": F.HASBREMADDED})
+	vars_brems.update({"BREMENERGY": F.BREMENERGY})
+	vars_brems.update({"BREMBENDCORR": F.BREMBENDCORR})
+	vars_brems.update({"BREMPIDE": F.BREMPIDE})
+	vars_brems.update({"ECALPIDE": F.ECALPIDE})
+	vars_brems.update({"ECALPIDMU": F.ECALPIDMU})
+	vars_brems.update({"HCALPIDE": F.HCALPIDE})
+	vars_brems.update({"HCALPIDMU": F.HCALPIDMU})
+	vars_brems.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
+	vars_brems.update({"ELECTRONSHOWERDLL": F.ELECTRONSHOWERDLL})
+	vars_brems.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2})
+	vars_brems.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2})
+	vars_brems.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2})
+	vars_brems.update({"ELECTRONENERGY": F.ELECTRONENERGY})
+	vars_brems.update({"BREMHYPOENERGY": F.BREMHYPOENERGY})
+	vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
+	#vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
+	vars_brems.update({"INBREM": F.INBREM})
+	vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
+	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
+
 	#return all functors
-	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars)
+	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars,vars_brems)
 	return functors
 
 def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
@@ -200,6 +223,7 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	var_B = functors[2]
 	vars_basic = functors[3]
 	evt_vars = functors[4]
+	vars_brems = functors[5]
 
 	#variables for Sb field
 	vars_Bst  = FunctorCollection()
@@ -250,10 +274,10 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	variables["Sb"]  = vars_composite + vars_Bst
 	variables["Lb"]  = vars_composite + var_B
 	variables["Lc"]  = vars_composite
-	variables["Lep"] = vars_basic
-	variables["Epi"] = vars_basic
-	variables["Km"] = vars_basic
-	variables["pip"] = vars_basic
+	variables["Lep"] = vars_basic + vars_brems
+	variables["Epi"] = vars_basic + vars_brems
+	variables["Km"] = vars_basic + vars_brems
+	variables["pip"] = vars_basic + vars_brems
 
 	#define tuple
 	my_tuple = Funtuple(
-- 
GitLab


From 3d45d905053f527c8b031b71de3edde87c7f2441 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 15:54:20 +0200
Subject: [PATCH 17/57] Fix info.yaml

---
 RDstar_taue_2024data/info.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
index 808f8ee379..0651abb089 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/RDstar_taue_2024data/info.yaml
@@ -16,7 +16,7 @@ defaults:
       input_raw_format: 0.5
       input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
       simulation: False
-      data_type: "Upgrade"
+      #data_type: "Upgrade"
       geometry_version: run3/2024.Q1.2-v00.00
       conditions_version: master
       input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
-- 
GitLab


From ac96cb639a83ab180964700942f55f8a1e6f761e Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Thu, 9 May 2024 13:54:03 +0200
Subject: [PATCH 18/57] Add info.yaml and run_Dzl.py

---
 .../info.yaml                                 | 12 +++----
 .../run_Dzl.py                                | 31 +++++++++++--------
 2 files changed, 24 insertions(+), 19 deletions(-)
 rename {RDstar_taue_2024data => SL_mu_nu_D0toKpi_2024_data}/info.yaml (83%)
 rename {RDstar_taue_2024data => SL_mu_nu_D0toKpi_2024_data}/run_Dzl.py (91%)

diff --git a/RDstar_taue_2024data/info.yaml b/SL_mu_nu_D0toKpi_2024_data/info.yaml
similarity index 83%
rename from RDstar_taue_2024data/info.yaml
rename to SL_mu_nu_D0toKpi_2024_data/info.yaml
index 0651abb089..6192c47c82 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/SL_mu_nu_D0toKpi_2024_data/info.yaml
@@ -1,17 +1,17 @@
 checks:
   hist:
     type: range
-    expression: Lb_M
+    expression: Sb_Delta_M
     limits:
-      min: 2_000 
-      max: 8_000 
-    n_bins: 100 
+      min: 130
+      max: 200 
+    n_bins: 70 
 
 defaults:
   application: "DaVinci/v64r4"
   output: DATA.ROOT
   options:
-    entrypoint: RDstar_taue_2024data.run_Dzl:main
+    entrypoint: SL_mu_nu_D0toKpi_2024_data.run_Dzl:main
     extra_options:
       input_raw_format: 0.5
       input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
@@ -30,7 +30,7 @@ defaults:
  ('2024Data', 'Down'),
 ]%}
 {%- for evttype, polarity in datasets %}
-RDstar_taue_{{ evttype }}_{{ polarity }}:
+b0_dstp_muon_and_taumu_{{ evttype }}_{{ polarity }}:
   input:
     bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
     dq_flags:
diff --git a/RDstar_taue_2024data/run_Dzl.py b/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
similarity index 91%
rename from RDstar_taue_2024data/run_Dzl.py
rename to SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
index 24107c0c61..0f0491375b 100644
--- a/RDstar_taue_2024data/run_Dzl.py
+++ b/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
@@ -228,6 +228,7 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	#variables for Sb field
 	vars_Bst  = FunctorCollection()
 	B_child   = F.CHILD(1, F.FORWARDARG0)
+	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
 	Epi_child = F.CHILD(2, F.FORWARDARG0)
 	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
 	#diff in vtx chi2 with and without extra particle
@@ -257,16 +258,20 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	#DOCACHI2 of extra particle wrt to mother i.e. Sb
 	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
 	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+	#vars_Bst['Dstar_M'] = F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))
+	#vars_Bst['D0_M'] = F.MASS @ (F.FOURMOMENTUM @ D0_child)
+	#vars_Bst['test_id'] = F.PARTICLE_ID @ D0_child
+	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
 
 	#define fields
 	fields = {}
-	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
-	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
-	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  e-)  [pi+]CC]CC'
-	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^e-)  [pi+]CC]CC'
-	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-) ^[pi+]CC]CC'
-	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  e-) [pi+]CC]CC'
-	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  e-) [pi+]CC]CC'
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  mu-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  mu-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  mu-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^mu-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  mu-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  mu-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  mu-) [pi+]CC]CC'
 
 	#add variables
 	variables = {}
@@ -303,14 +308,14 @@ def get_extra_pions():
 
 #def main(options):
 def main(options: Options):
-	line_name   = ['SpruceSLB_BuToD0ENu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu']
+	line_name   = ['SpruceSLB_BuToD0MuNu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu']
 
 	#define filer
-	my_filter_e = create_lines_filter(name="Filter_e", lines=[line_name[0]])
+	my_filter_mu = create_lines_filter(name="Filter_mu", lines=[line_name[0]])
 	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
 
 	#get data and extra particles
-	lb_e = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_mu = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
 	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
 	extra_particles = get_extra_pions()
 
@@ -319,17 +324,17 @@ def main(options: Options):
 	rec_summary = get_rec_summary()
 	hadron_candidate_id = 421
 	#make sb candidate
-	Bst_e = make_Bst(lb_e, extra_particles,'e',hadron_candidate_id,v2_pvs,False)
+	Bst_mu = make_Bst(lb_mu, extra_particles,'mu',hadron_candidate_id,v2_pvs,False)
 	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
 	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
 
 
-	tuple_file_e = tuple_Bst(Bst_e,'e', 'None', v2_pvs, rec_summary)
+	tuple_file_mu = tuple_Bst(Bst_mu,'mu', 'None', v2_pvs, rec_summary)
 	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
 
 	#define algorithms
 	user_algorithms = {}
-	user_algorithms['Alg_e'] = [my_filter_e, tuple_file_e]
+	user_algorithms['Alg_mu'] = [my_filter_mu, tuple_file_mu]
 	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
 
 	return make_config(options, user_algorithms)
-- 
GitLab


From d27d5fa1a9bf6e27cc018652d75e7ffa8474e9da Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Sun, 12 May 2024 11:40:41 +0200
Subject: [PATCH 19/57] Add D0toKpi l nu fakeline

---
 SL_e_nu_D0toKpi_fakeline_2024_data/info.yaml  |  43 +++
 SL_e_nu_D0toKpi_fakeline_2024_data/run_Dzl.py | 340 ++++++++++++++++++
 SL_mu_nu_D0toKpi_2024_data/run_Dzl.py         |  26 +-
 SL_mu_nu_D0toKpi_fakeline_2024_data/info.yaml |  43 +++
 .../run_Dzl.py                                | 340 ++++++++++++++++++
 5 files changed, 779 insertions(+), 13 deletions(-)
 create mode 100644 SL_e_nu_D0toKpi_fakeline_2024_data/info.yaml
 create mode 100644 SL_e_nu_D0toKpi_fakeline_2024_data/run_Dzl.py
 create mode 100644 SL_mu_nu_D0toKpi_fakeline_2024_data/info.yaml
 create mode 100644 SL_mu_nu_D0toKpi_fakeline_2024_data/run_Dzl.py

diff --git a/SL_e_nu_D0toKpi_fakeline_2024_data/info.yaml b/SL_e_nu_D0toKpi_fakeline_2024_data/info.yaml
new file mode 100644
index 0000000000..c4f455a0ee
--- /dev/null
+++ b/SL_e_nu_D0toKpi_fakeline_2024_data/info.yaml
@@ -0,0 +1,43 @@
+checks:
+  hist:
+    type: range
+    expression: Sb_Delta_M
+    limits:
+      min: 130
+      max: 200 
+    n_bins: 70 
+
+defaults:
+  application: "DaVinci/v64r4"
+  output: DATA.ROOT
+  options:
+    entrypoint: SL_e_nu_D0toKpi_fakeline_2024_data.run_Dzl:main
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
+      simulation: False
+      #data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "sl" # for streamed data
+      #evt_max: 1000
+  inform:
+    - ching-hua.li@cern.ch
+  wg: SL
+
+{%- set datasets = [
+ ('2024Data', 'Down'),
+]%}
+{%- for evttype, polarity in datasets %}
+b0_dstp_e_and_taue_fake_{{ evttype }}_{{ polarity }}:
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    keep_running: true
+    n_test_lfns: 1 
+  checks:
+   - hist
+{%- endfor %}
diff --git a/SL_e_nu_D0toKpi_fakeline_2024_data/run_Dzl.py b/SL_e_nu_D0toKpi_fakeline_2024_data/run_Dzl.py
new file mode 100644
index 0000000000..8bc45c7c87
--- /dev/null
+++ b/SL_e_nu_D0toKpi_fakeline_2024_data/run_Dzl.py
@@ -0,0 +1,340 @@
+import sys,os,math
+from PyConf.reading import get_pvs, get_rec_summary, get_particles
+import Functors as F
+from FunTuple import FunctorCollection
+from FunTuple import FunTuple_Particles as Funtuple
+from DaVinci.algorithms import create_lines_filter
+from DaVinci import Options,make_config
+import FunTuple.functorcollections as FC
+from DaVinciMCTools import MCTruthAndBkgCat
+from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Functors.grammar import Functor
+from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
+
+_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
+_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
+_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
+#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
+#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
+ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
+#MCNEUTRINO = F.FIND_MCDECAY("[ Lambda_b0 => Lambda_c+ mu- ^nu_mu~ ]CC")
+
+TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
+#MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(1, F.PARTICLE_ID)) == id)
+#GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(2, F.PARTICLE_ID)) == id)
+#GD_GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(3, F.PARTICLE_ID)) == id)
+
+def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
+	if do_truth_matching == True :
+		#filter B keeping only true D0 and true leptons
+		MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
+		Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
+		lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
+		Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
+		lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
+		cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
+		signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
+	else : signal_B = B
+
+	#combine to make [B*0 -> B*- pi+]cc
+	Bst_1 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_1_{lepton}',
+		DecayDescriptor='[B0 -> B- pi+]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#combine to make [B*0 -> B*- pi-]cc
+	Bst_2 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_2_{lepton}',
+		DecayDescriptor='[B0 -> B- pi-]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#merge the two Bst candidates
+	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
+	return Bst
+
+def get_functors(MCTRUTH, v2_pvs, rec_summary):
+	#define common variables for all fields (composite and basic)
+	vars_common  = FunctorCollection()
+	#all pvs: ip, ipchi2. The PV positions are stored in event variables
+	vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
+	vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
+	#best pv: x, y, z, ip, ipchi2
+	vars_common['BPV_X']          = F.BPVX(v2_pvs)
+	vars_common['BPV_Y']          = F.BPVY(v2_pvs)
+	vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
+	vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
+	vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
+	vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
+	vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
+	#particle id, key, truekey. The trueid is stored in MCHierarchy
+	vars_common['ID']            = F.PARTICLE_ID
+	vars_common['KEY']           = F.OBJECT_KEY
+	#get charge, min ip and min ipchi2
+	vars_common['CHARGE']        = F.CHARGE
+	vars_common['MINIP']         = F.MINIP(v2_pvs)
+	vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
+	#reco kinematics
+	vars_common += FC.Kinematics()
+	vars_common['ETA']           = F.ETA
+	vars_common['PHI']           = F.PHI
+	if MCTRUTH != 'None':
+		#mc vars
+		vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
+		vars_common['TRUEETA'] = MCTRUTH(F.ETA)
+		vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
+		#type of the origin vertex
+		vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
+		##mc truth hierarchy (done seperately)
+		#vars_common += FC.MCHierarchy(mctruth_alg = MCTRUTH)
+		#make some helper functions
+		MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
+		MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
+		vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
+		vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
+		vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
+		for i in range(2,14):
+		  prefix = "MC_GD_MOTHER_{}".format(i)
+		  vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
+		  vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
+
+	#variables for composite particles
+	vars_composite  = FunctorCollection()
+	#end vertex position and end vertex chi2
+	vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
+	vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
+	vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
+	#all pvs: dira, fd, fdchi2
+	vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
+	vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
+	vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
+	vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
+	vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
+	#best pv: dira, fd, fdchi2, corrm, ltime, dls
+	vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
+	vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
+	vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
+	vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
+	vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
+	vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
+	#mc composite vertex information
+
+	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
+	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
+	# only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
+	# the DOCA/DOCACHI2 see below.
+	vars_composite['MAX_DOCA'] = F.MAXDOCA
+	vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
+	vars_composite['MAX_SDOCA'] = F.MAXSDOCA
+	vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
+
+	#variables for Lb field
+	var_B  = FunctorCollection()
+	#var_B['TRUENU_PX'] = MCTRUTH(F.PX @ MCNEUTRINO)
+	#var_B['TRUENU_PY'] = MCTRUTH(F.PY @ MCNEUTRINO)
+	#var_B['TRUENU_PZ'] = MCTRUTH(F.PZ @ MCNEUTRINO)
+	#var_B['TRUENU_ENERGY'] = MCTRUTH(F.ENERGY @ MCNEUTRINO)
+	###Bkg category
+	##var_B["BKGCAT"] = MCTRUTH.BkgCat
+
+	#variables for basics
+	vars_basic  = FunctorCollection()
+	vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
+	vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
+	vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
+	vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
+	vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
+	vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
+	vars_basic['GHOSTPROB'] = F.GHOSTPROB
+	vars_basic['PIDpi'] = F.PID_PI
+	vars_basic['PIDk']  = F.PID_K
+	vars_basic['PIDp']  = F.PID_P
+	vars_basic['PIDe']  = F.PID_E
+	vars_basic['PIDmu'] = F.PID_MU
+	if MCTRUTH != 'None':
+		vars_basic['TRUEORIGINVERTEX_X'] = MCTRUTH(F.ORIGIN_VX)
+		vars_basic['TRUEORIGINVERTEX_Y'] = MCTRUTH(F.ORIGIN_VY)
+		vars_basic['TRUEORIGINVERTEX_Z'] = MCTRUTH(F.ORIGIN_VZ)
+
+	#variables for event
+	evt_vars = FunctorCollection()
+	#evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
+	#evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
+	#evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
+	#evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
+	#evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
+	evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
+	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
+	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
+
+	vars_brems = FunctorCollection({})
+	vars_brems.update({"HASBREM": F.HASBREM})
+	#vars_brems.update({"HASBREMADDED": F.HASBREMADDED})
+	vars_brems.update({"BREMENERGY": F.BREMENERGY})
+	vars_brems.update({"BREMBENDCORR": F.BREMBENDCORR})
+	vars_brems.update({"BREMPIDE": F.BREMPIDE})
+	vars_brems.update({"ECALPIDE": F.ECALPIDE})
+	vars_brems.update({"ECALPIDMU": F.ECALPIDMU})
+	vars_brems.update({"HCALPIDE": F.HCALPIDE})
+	vars_brems.update({"HCALPIDMU": F.HCALPIDMU})
+	vars_brems.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
+	vars_brems.update({"ELECTRONSHOWERDLL": F.ELECTRONSHOWERDLL})
+	vars_brems.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2})
+	vars_brems.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2})
+	vars_brems.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2})
+	vars_brems.update({"ELECTRONENERGY": F.ELECTRONENERGY})
+	vars_brems.update({"BREMHYPOENERGY": F.BREMHYPOENERGY})
+	vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
+	#vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
+	vars_brems.update({"INBREM": F.INBREM})
+	vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
+	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
+
+	#return all functors
+	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars,vars_brems)
+	return functors
+
+def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
+	#get functors
+	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
+	vars_common = functors[0]
+	vars_composite = functors[1]
+	var_B = functors[2]
+	vars_basic = functors[3]
+	evt_vars = functors[4]
+	vars_brems = functors[5]
+
+	#variables for Sb field
+	vars_Bst  = FunctorCollection()
+	B_child   = F.CHILD(1, F.FORWARDARG0)
+	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
+	Epi_child = F.CHILD(2, F.FORWARDARG0)
+	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+	#diff in vtx chi2 with and without extra particle
+	vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
+	#IP and IPChi2 of extra particle wrt to Sb end vertex
+	vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	#IP and IPChi2 of extra particle wrt to Lb end vertex
+	vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+	#angle between extra particle and Lb
+	vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+	#diff in fd chi2 with and without extra particle
+	vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
+	vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+	#IP chi2 of extra particle wrt PV and SV of Sb
+	vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	#IP chi2 of extra particle wrt PV and SV of Bb
+	vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+	#DOCA and DOCACHI2 b/w Lb and extra particle
+	vars_Bst['DOCA12']       = F.DOCA(1, 2)
+	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+	#vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
+	#vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
+	#DOCACHI2 of extra particle wrt to mother i.e. Sb
+	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
+	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+	#vars_Bst['Dstar_M'] = F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))
+	#vars_Bst['D0_M'] = F.MASS @ (F.FOURMOMENTUM @ D0_child)
+	#vars_Bst['test_id'] = F.PARTICLE_ID @ D0_child
+	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
+
+	#define fields
+	fields = {}
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^{lepton}-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  {lepton}-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  {lepton}-) [pi+]CC]CC'
+
+	#add variables
+	variables = {}
+	variables["ALL"] = vars_common
+	variables["Sb"]  = vars_composite + vars_Bst
+	variables["Lb"]  = vars_composite + var_B
+	variables["Lc"]  = vars_composite
+	variables["Lep"] = vars_basic + vars_brems
+	variables["Epi"] = vars_basic + vars_brems
+	variables["Km"] = vars_basic + vars_brems
+	variables["pip"] = vars_basic + vars_brems
+
+	#define tuple
+	my_tuple = Funtuple(
+		name=f"Tuple_{lepton}",
+		tuple_name="DecayTree",
+		fields=fields,
+		variables=variables,
+		inputs=Bst)
+
+	return my_tuple
+
+def get_extra_pions():
+	"""
+	Note this function in DaVinci requires:
+	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
+	and it's related LHCb, DaVinci and Rec MRs
+	"""
+	long_pions = make_has_rich_long_pions()
+	up_pions = make_has_rich_up_pions()
+	down_pions = make_has_rich_down_pions()
+	return ParticleContainersMerger([long_pions, up_pions, down_pions],
+									name='Pions_combiner')
+
+#def main(options):
+def main(options: Options):
+	line_name = ['SpruceSLB_BuToD0ENu_D0ToKPi_FakeElectron','SpruceSLB_BuToD0TauNu_D0ToKPi_FakeElectron']
+
+	#define filer
+	my_filter_l = create_lines_filter(name="Filter_l", lines=[line_name[0]])
+	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
+
+	#get data and extra particles
+	lb_l = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
+	extra_particles = get_extra_pions()
+
+	#get v2_pvs and rec_summary
+	v2_pvs  = get_pvs()
+	rec_summary = get_rec_summary()
+	hadron_candidate_id = 421
+	#make sb candidate
+	Bst_l = make_Bst(lb_l, extra_particles,'e',hadron_candidate_id,v2_pvs,False)
+	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
+	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+
+
+	tuple_file_l = tuple_Bst(Bst_l,'e', 'None', v2_pvs, rec_summary)
+	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
+
+	#define algorithms
+	user_algorithms = {}
+	user_algorithms['Alg_l'] = [my_filter_l, tuple_file_l]
+	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
+
+	return make_config(options, user_algorithms)
diff --git a/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py b/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
index 0f0491375b..0cb5e40d2a 100644
--- a/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
+++ b/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
@@ -265,13 +265,13 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 
 	#define fields
 	fields = {}
-	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  mu-)  [pi+]CC]CC'
-	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  mu-)  [pi+]CC]CC'
-	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  mu-)  [pi+]CC]CC'
-	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^mu-)  [pi+]CC]CC'
-	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  mu-) ^[pi+]CC]CC'
-	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  mu-) [pi+]CC]CC'
-	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  mu-) [pi+]CC]CC'
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^{lepton}-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  {lepton}-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  {lepton}-) [pi+]CC]CC'
 
 	#add variables
 	variables = {}
@@ -308,14 +308,14 @@ def get_extra_pions():
 
 #def main(options):
 def main(options: Options):
-	line_name   = ['SpruceSLB_BuToD0MuNu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu']
+	line_name = ['SpruceSLB_BuToD0MuNu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu']
 
 	#define filer
-	my_filter_mu = create_lines_filter(name="Filter_mu", lines=[line_name[0]])
+	my_filter_l = create_lines_filter(name="Filter_l", lines=[line_name[0]])
 	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
 
 	#get data and extra particles
-	lb_mu = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_l = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
 	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
 	extra_particles = get_extra_pions()
 
@@ -324,17 +324,17 @@ def main(options: Options):
 	rec_summary = get_rec_summary()
 	hadron_candidate_id = 421
 	#make sb candidate
-	Bst_mu = make_Bst(lb_mu, extra_particles,'mu',hadron_candidate_id,v2_pvs,False)
+	Bst_l = make_Bst(lb_l, extra_particles,'mu',hadron_candidate_id,v2_pvs,False)
 	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
 	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
 
 
-	tuple_file_mu = tuple_Bst(Bst_mu,'mu', 'None', v2_pvs, rec_summary)
+	tuple_file_l = tuple_Bst(Bst_l,'mu', 'None', v2_pvs, rec_summary)
 	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
 
 	#define algorithms
 	user_algorithms = {}
-	user_algorithms['Alg_mu'] = [my_filter_mu, tuple_file_mu]
+	user_algorithms['Alg_l'] = [my_filter_l, tuple_file_l]
 	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
 
 	return make_config(options, user_algorithms)
diff --git a/SL_mu_nu_D0toKpi_fakeline_2024_data/info.yaml b/SL_mu_nu_D0toKpi_fakeline_2024_data/info.yaml
new file mode 100644
index 0000000000..c2d8975aac
--- /dev/null
+++ b/SL_mu_nu_D0toKpi_fakeline_2024_data/info.yaml
@@ -0,0 +1,43 @@
+checks:
+  hist:
+    type: range
+    expression: Sb_Delta_M
+    limits:
+      min: 130
+      max: 200 
+    n_bins: 70 
+
+defaults:
+  application: "DaVinci/v64r4"
+  output: DATA.ROOT
+  options:
+    entrypoint: SL_mu_nu_D0toKpi_fakeline_2024_data.run_Dzl:main
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
+      simulation: False
+      #data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "sl" # for streamed data
+      #evt_max: 1000
+  inform:
+    - ching-hua.li@cern.ch
+  wg: SL
+
+{%- set datasets = [
+ ('2024Data', 'Down'),
+]%}
+{%- for evttype, polarity in datasets %}
+b0_dstp_muon_and_taumu_fake_{{ evttype }}_{{ polarity }}:
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    keep_running: true
+    n_test_lfns: 1 
+  checks:
+   - hist
+{%- endfor %}
diff --git a/SL_mu_nu_D0toKpi_fakeline_2024_data/run_Dzl.py b/SL_mu_nu_D0toKpi_fakeline_2024_data/run_Dzl.py
new file mode 100644
index 0000000000..2d3d332375
--- /dev/null
+++ b/SL_mu_nu_D0toKpi_fakeline_2024_data/run_Dzl.py
@@ -0,0 +1,340 @@
+import sys,os,math
+from PyConf.reading import get_pvs, get_rec_summary, get_particles
+import Functors as F
+from FunTuple import FunctorCollection
+from FunTuple import FunTuple_Particles as Funtuple
+from DaVinci.algorithms import create_lines_filter
+from DaVinci import Options,make_config
+import FunTuple.functorcollections as FC
+from DaVinciMCTools import MCTruthAndBkgCat
+from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Functors.grammar import Functor
+from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
+
+_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
+_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
+_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
+#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
+#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
+ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
+#MCNEUTRINO = F.FIND_MCDECAY("[ Lambda_b0 => Lambda_c+ mu- ^nu_mu~ ]CC")
+
+TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
+#MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(1, F.PARTICLE_ID)) == id)
+#GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(2, F.PARTICLE_ID)) == id)
+#GD_GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(3, F.PARTICLE_ID)) == id)
+
+def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
+	if do_truth_matching == True :
+		#filter B keeping only true D0 and true leptons
+		MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
+		Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
+		lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
+		Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
+		lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
+		cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
+		signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
+	else : signal_B = B
+
+	#combine to make [B*0 -> B*- pi+]cc
+	Bst_1 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_1_{lepton}',
+		DecayDescriptor='[B0 -> B- pi+]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#combine to make [B*0 -> B*- pi-]cc
+	Bst_2 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_2_{lepton}',
+		DecayDescriptor='[B0 -> B- pi-]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#merge the two Bst candidates
+	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
+	return Bst
+
+def get_functors(MCTRUTH, v2_pvs, rec_summary):
+	#define common variables for all fields (composite and basic)
+	vars_common  = FunctorCollection()
+	#all pvs: ip, ipchi2. The PV positions are stored in event variables
+	vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
+	vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
+	#best pv: x, y, z, ip, ipchi2
+	vars_common['BPV_X']          = F.BPVX(v2_pvs)
+	vars_common['BPV_Y']          = F.BPVY(v2_pvs)
+	vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
+	vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
+	vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
+	vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
+	vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
+	#particle id, key, truekey. The trueid is stored in MCHierarchy
+	vars_common['ID']            = F.PARTICLE_ID
+	vars_common['KEY']           = F.OBJECT_KEY
+	#get charge, min ip and min ipchi2
+	vars_common['CHARGE']        = F.CHARGE
+	vars_common['MINIP']         = F.MINIP(v2_pvs)
+	vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
+	#reco kinematics
+	vars_common += FC.Kinematics()
+	vars_common['ETA']           = F.ETA
+	vars_common['PHI']           = F.PHI
+	if MCTRUTH != 'None':
+		#mc vars
+		vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
+		vars_common['TRUEETA'] = MCTRUTH(F.ETA)
+		vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
+		#type of the origin vertex
+		vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
+		##mc truth hierarchy (done seperately)
+		#vars_common += FC.MCHierarchy(mctruth_alg = MCTRUTH)
+		#make some helper functions
+		MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
+		MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
+		vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
+		vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
+		vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
+		for i in range(2,14):
+		  prefix = "MC_GD_MOTHER_{}".format(i)
+		  vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
+		  vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
+
+	#variables for composite particles
+	vars_composite  = FunctorCollection()
+	#end vertex position and end vertex chi2
+	vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
+	vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
+	vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
+	#all pvs: dira, fd, fdchi2
+	vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
+	vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
+	vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
+	vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
+	vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
+	#best pv: dira, fd, fdchi2, corrm, ltime, dls
+	vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
+	vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
+	vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
+	vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
+	vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
+	vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
+	#mc composite vertex information
+
+	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
+	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
+	# only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
+	# the DOCA/DOCACHI2 see below.
+	vars_composite['MAX_DOCA'] = F.MAXDOCA
+	vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
+	vars_composite['MAX_SDOCA'] = F.MAXSDOCA
+	vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
+
+	#variables for Lb field
+	var_B  = FunctorCollection()
+	#var_B['TRUENU_PX'] = MCTRUTH(F.PX @ MCNEUTRINO)
+	#var_B['TRUENU_PY'] = MCTRUTH(F.PY @ MCNEUTRINO)
+	#var_B['TRUENU_PZ'] = MCTRUTH(F.PZ @ MCNEUTRINO)
+	#var_B['TRUENU_ENERGY'] = MCTRUTH(F.ENERGY @ MCNEUTRINO)
+	###Bkg category
+	##var_B["BKGCAT"] = MCTRUTH.BkgCat
+
+	#variables for basics
+	vars_basic  = FunctorCollection()
+	vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
+	vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
+	vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
+	vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
+	vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
+	vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
+	vars_basic['GHOSTPROB'] = F.GHOSTPROB
+	vars_basic['PIDpi'] = F.PID_PI
+	vars_basic['PIDk']  = F.PID_K
+	vars_basic['PIDp']  = F.PID_P
+	vars_basic['PIDe']  = F.PID_E
+	vars_basic['PIDmu'] = F.PID_MU
+	if MCTRUTH != 'None':
+		vars_basic['TRUEORIGINVERTEX_X'] = MCTRUTH(F.ORIGIN_VX)
+		vars_basic['TRUEORIGINVERTEX_Y'] = MCTRUTH(F.ORIGIN_VY)
+		vars_basic['TRUEORIGINVERTEX_Z'] = MCTRUTH(F.ORIGIN_VZ)
+
+	#variables for event
+	evt_vars = FunctorCollection()
+	#evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
+	#evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
+	#evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
+	#evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
+	#evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
+	evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
+	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
+	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
+
+	vars_brems = FunctorCollection({})
+	vars_brems.update({"HASBREM": F.HASBREM})
+	#vars_brems.update({"HASBREMADDED": F.HASBREMADDED})
+	vars_brems.update({"BREMENERGY": F.BREMENERGY})
+	vars_brems.update({"BREMBENDCORR": F.BREMBENDCORR})
+	vars_brems.update({"BREMPIDE": F.BREMPIDE})
+	vars_brems.update({"ECALPIDE": F.ECALPIDE})
+	vars_brems.update({"ECALPIDMU": F.ECALPIDMU})
+	vars_brems.update({"HCALPIDE": F.HCALPIDE})
+	vars_brems.update({"HCALPIDMU": F.HCALPIDMU})
+	vars_brems.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
+	vars_brems.update({"ELECTRONSHOWERDLL": F.ELECTRONSHOWERDLL})
+	vars_brems.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2})
+	vars_brems.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2})
+	vars_brems.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2})
+	vars_brems.update({"ELECTRONENERGY": F.ELECTRONENERGY})
+	vars_brems.update({"BREMHYPOENERGY": F.BREMHYPOENERGY})
+	vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
+	#vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
+	vars_brems.update({"INBREM": F.INBREM})
+	vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
+	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
+
+	#return all functors
+	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars,vars_brems)
+	return functors
+
+def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
+	#get functors
+	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
+	vars_common = functors[0]
+	vars_composite = functors[1]
+	var_B = functors[2]
+	vars_basic = functors[3]
+	evt_vars = functors[4]
+	vars_brems = functors[5]
+
+	#variables for Sb field
+	vars_Bst  = FunctorCollection()
+	B_child   = F.CHILD(1, F.FORWARDARG0)
+	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
+	Epi_child = F.CHILD(2, F.FORWARDARG0)
+	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+	#diff in vtx chi2 with and without extra particle
+	vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
+	#IP and IPChi2 of extra particle wrt to Sb end vertex
+	vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	#IP and IPChi2 of extra particle wrt to Lb end vertex
+	vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+	#angle between extra particle and Lb
+	vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+	#diff in fd chi2 with and without extra particle
+	vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
+	vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+	#IP chi2 of extra particle wrt PV and SV of Sb
+	vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	#IP chi2 of extra particle wrt PV and SV of Bb
+	vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+	#DOCA and DOCACHI2 b/w Lb and extra particle
+	vars_Bst['DOCA12']       = F.DOCA(1, 2)
+	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+	#vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
+	#vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
+	#DOCACHI2 of extra particle wrt to mother i.e. Sb
+	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
+	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+	#vars_Bst['Dstar_M'] = F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))
+	#vars_Bst['D0_M'] = F.MASS @ (F.FOURMOMENTUM @ D0_child)
+	#vars_Bst['test_id'] = F.PARTICLE_ID @ D0_child
+	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
+
+	#define fields
+	fields = {}
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^{lepton}-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  {lepton}-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  {lepton}-) [pi+]CC]CC'
+
+	#add variables
+	variables = {}
+	variables["ALL"] = vars_common
+	variables["Sb"]  = vars_composite + vars_Bst
+	variables["Lb"]  = vars_composite + var_B
+	variables["Lc"]  = vars_composite
+	variables["Lep"] = vars_basic + vars_brems
+	variables["Epi"] = vars_basic + vars_brems
+	variables["Km"] = vars_basic + vars_brems
+	variables["pip"] = vars_basic + vars_brems
+
+	#define tuple
+	my_tuple = Funtuple(
+		name=f"Tuple_{lepton}",
+		tuple_name="DecayTree",
+		fields=fields,
+		variables=variables,
+		inputs=Bst)
+
+	return my_tuple
+
+def get_extra_pions():
+	"""
+	Note this function in DaVinci requires:
+	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
+	and it's related LHCb, DaVinci and Rec MRs
+	"""
+	long_pions = make_has_rich_long_pions()
+	up_pions = make_has_rich_up_pions()
+	down_pions = make_has_rich_down_pions()
+	return ParticleContainersMerger([long_pions, up_pions, down_pions],
+									name='Pions_combiner')
+
+#def main(options):
+def main(options: Options):
+	line_name = ['SpruceSLB_BuToD0MuNu_D0ToKPi_FakeMuon','SpruceSLB_BuToD0TauNu_D0ToKPi_FakeMuon']
+
+	#define filer
+	my_filter_l = create_lines_filter(name="Filter_l", lines=[line_name[0]])
+	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
+
+	#get data and extra particles
+	lb_l = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
+	extra_particles = get_extra_pions()
+
+	#get v2_pvs and rec_summary
+	v2_pvs  = get_pvs()
+	rec_summary = get_rec_summary()
+	hadron_candidate_id = 421
+	#make sb candidate
+	Bst_l = make_Bst(lb_l, extra_particles,'mu',hadron_candidate_id,v2_pvs,False)
+	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
+	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+
+
+	tuple_file_l = tuple_Bst(Bst_l,'mu', 'None', v2_pvs, rec_summary)
+	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
+
+	#define algorithms
+	user_algorithms = {}
+	user_algorithms['Alg_l'] = [my_filter_l, tuple_file_l]
+	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
+
+	return make_config(options, user_algorithms)
-- 
GitLab


From 3835191813e2e80e5256655f9dfad9a5e910c03c Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <chinghua@lxplus710.cern.ch>
Date: Thu, 15 Feb 2024 13:40:12 +0100
Subject: [PATCH 20/57] Add D02KK MC production for starterkit

---
 D02HH_Practice/README.md         |  1 +
 D02HH_Practice/info.yaml         | 14 ++++++++++++
 D02HH_Practice/ntuple_options.py | 38 ++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+)
 create mode 100644 D02HH_Practice/README.md
 create mode 100644 D02HH_Practice/info.yaml
 create mode 100755 D02HH_Practice/ntuple_options.py

diff --git a/D02HH_Practice/README.md b/D02HH_Practice/README.md
new file mode 100644
index 0000000000..518eb21598
--- /dev/null
+++ b/D02HH_Practice/README.md
@@ -0,0 +1 @@
+I want weed
diff --git a/D02HH_Practice/info.yaml b/D02HH_Practice/info.yaml
new file mode 100644
index 0000000000..510dce396d
--- /dev/null
+++ b/D02HH_Practice/info.yaml
@@ -0,0 +1,14 @@
+defaults:
+    application: DaVinci/v46r10
+    wg: Charm
+    automatically_configure: yes
+    turbo: no
+    inform:
+        - chinghua@cern.ch
+    options:
+        - ntuple_options.py
+    output: D02KK.ROOT
+
+2016_MagDown_PromptMC_D02KK:
+    input:
+        bk_query: "/MC/2016/Beam6500GeV-2016-MagDown-Nu1.6-25ns-Pythia8/Sim09c/Trig0x6138160F/Reco16/Turbo03/Stripping28r1NoPrescalingFlagged/27163002/ALLSTREAMS.DST"
diff --git a/D02HH_Practice/ntuple_options.py b/D02HH_Practice/ntuple_options.py
new file mode 100755
index 0000000000..0297e5cc85
--- /dev/null
+++ b/D02HH_Practice/ntuple_options.py
@@ -0,0 +1,38 @@
+from Configurables import DecayTreeTuple
+
+## Specify the stream and stripping line
+stream = "AllStreams"
+line   = "D2hhPromptDst2D2KKLine"
+
+## We create the DecayTreeTuple object, and indicate the Input 
+## (i.e., the TES location where the desired candidates may be)
+## as well as the decay descriptor
+dtt = DecayTreeTuple("TupleDstToD0pi_D0ToKK")
+dtt.Inputs = ["/Event/{0}/Phys/{1}/Particles".format(stream, line)]
+dtt.Decay  = "[D*(2010)+ -> (D0 -> K- K+) pi+]CC"
+
+from Configurables import DaVinci
+
+DaVinci().UserAlgorithms += [dtt]
+
+# In general, thanks to using the automatically_configure setting, you don't need what's below so it can be removed
+"""
+DaVinci().InputType       = "DST"
+DaVinci().TupleFile       = "DVntuple.root"
+DaVinci().PrintFreq       = 1000
+DaVinci().DataType        = "2016"
+DaVinci().Simulation      = True
+DaVinci().Lumi            = not DaVinci().Simulation
+DaVinci().EvtMax          = -1
+DaVinci().CondDBtag       = "sim-20170721-2-vc-md100"
+DaVinci().DDDBtag         = "dddb-20170721-3"
+"""
+
+# The Analysis Productions software automatically finds a valid remote file to test on so we can drop this bit
+"""
+from GaudiConf import IOHelper
+
+IOHelper().inputFiles([
+	"./00070793_00000001_7.AllStreams.dst"
+], clear=True)
+"""
\ No newline at end of file
-- 
GitLab


From c5173fbf862e56bed184cacc1a650068278fd723 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <chinghua@lxplus710.cern.ch>
Date: Thu, 15 Feb 2024 13:50:51 +0100
Subject: [PATCH 21/57] test

---
 D02HH_Practice/README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/D02HH_Practice/README.md b/D02HH_Practice/README.md
index 518eb21598..cc34fb0b7a 100644
--- a/D02HH_Practice/README.md
+++ b/D02HH_Practice/README.md
@@ -1 +1 @@
-I want weed
+I want weed XDDDD
-- 
GitLab


From e8f70de7a412434638f4eb92f2354bce1823540c Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <chinghua@lxplus710.cern.ch>
Date: Thu, 15 Feb 2024 14:10:52 +0100
Subject: [PATCH 22/57] test check

---
 D02HH_Practice/info.yaml | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/D02HH_Practice/info.yaml b/D02HH_Practice/info.yaml
index 510dce396d..dbe57daefb 100644
--- a/D02HH_Practice/info.yaml
+++ b/D02HH_Practice/info.yaml
@@ -8,7 +8,31 @@ defaults:
     options:
         - ntuple_options.py
     output: D02KK.ROOT
+checks:
+    histogram:
+        type: range
+        expression: Dst_2010_plus_M
+        limits:
+            min: 1900
+            max: 2300
+        blind_ranges:
+            min: 2000
+            max: 2020
+    histogram_fail:
+        type: range
+        expression: Dst_2010_plus_M
+        limits:
+            min: 0
+            max: 10
+    at_least_50_entries:
+        type: num_entries
+        tree_pattern: TupleDstToD0pi_D0ToKK/DecayTree
+        count: 50
 
 2016_MagDown_PromptMC_D02KK:
     input:
         bk_query: "/MC/2016/Beam6500GeV-2016-MagDown-Nu1.6-25ns-Pythia8/Sim09c/Trig0x6138160F/Reco16/Turbo03/Stripping28r1NoPrescalingFlagged/27163002/ALLSTREAMS.DST"
+    checks:
+        - histogram
+        - histogram_fail
+        - at_least_50_entries
-- 
GitLab


From 855404aa5d399fcb6c5527b96a32c2dc8e6e1419 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 11:39:24 +0200
Subject: [PATCH 23/57] Add RDstar_taue production for 2024 data checking

---
 RDstar_taue_2024data/info.yaml  |  43 +++++
 RDstar_taue_2024data/run_Dzl.py | 311 ++++++++++++++++++++++++++++++++
 2 files changed, 354 insertions(+)
 create mode 100644 RDstar_taue_2024data/info.yaml
 create mode 100644 RDstar_taue_2024data/run_Dzl.py

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
new file mode 100644
index 0000000000..2681a0a72b
--- /dev/null
+++ b/RDstar_taue_2024data/info.yaml
@@ -0,0 +1,43 @@
+checks:
+  hist_Sb_M:
+    type: range
+    expression: Sb_M
+    limits:
+      min: 2_000 
+      max: 8_000 
+    n_bins: 100 
+
+defaults:
+  application: "DaVinci/v64r4"
+  output: DATA.ROOT
+  options:
+    entrypoint: RDstar_taue_2024data.run_Dzl:main
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
+      simulation: False
+      data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "sl" # for streamed data
+      evt_max: 1000
+  inform:
+    - ching-hua.li@cern.ch
+  wg: SL
+
+{%- set datasets = [
+ ('2024Data', 'Down'),
+]%}
+{%- for evttype, polarity in datasets %}
+RDstar_taue_{{ evttype }}_{{ polarity }}:
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    keep_running: true
+    n_test_lfns: 1 
+  checks:
+   - hist_Sb_M
+{%- endfor %}
diff --git a/RDstar_taue_2024data/run_Dzl.py b/RDstar_taue_2024data/run_Dzl.py
new file mode 100644
index 0000000000..56c3ea074d
--- /dev/null
+++ b/RDstar_taue_2024data/run_Dzl.py
@@ -0,0 +1,311 @@
+import sys,os,math
+from PyConf.reading import get_pvs, get_rec_summary, get_particles
+import Functors as F
+from FunTuple import FunctorCollection
+from FunTuple import FunTuple_Particles as Funtuple
+from DaVinci.algorithms import create_lines_filter
+from DaVinci import Options,make_config
+import FunTuple.functorcollections as FC
+from DaVinciMCTools import MCTruthAndBkgCat
+from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Functors.grammar import Functor
+from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
+
+_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
+_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
+_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
+#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
+#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
+ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
+#MCNEUTRINO = F.FIND_MCDECAY("[ Lambda_b0 => Lambda_c+ mu- ^nu_mu~ ]CC")
+
+TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
+#MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(1, F.PARTICLE_ID)) == id)
+#GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(2, F.PARTICLE_ID)) == id)
+#GD_GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(3, F.PARTICLE_ID)) == id)
+
+def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
+	if do_truth_matching == True :
+		#filter B keeping only true D0 and true leptons
+		MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
+		Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
+		lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
+		Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
+		lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
+		cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
+		signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
+	else : signal_B = B
+
+	#combine to make [B*0 -> B*- pi+]cc
+	Bst_1 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_1_{lepton}',
+		DecayDescriptor='[B0 -> B- pi+]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#combine to make [B*0 -> B*- pi-]cc
+	Bst_2 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_2_{lepton}',
+		DecayDescriptor='[B0 -> B- pi-]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#merge the two Bst candidates
+	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
+	return Bst
+
+def get_functors(MCTRUTH, v2_pvs, rec_summary):
+	#define common variables for all fields (composite and basic)
+	vars_common  = FunctorCollection()
+	#all pvs: ip, ipchi2. The PV positions are stored in event variables
+	vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
+	vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
+	#best pv: x, y, z, ip, ipchi2
+	vars_common['BPV_X']          = F.BPVX(v2_pvs)
+	vars_common['BPV_Y']          = F.BPVY(v2_pvs)
+	vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
+	vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
+	vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
+	vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
+	vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
+	#particle id, key, truekey. The trueid is stored in MCHierarchy
+	vars_common['ID']            = F.PARTICLE_ID
+	vars_common['KEY']           = F.OBJECT_KEY
+	#get charge, min ip and min ipchi2
+	vars_common['CHARGE']        = F.CHARGE
+	vars_common['MINIP']         = F.MINIP(v2_pvs)
+	vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
+	#reco kinematics
+	vars_common += FC.Kinematics()
+	vars_common['ETA']           = F.ETA
+	vars_common['PHI']           = F.PHI
+	if MCTRUTH != 'None':
+		#mc vars
+		vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
+		vars_common['TRUEETA'] = MCTRUTH(F.ETA)
+		vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
+		#type of the origin vertex
+		vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
+		##mc truth hierarchy (done seperately)
+		#vars_common += FC.MCHierarchy(mctruth_alg = MCTRUTH)
+		#make some helper functions
+		MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
+		MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
+		vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
+		vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
+		vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
+		for i in range(2,14):
+		  prefix = "MC_GD_MOTHER_{}".format(i)
+		  vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
+		  vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
+
+	#variables for composite particles
+	vars_composite  = FunctorCollection()
+	#end vertex position and end vertex chi2
+	vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
+	vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
+	vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
+	#all pvs: dira, fd, fdchi2
+	vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
+	vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
+	vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
+	vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
+	vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
+	#best pv: dira, fd, fdchi2, corrm, ltime, dls
+	vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
+	vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
+	vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
+	vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
+	vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
+	vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
+	#mc composite vertex information
+
+	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
+	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
+	# only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
+	# the DOCA/DOCACHI2 see below.
+	vars_composite['MAX_DOCA'] = F.MAXDOCA
+	vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
+	vars_composite['MAX_SDOCA'] = F.MAXSDOCA
+	vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
+
+	#variables for Lb field
+	var_B  = FunctorCollection()
+	#var_B['TRUENU_PX'] = MCTRUTH(F.PX @ MCNEUTRINO)
+	#var_B['TRUENU_PY'] = MCTRUTH(F.PY @ MCNEUTRINO)
+	#var_B['TRUENU_PZ'] = MCTRUTH(F.PZ @ MCNEUTRINO)
+	#var_B['TRUENU_ENERGY'] = MCTRUTH(F.ENERGY @ MCNEUTRINO)
+	###Bkg category
+	##var_B["BKGCAT"] = MCTRUTH.BkgCat
+
+	#variables for basics
+	vars_basic  = FunctorCollection()
+	vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
+	vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
+	vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
+	vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
+	vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
+	vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
+	vars_basic['GHOSTPROB'] = F.GHOSTPROB
+	vars_basic['PIDpi'] = F.PID_PI
+	vars_basic['PIDk']  = F.PID_K
+	vars_basic['PIDp']  = F.PID_P
+	vars_basic['PIDe']  = F.PID_E
+	vars_basic['PIDmu'] = F.PID_MU
+	if MCTRUTH != 'None':
+		vars_basic['TRUEORIGINVERTEX_X'] = MCTRUTH(F.ORIGIN_VX)
+		vars_basic['TRUEORIGINVERTEX_Y'] = MCTRUTH(F.ORIGIN_VY)
+		vars_basic['TRUEORIGINVERTEX_Z'] = MCTRUTH(F.ORIGIN_VZ)
+
+	#variables for event
+	evt_vars = FunctorCollection()
+	#evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
+	#evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
+	#evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
+	#evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
+	#evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
+	evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
+	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
+	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
+
+	#return all functors
+	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars)
+	return functors
+
+def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
+	#get functors
+	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
+	vars_common = functors[0]
+	vars_composite = functors[1]
+	var_B = functors[2]
+	vars_basic = functors[3]
+	evt_vars = functors[4]
+
+	#variables for Sb field
+	vars_Bst  = FunctorCollection()
+	B_child   = F.CHILD(1, F.FORWARDARG0)
+	Epi_child = F.CHILD(2, F.FORWARDARG0)
+	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+	#diff in vtx chi2 with and without extra particle
+	vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
+	#IP and IPChi2 of extra particle wrt to Sb end vertex
+	vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	#IP and IPChi2 of extra particle wrt to Lb end vertex
+	vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+	#angle between extra particle and Lb
+	vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+	#diff in fd chi2 with and without extra particle
+	vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
+	vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+	#IP chi2 of extra particle wrt PV and SV of Sb
+	vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	#IP chi2 of extra particle wrt PV and SV of Bb
+	vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+	#DOCA and DOCACHI2 b/w Lb and extra particle
+	vars_Bst['DOCA12']       = F.DOCA(1, 2)
+	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+	#vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
+	#vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
+	#DOCACHI2 of extra particle wrt to mother i.e. Sb
+	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
+	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+
+	#define fields
+	fields = {}
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  e-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^e-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  e-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  e-) [pi+]CC]CC'
+
+	#add variables
+	variables = {}
+	variables["ALL"] = vars_common
+	variables["Sb"]  = vars_composite + vars_Bst
+	variables["Lb"]  = vars_composite + var_B
+	variables["Lc"]  = vars_composite
+	variables["Lep"] = vars_basic
+	variables["Epi"] = vars_basic
+	variables["Km"] = vars_basic
+	variables["pip"] = vars_basic
+
+	#define tuple
+	my_tuple = Funtuple(
+		name=f"Tuple_{lepton}",
+		tuple_name="DecayTree",
+		fields=fields,
+		variables=variables,
+		inputs=Bst)
+
+	return my_tuple
+
+def get_extra_pions():
+	"""
+	Note this function in DaVinci requires:
+	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
+	and it's related LHCb, DaVinci and Rec MRs
+	"""
+	long_pions = make_has_rich_long_pions()
+	up_pions = make_has_rich_up_pions()
+	down_pions = make_has_rich_down_pions()
+	return ParticleContainersMerger([long_pions, up_pions, down_pions],
+									name='Pions_combiner')
+
+#def main(options):
+def main(options: Options):
+	line_name   = ['SpruceSLB_BuToD0ENu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu']
+
+	#define filer
+	my_filter_e = create_lines_filter(name="Filter_e", lines=[line_name[0]])
+	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
+
+	#get data and extra particles
+	lb_e = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
+	extra_particles = get_extra_pions()
+
+	#get v2_pvs and rec_summary
+	v2_pvs  = get_pvs()
+	rec_summary = get_rec_summary()
+	hadron_candidate_id = 421
+	#make sb candidate
+	Bst_e = make_Bst(lb_e, extra_particles,'e',hadron_candidate_id,v2_pvs,False)
+	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
+	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+
+
+	tuple_file_e = tuple_Bst(Bst_e,'e', 'None', v2_pvs, rec_summary)
+	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
+
+	#define algorithms
+	user_algorithms = {}
+	user_algorithms['Alg_e'] = [my_filter_e, tuple_file_e]
+	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
+
+	return make_config(options, user_algorithms)
-- 
GitLab


From 4d9d79b57c07279c9559d9f36408f36570bdd63a Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 11:58:24 +0200
Subject: [PATCH 24/57] Remove D02HH_Practice

---
 D02HH_Practice/README.md         |  1 -
 D02HH_Practice/info.yaml         | 38 --------------------------------
 D02HH_Practice/ntuple_options.py | 38 --------------------------------
 3 files changed, 77 deletions(-)
 delete mode 100644 D02HH_Practice/README.md
 delete mode 100644 D02HH_Practice/info.yaml
 delete mode 100755 D02HH_Practice/ntuple_options.py

diff --git a/D02HH_Practice/README.md b/D02HH_Practice/README.md
deleted file mode 100644
index cc34fb0b7a..0000000000
--- a/D02HH_Practice/README.md
+++ /dev/null
@@ -1 +0,0 @@
-I want weed XDDDD
diff --git a/D02HH_Practice/info.yaml b/D02HH_Practice/info.yaml
deleted file mode 100644
index dbe57daefb..0000000000
--- a/D02HH_Practice/info.yaml
+++ /dev/null
@@ -1,38 +0,0 @@
-defaults:
-    application: DaVinci/v46r10
-    wg: Charm
-    automatically_configure: yes
-    turbo: no
-    inform:
-        - chinghua@cern.ch
-    options:
-        - ntuple_options.py
-    output: D02KK.ROOT
-checks:
-    histogram:
-        type: range
-        expression: Dst_2010_plus_M
-        limits:
-            min: 1900
-            max: 2300
-        blind_ranges:
-            min: 2000
-            max: 2020
-    histogram_fail:
-        type: range
-        expression: Dst_2010_plus_M
-        limits:
-            min: 0
-            max: 10
-    at_least_50_entries:
-        type: num_entries
-        tree_pattern: TupleDstToD0pi_D0ToKK/DecayTree
-        count: 50
-
-2016_MagDown_PromptMC_D02KK:
-    input:
-        bk_query: "/MC/2016/Beam6500GeV-2016-MagDown-Nu1.6-25ns-Pythia8/Sim09c/Trig0x6138160F/Reco16/Turbo03/Stripping28r1NoPrescalingFlagged/27163002/ALLSTREAMS.DST"
-    checks:
-        - histogram
-        - histogram_fail
-        - at_least_50_entries
diff --git a/D02HH_Practice/ntuple_options.py b/D02HH_Practice/ntuple_options.py
deleted file mode 100755
index 0297e5cc85..0000000000
--- a/D02HH_Practice/ntuple_options.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from Configurables import DecayTreeTuple
-
-## Specify the stream and stripping line
-stream = "AllStreams"
-line   = "D2hhPromptDst2D2KKLine"
-
-## We create the DecayTreeTuple object, and indicate the Input 
-## (i.e., the TES location where the desired candidates may be)
-## as well as the decay descriptor
-dtt = DecayTreeTuple("TupleDstToD0pi_D0ToKK")
-dtt.Inputs = ["/Event/{0}/Phys/{1}/Particles".format(stream, line)]
-dtt.Decay  = "[D*(2010)+ -> (D0 -> K- K+) pi+]CC"
-
-from Configurables import DaVinci
-
-DaVinci().UserAlgorithms += [dtt]
-
-# In general, thanks to using the automatically_configure setting, you don't need what's below so it can be removed
-"""
-DaVinci().InputType       = "DST"
-DaVinci().TupleFile       = "DVntuple.root"
-DaVinci().PrintFreq       = 1000
-DaVinci().DataType        = "2016"
-DaVinci().Simulation      = True
-DaVinci().Lumi            = not DaVinci().Simulation
-DaVinci().EvtMax          = -1
-DaVinci().CondDBtag       = "sim-20170721-2-vc-md100"
-DaVinci().DDDBtag         = "dddb-20170721-3"
-"""
-
-# The Analysis Productions software automatically finds a valid remote file to test on so we can drop this bit
-"""
-from GaudiConf import IOHelper
-
-IOHelper().inputFiles([
-	"./00070793_00000001_7.AllStreams.dst"
-], clear=True)
-"""
\ No newline at end of file
-- 
GitLab


From 12ff95b386cbf36cb8a21809b3f7e2fbaad3aa2c Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 12:02:11 +0200
Subject: [PATCH 25/57] Fix info.yaml

---
 RDstar_taue_2024data/info.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
index 2681a0a72b..49eb72ae27 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/RDstar_taue_2024data/info.yaml
@@ -21,7 +21,7 @@ defaults:
       conditions_version: master
       input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
       input_stream: "sl" # for streamed data
-      evt_max: 1000
+      #evt_max: 1000
   inform:
     - ching-hua.li@cern.ch
   wg: SL
-- 
GitLab


From b78916a57b7e0ee6eebfae540b68c6018a88d53c Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 13:17:33 +0200
Subject: [PATCH 26/57] add Brems variables

---
 RDstar_taue_2024data/info.yaml  |  6 +++---
 RDstar_taue_2024data/run_Dzl.py | 34 ++++++++++++++++++++++++++++-----
 2 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
index 49eb72ae27..808f8ee379 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/RDstar_taue_2024data/info.yaml
@@ -1,7 +1,7 @@
 checks:
-  hist_Sb_M:
+  hist:
     type: range
-    expression: Sb_M
+    expression: Lb_M
     limits:
       min: 2_000 
       max: 8_000 
@@ -39,5 +39,5 @@ RDstar_taue_{{ evttype }}_{{ polarity }}:
     keep_running: true
     n_test_lfns: 1 
   checks:
-   - hist_Sb_M
+   - hist
 {%- endfor %}
diff --git a/RDstar_taue_2024data/run_Dzl.py b/RDstar_taue_2024data/run_Dzl.py
index 56c3ea074d..24107c0c61 100644
--- a/RDstar_taue_2024data/run_Dzl.py
+++ b/RDstar_taue_2024data/run_Dzl.py
@@ -188,8 +188,31 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
 	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
 
+	vars_brems = FunctorCollection({})
+	vars_brems.update({"HASBREM": F.HASBREM})
+	#vars_brems.update({"HASBREMADDED": F.HASBREMADDED})
+	vars_brems.update({"BREMENERGY": F.BREMENERGY})
+	vars_brems.update({"BREMBENDCORR": F.BREMBENDCORR})
+	vars_brems.update({"BREMPIDE": F.BREMPIDE})
+	vars_brems.update({"ECALPIDE": F.ECALPIDE})
+	vars_brems.update({"ECALPIDMU": F.ECALPIDMU})
+	vars_brems.update({"HCALPIDE": F.HCALPIDE})
+	vars_brems.update({"HCALPIDMU": F.HCALPIDMU})
+	vars_brems.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
+	vars_brems.update({"ELECTRONSHOWERDLL": F.ELECTRONSHOWERDLL})
+	vars_brems.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2})
+	vars_brems.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2})
+	vars_brems.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2})
+	vars_brems.update({"ELECTRONENERGY": F.ELECTRONENERGY})
+	vars_brems.update({"BREMHYPOENERGY": F.BREMHYPOENERGY})
+	vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
+	#vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
+	vars_brems.update({"INBREM": F.INBREM})
+	vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
+	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
+
 	#return all functors
-	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars)
+	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars,vars_brems)
 	return functors
 
 def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
@@ -200,6 +223,7 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	var_B = functors[2]
 	vars_basic = functors[3]
 	evt_vars = functors[4]
+	vars_brems = functors[5]
 
 	#variables for Sb field
 	vars_Bst  = FunctorCollection()
@@ -250,10 +274,10 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	variables["Sb"]  = vars_composite + vars_Bst
 	variables["Lb"]  = vars_composite + var_B
 	variables["Lc"]  = vars_composite
-	variables["Lep"] = vars_basic
-	variables["Epi"] = vars_basic
-	variables["Km"] = vars_basic
-	variables["pip"] = vars_basic
+	variables["Lep"] = vars_basic + vars_brems
+	variables["Epi"] = vars_basic + vars_brems
+	variables["Km"] = vars_basic + vars_brems
+	variables["pip"] = vars_basic + vars_brems
 
 	#define tuple
 	my_tuple = Funtuple(
-- 
GitLab


From 6430e46f8ab23cf38bbb3d3ac71b05d01a02868e Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 6 May 2024 15:54:20 +0200
Subject: [PATCH 27/57] Fix info.yaml

---
 RDstar_taue_2024data/info.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/RDstar_taue_2024data/info.yaml b/RDstar_taue_2024data/info.yaml
index 808f8ee379..0651abb089 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/RDstar_taue_2024data/info.yaml
@@ -16,7 +16,7 @@ defaults:
       input_raw_format: 0.5
       input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
       simulation: False
-      data_type: "Upgrade"
+      #data_type: "Upgrade"
       geometry_version: run3/2024.Q1.2-v00.00
       conditions_version: master
       input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
-- 
GitLab


From 69e4306c947795326967e806e28b201be945c4ad Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Thu, 9 May 2024 13:54:03 +0200
Subject: [PATCH 28/57] Add info.yaml and run_Dzl.py

---
 .../info.yaml                                 | 12 +++----
 .../run_Dzl.py                                | 31 +++++++++++--------
 2 files changed, 24 insertions(+), 19 deletions(-)
 rename {RDstar_taue_2024data => SL_mu_nu_D0toKpi_2024_data}/info.yaml (83%)
 rename {RDstar_taue_2024data => SL_mu_nu_D0toKpi_2024_data}/run_Dzl.py (91%)

diff --git a/RDstar_taue_2024data/info.yaml b/SL_mu_nu_D0toKpi_2024_data/info.yaml
similarity index 83%
rename from RDstar_taue_2024data/info.yaml
rename to SL_mu_nu_D0toKpi_2024_data/info.yaml
index 0651abb089..6192c47c82 100644
--- a/RDstar_taue_2024data/info.yaml
+++ b/SL_mu_nu_D0toKpi_2024_data/info.yaml
@@ -1,17 +1,17 @@
 checks:
   hist:
     type: range
-    expression: Lb_M
+    expression: Sb_Delta_M
     limits:
-      min: 2_000 
-      max: 8_000 
-    n_bins: 100 
+      min: 130
+      max: 200 
+    n_bins: 70 
 
 defaults:
   application: "DaVinci/v64r4"
   output: DATA.ROOT
   options:
-    entrypoint: RDstar_taue_2024data.run_Dzl:main
+    entrypoint: SL_mu_nu_D0toKpi_2024_data.run_Dzl:main
     extra_options:
       input_raw_format: 0.5
       input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
@@ -30,7 +30,7 @@ defaults:
  ('2024Data', 'Down'),
 ]%}
 {%- for evttype, polarity in datasets %}
-RDstar_taue_{{ evttype }}_{{ polarity }}:
+b0_dstp_muon_and_taumu_{{ evttype }}_{{ polarity }}:
   input:
     bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
     dq_flags:
diff --git a/RDstar_taue_2024data/run_Dzl.py b/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
similarity index 91%
rename from RDstar_taue_2024data/run_Dzl.py
rename to SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
index 24107c0c61..0f0491375b 100644
--- a/RDstar_taue_2024data/run_Dzl.py
+++ b/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
@@ -228,6 +228,7 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	#variables for Sb field
 	vars_Bst  = FunctorCollection()
 	B_child   = F.CHILD(1, F.FORWARDARG0)
+	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
 	Epi_child = F.CHILD(2, F.FORWARDARG0)
 	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
 	#diff in vtx chi2 with and without extra particle
@@ -257,16 +258,20 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	#DOCACHI2 of extra particle wrt to mother i.e. Sb
 	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
 	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+	#vars_Bst['Dstar_M'] = F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))
+	#vars_Bst['D0_M'] = F.MASS @ (F.FOURMOMENTUM @ D0_child)
+	#vars_Bst['test_id'] = F.PARTICLE_ID @ D0_child
+	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
 
 	#define fields
 	fields = {}
-	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
-	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  e-)  [pi+]CC]CC'
-	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  e-)  [pi+]CC]CC'
-	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^e-)  [pi+]CC]CC'
-	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  e-) ^[pi+]CC]CC'
-	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  e-) [pi+]CC]CC'
-	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  e-) [pi+]CC]CC'
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  mu-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  mu-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  mu-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^mu-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  mu-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  mu-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  mu-) [pi+]CC]CC'
 
 	#add variables
 	variables = {}
@@ -303,14 +308,14 @@ def get_extra_pions():
 
 #def main(options):
 def main(options: Options):
-	line_name   = ['SpruceSLB_BuToD0ENu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu']
+	line_name   = ['SpruceSLB_BuToD0MuNu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu']
 
 	#define filer
-	my_filter_e = create_lines_filter(name="Filter_e", lines=[line_name[0]])
+	my_filter_mu = create_lines_filter(name="Filter_mu", lines=[line_name[0]])
 	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
 
 	#get data and extra particles
-	lb_e = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_mu = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
 	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
 	extra_particles = get_extra_pions()
 
@@ -319,17 +324,17 @@ def main(options: Options):
 	rec_summary = get_rec_summary()
 	hadron_candidate_id = 421
 	#make sb candidate
-	Bst_e = make_Bst(lb_e, extra_particles,'e',hadron_candidate_id,v2_pvs,False)
+	Bst_mu = make_Bst(lb_mu, extra_particles,'mu',hadron_candidate_id,v2_pvs,False)
 	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
 	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
 
 
-	tuple_file_e = tuple_Bst(Bst_e,'e', 'None', v2_pvs, rec_summary)
+	tuple_file_mu = tuple_Bst(Bst_mu,'mu', 'None', v2_pvs, rec_summary)
 	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
 
 	#define algorithms
 	user_algorithms = {}
-	user_algorithms['Alg_e'] = [my_filter_e, tuple_file_e]
+	user_algorithms['Alg_mu'] = [my_filter_mu, tuple_file_mu]
 	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
 
 	return make_config(options, user_algorithms)
-- 
GitLab


From 272e173983bbbaef4a880378fd1acee138d6d08a Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Sun, 12 May 2024 11:40:41 +0200
Subject: [PATCH 29/57] Add D0toKpi l nu fakeline

---
 SL_e_nu_D0toKpi_fakeline_2024_data/info.yaml  |  43 +++
 SL_e_nu_D0toKpi_fakeline_2024_data/run_Dzl.py | 340 ++++++++++++++++++
 SL_mu_nu_D0toKpi_2024_data/run_Dzl.py         |  26 +-
 SL_mu_nu_D0toKpi_fakeline_2024_data/info.yaml |  43 +++
 .../run_Dzl.py                                | 340 ++++++++++++++++++
 5 files changed, 779 insertions(+), 13 deletions(-)
 create mode 100644 SL_e_nu_D0toKpi_fakeline_2024_data/info.yaml
 create mode 100644 SL_e_nu_D0toKpi_fakeline_2024_data/run_Dzl.py
 create mode 100644 SL_mu_nu_D0toKpi_fakeline_2024_data/info.yaml
 create mode 100644 SL_mu_nu_D0toKpi_fakeline_2024_data/run_Dzl.py

diff --git a/SL_e_nu_D0toKpi_fakeline_2024_data/info.yaml b/SL_e_nu_D0toKpi_fakeline_2024_data/info.yaml
new file mode 100644
index 0000000000..c4f455a0ee
--- /dev/null
+++ b/SL_e_nu_D0toKpi_fakeline_2024_data/info.yaml
@@ -0,0 +1,43 @@
+checks:
+  hist:
+    type: range
+    expression: Sb_Delta_M
+    limits:
+      min: 130
+      max: 200 
+    n_bins: 70 
+
+defaults:
+  application: "DaVinci/v64r4"
+  output: DATA.ROOT
+  options:
+    entrypoint: SL_e_nu_D0toKpi_fakeline_2024_data.run_Dzl:main
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
+      simulation: False
+      #data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "sl" # for streamed data
+      #evt_max: 1000
+  inform:
+    - ching-hua.li@cern.ch
+  wg: SL
+
+{%- set datasets = [
+ ('2024Data', 'Down'),
+]%}
+{%- for evttype, polarity in datasets %}
+b0_dstp_e_and_taue_fake_{{ evttype }}_{{ polarity }}:
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    keep_running: true
+    n_test_lfns: 1 
+  checks:
+   - hist
+{%- endfor %}
diff --git a/SL_e_nu_D0toKpi_fakeline_2024_data/run_Dzl.py b/SL_e_nu_D0toKpi_fakeline_2024_data/run_Dzl.py
new file mode 100644
index 0000000000..8bc45c7c87
--- /dev/null
+++ b/SL_e_nu_D0toKpi_fakeline_2024_data/run_Dzl.py
@@ -0,0 +1,340 @@
+import sys,os,math
+from PyConf.reading import get_pvs, get_rec_summary, get_particles
+import Functors as F
+from FunTuple import FunctorCollection
+from FunTuple import FunTuple_Particles as Funtuple
+from DaVinci.algorithms import create_lines_filter
+from DaVinci import Options,make_config
+import FunTuple.functorcollections as FC
+from DaVinciMCTools import MCTruthAndBkgCat
+from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Functors.grammar import Functor
+from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
+
+_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
+_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
+_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
+#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
+#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
+ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
+#MCNEUTRINO = F.FIND_MCDECAY("[ Lambda_b0 => Lambda_c+ mu- ^nu_mu~ ]CC")
+
+TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
+#MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(1, F.PARTICLE_ID)) == id)
+#GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(2, F.PARTICLE_ID)) == id)
+#GD_GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(3, F.PARTICLE_ID)) == id)
+
+def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
+	if do_truth_matching == True :
+		#filter B keeping only true D0 and true leptons
+		MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
+		Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
+		lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
+		Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
+		lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
+		cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
+		signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
+	else : signal_B = B
+
+	#combine to make [B*0 -> B*- pi+]cc
+	Bst_1 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_1_{lepton}',
+		DecayDescriptor='[B0 -> B- pi+]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#combine to make [B*0 -> B*- pi-]cc
+	Bst_2 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_2_{lepton}',
+		DecayDescriptor='[B0 -> B- pi-]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#merge the two Bst candidates
+	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
+	return Bst
+
+def get_functors(MCTRUTH, v2_pvs, rec_summary):
+	#define common variables for all fields (composite and basic)
+	vars_common  = FunctorCollection()
+	#all pvs: ip, ipchi2. The PV positions are stored in event variables
+	vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
+	vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
+	#best pv: x, y, z, ip, ipchi2
+	vars_common['BPV_X']          = F.BPVX(v2_pvs)
+	vars_common['BPV_Y']          = F.BPVY(v2_pvs)
+	vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
+	vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
+	vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
+	vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
+	vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
+	#particle id, key, truekey. The trueid is stored in MCHierarchy
+	vars_common['ID']            = F.PARTICLE_ID
+	vars_common['KEY']           = F.OBJECT_KEY
+	#get charge, min ip and min ipchi2
+	vars_common['CHARGE']        = F.CHARGE
+	vars_common['MINIP']         = F.MINIP(v2_pvs)
+	vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
+	#reco kinematics
+	vars_common += FC.Kinematics()
+	vars_common['ETA']           = F.ETA
+	vars_common['PHI']           = F.PHI
+	if MCTRUTH != 'None':
+		#mc vars
+		vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
+		vars_common['TRUEETA'] = MCTRUTH(F.ETA)
+		vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
+		#type of the origin vertex
+		vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
+		##mc truth hierarchy (done seperately)
+		#vars_common += FC.MCHierarchy(mctruth_alg = MCTRUTH)
+		#make some helper functions
+		MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
+		MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
+		vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
+		vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
+		vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
+		for i in range(2,14):
+		  prefix = "MC_GD_MOTHER_{}".format(i)
+		  vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
+		  vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
+
+	#variables for composite particles
+	vars_composite  = FunctorCollection()
+	#end vertex position and end vertex chi2
+	vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
+	vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
+	vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
+	#all pvs: dira, fd, fdchi2
+	vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
+	vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
+	vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
+	vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
+	vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
+	#best pv: dira, fd, fdchi2, corrm, ltime, dls
+	vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
+	vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
+	vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
+	vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
+	vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
+	vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
+	#mc composite vertex information
+
+	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
+	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
+	# only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
+	# the DOCA/DOCACHI2 see below.
+	vars_composite['MAX_DOCA'] = F.MAXDOCA
+	vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
+	vars_composite['MAX_SDOCA'] = F.MAXSDOCA
+	vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
+
+	#variables for Lb field
+	var_B  = FunctorCollection()
+	#var_B['TRUENU_PX'] = MCTRUTH(F.PX @ MCNEUTRINO)
+	#var_B['TRUENU_PY'] = MCTRUTH(F.PY @ MCNEUTRINO)
+	#var_B['TRUENU_PZ'] = MCTRUTH(F.PZ @ MCNEUTRINO)
+	#var_B['TRUENU_ENERGY'] = MCTRUTH(F.ENERGY @ MCNEUTRINO)
+	###Bkg category
+	##var_B["BKGCAT"] = MCTRUTH.BkgCat
+
+	#variables for basics
+	vars_basic  = FunctorCollection()
+	vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
+	vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
+	vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
+	vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
+	vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
+	vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
+	vars_basic['GHOSTPROB'] = F.GHOSTPROB
+	vars_basic['PIDpi'] = F.PID_PI
+	vars_basic['PIDk']  = F.PID_K
+	vars_basic['PIDp']  = F.PID_P
+	vars_basic['PIDe']  = F.PID_E
+	vars_basic['PIDmu'] = F.PID_MU
+	if MCTRUTH != 'None':
+		vars_basic['TRUEORIGINVERTEX_X'] = MCTRUTH(F.ORIGIN_VX)
+		vars_basic['TRUEORIGINVERTEX_Y'] = MCTRUTH(F.ORIGIN_VY)
+		vars_basic['TRUEORIGINVERTEX_Z'] = MCTRUTH(F.ORIGIN_VZ)
+
+	#variables for event
+	evt_vars = FunctorCollection()
+	#evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
+	#evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
+	#evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
+	#evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
+	#evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
+	evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
+	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
+	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
+
+	vars_brems = FunctorCollection({})
+	vars_brems.update({"HASBREM": F.HASBREM})
+	#vars_brems.update({"HASBREMADDED": F.HASBREMADDED})
+	vars_brems.update({"BREMENERGY": F.BREMENERGY})
+	vars_brems.update({"BREMBENDCORR": F.BREMBENDCORR})
+	vars_brems.update({"BREMPIDE": F.BREMPIDE})
+	vars_brems.update({"ECALPIDE": F.ECALPIDE})
+	vars_brems.update({"ECALPIDMU": F.ECALPIDMU})
+	vars_brems.update({"HCALPIDE": F.HCALPIDE})
+	vars_brems.update({"HCALPIDMU": F.HCALPIDMU})
+	vars_brems.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
+	vars_brems.update({"ELECTRONSHOWERDLL": F.ELECTRONSHOWERDLL})
+	vars_brems.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2})
+	vars_brems.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2})
+	vars_brems.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2})
+	vars_brems.update({"ELECTRONENERGY": F.ELECTRONENERGY})
+	vars_brems.update({"BREMHYPOENERGY": F.BREMHYPOENERGY})
+	vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
+	#vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
+	vars_brems.update({"INBREM": F.INBREM})
+	vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
+	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
+
+	#return all functors
+	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars,vars_brems)
+	return functors
+
+def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
+	#get functors
+	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
+	vars_common = functors[0]
+	vars_composite = functors[1]
+	var_B = functors[2]
+	vars_basic = functors[3]
+	evt_vars = functors[4]
+	vars_brems = functors[5]
+
+	#variables for Sb field
+	vars_Bst  = FunctorCollection()
+	B_child   = F.CHILD(1, F.FORWARDARG0)
+	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
+	Epi_child = F.CHILD(2, F.FORWARDARG0)
+	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+	#diff in vtx chi2 with and without extra particle
+	vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
+	#IP and IPChi2 of extra particle wrt to Sb end vertex
+	vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	#IP and IPChi2 of extra particle wrt to Lb end vertex
+	vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+	#angle between extra particle and Lb
+	vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+	#diff in fd chi2 with and without extra particle
+	vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
+	vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+	#IP chi2 of extra particle wrt PV and SV of Sb
+	vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	#IP chi2 of extra particle wrt PV and SV of Bb
+	vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+	#DOCA and DOCACHI2 b/w Lb and extra particle
+	vars_Bst['DOCA12']       = F.DOCA(1, 2)
+	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+	#vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
+	#vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
+	#DOCACHI2 of extra particle wrt to mother i.e. Sb
+	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
+	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+	#vars_Bst['Dstar_M'] = F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))
+	#vars_Bst['D0_M'] = F.MASS @ (F.FOURMOMENTUM @ D0_child)
+	#vars_Bst['test_id'] = F.PARTICLE_ID @ D0_child
+	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
+
+	#define fields
+	fields = {}
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^{lepton}-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  {lepton}-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  {lepton}-) [pi+]CC]CC'
+
+	#add variables
+	variables = {}
+	variables["ALL"] = vars_common
+	variables["Sb"]  = vars_composite + vars_Bst
+	variables["Lb"]  = vars_composite + var_B
+	variables["Lc"]  = vars_composite
+	variables["Lep"] = vars_basic + vars_brems
+	variables["Epi"] = vars_basic + vars_brems
+	variables["Km"] = vars_basic + vars_brems
+	variables["pip"] = vars_basic + vars_brems
+
+	#define tuple
+	my_tuple = Funtuple(
+		name=f"Tuple_{lepton}",
+		tuple_name="DecayTree",
+		fields=fields,
+		variables=variables,
+		inputs=Bst)
+
+	return my_tuple
+
+def get_extra_pions():
+	"""
+	Note this function in DaVinci requires:
+	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
+	and it's related LHCb, DaVinci and Rec MRs
+	"""
+	long_pions = make_has_rich_long_pions()
+	up_pions = make_has_rich_up_pions()
+	down_pions = make_has_rich_down_pions()
+	return ParticleContainersMerger([long_pions, up_pions, down_pions],
+									name='Pions_combiner')
+
+#def main(options):
+def main(options: Options):
+	line_name = ['SpruceSLB_BuToD0ENu_D0ToKPi_FakeElectron','SpruceSLB_BuToD0TauNu_D0ToKPi_FakeElectron']
+
+	#define filer
+	my_filter_l = create_lines_filter(name="Filter_l", lines=[line_name[0]])
+	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
+
+	#get data and extra particles
+	lb_l = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
+	extra_particles = get_extra_pions()
+
+	#get v2_pvs and rec_summary
+	v2_pvs  = get_pvs()
+	rec_summary = get_rec_summary()
+	hadron_candidate_id = 421
+	#make sb candidate
+	Bst_l = make_Bst(lb_l, extra_particles,'e',hadron_candidate_id,v2_pvs,False)
+	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
+	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+
+
+	tuple_file_l = tuple_Bst(Bst_l,'e', 'None', v2_pvs, rec_summary)
+	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
+
+	#define algorithms
+	user_algorithms = {}
+	user_algorithms['Alg_l'] = [my_filter_l, tuple_file_l]
+	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
+
+	return make_config(options, user_algorithms)
diff --git a/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py b/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
index 0f0491375b..0cb5e40d2a 100644
--- a/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
+++ b/SL_mu_nu_D0toKpi_2024_data/run_Dzl.py
@@ -265,13 +265,13 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 
 	#define fields
 	fields = {}
-	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  mu-)  [pi+]CC]CC'
-	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  mu-)  [pi+]CC]CC'
-	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  mu-)  [pi+]CC]CC'
-	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^mu-)  [pi+]CC]CC'
-	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  mu-) ^[pi+]CC]CC'
-	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  mu-) [pi+]CC]CC'
-	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  mu-) [pi+]CC]CC'
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^{lepton}-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  {lepton}-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  {lepton}-) [pi+]CC]CC'
 
 	#add variables
 	variables = {}
@@ -308,14 +308,14 @@ def get_extra_pions():
 
 #def main(options):
 def main(options: Options):
-	line_name   = ['SpruceSLB_BuToD0MuNu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu']
+	line_name = ['SpruceSLB_BuToD0MuNu_D0ToKPi','SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu']
 
 	#define filer
-	my_filter_mu = create_lines_filter(name="Filter_mu", lines=[line_name[0]])
+	my_filter_l = create_lines_filter(name="Filter_l", lines=[line_name[0]])
 	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
 
 	#get data and extra particles
-	lb_mu = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_l = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
 	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
 	extra_particles = get_extra_pions()
 
@@ -324,17 +324,17 @@ def main(options: Options):
 	rec_summary = get_rec_summary()
 	hadron_candidate_id = 421
 	#make sb candidate
-	Bst_mu = make_Bst(lb_mu, extra_particles,'mu',hadron_candidate_id,v2_pvs,False)
+	Bst_l = make_Bst(lb_l, extra_particles,'mu',hadron_candidate_id,v2_pvs,False)
 	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
 	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
 
 
-	tuple_file_mu = tuple_Bst(Bst_mu,'mu', 'None', v2_pvs, rec_summary)
+	tuple_file_l = tuple_Bst(Bst_l,'mu', 'None', v2_pvs, rec_summary)
 	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
 
 	#define algorithms
 	user_algorithms = {}
-	user_algorithms['Alg_mu'] = [my_filter_mu, tuple_file_mu]
+	user_algorithms['Alg_l'] = [my_filter_l, tuple_file_l]
 	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
 
 	return make_config(options, user_algorithms)
diff --git a/SL_mu_nu_D0toKpi_fakeline_2024_data/info.yaml b/SL_mu_nu_D0toKpi_fakeline_2024_data/info.yaml
new file mode 100644
index 0000000000..c2d8975aac
--- /dev/null
+++ b/SL_mu_nu_D0toKpi_fakeline_2024_data/info.yaml
@@ -0,0 +1,43 @@
+checks:
+  hist:
+    type: range
+    expression: Sb_Delta_M
+    limits:
+      min: 130
+      max: 200 
+    n_bins: 70 
+
+defaults:
+  application: "DaVinci/v64r4"
+  output: DATA.ROOT
+  options:
+    entrypoint: SL_mu_nu_D0toKpi_fakeline_2024_data.run_Dzl:main
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
+      simulation: False
+      #data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "sl" # for streamed data
+      #evt_max: 1000
+  inform:
+    - ching-hua.li@cern.ch
+  wg: SL
+
+{%- set datasets = [
+ ('2024Data', 'Down'),
+]%}
+{%- for evttype, polarity in datasets %}
+b0_dstp_muon_and_taumu_fake_{{ evttype }}_{{ polarity }}:
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    keep_running: true
+    n_test_lfns: 1 
+  checks:
+   - hist
+{%- endfor %}
diff --git a/SL_mu_nu_D0toKpi_fakeline_2024_data/run_Dzl.py b/SL_mu_nu_D0toKpi_fakeline_2024_data/run_Dzl.py
new file mode 100644
index 0000000000..2d3d332375
--- /dev/null
+++ b/SL_mu_nu_D0toKpi_fakeline_2024_data/run_Dzl.py
@@ -0,0 +1,340 @@
+import sys,os,math
+from PyConf.reading import get_pvs, get_rec_summary, get_particles
+import Functors as F
+from FunTuple import FunctorCollection
+from FunTuple import FunTuple_Particles as Funtuple
+from DaVinci.algorithms import create_lines_filter
+from DaVinci import Options,make_config
+import FunTuple.functorcollections as FC
+from DaVinciMCTools import MCTruthAndBkgCat
+from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Functors.grammar import Functor
+from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
+
+_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
+_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
+_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
+#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
+#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
+ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
+#MCNEUTRINO = F.FIND_MCDECAY("[ Lambda_b0 => Lambda_c+ mu- ^nu_mu~ ]CC")
+
+TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
+#MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(1, F.PARTICLE_ID)) == id)
+#GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(2, F.PARTICLE_ID)) == id)
+#GD_GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(3, F.PARTICLE_ID)) == id)
+
+def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
+	if do_truth_matching == True :
+		#filter B keeping only true D0 and true leptons
+		MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
+		Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
+		lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
+		Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
+		lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
+		cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
+		signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
+	else : signal_B = B
+
+	#combine to make [B*0 -> B*- pi+]cc
+	Bst_1 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_1_{lepton}',
+		DecayDescriptor='[B0 -> B- pi+]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#combine to make [B*0 -> B*- pi-]cc
+	Bst_2 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_2_{lepton}',
+		DecayDescriptor='[B0 -> B- pi-]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#merge the two Bst candidates
+	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
+	return Bst
+
+def get_functors(MCTRUTH, v2_pvs, rec_summary):
+	#define common variables for all fields (composite and basic)
+	vars_common  = FunctorCollection()
+	#all pvs: ip, ipchi2. The PV positions are stored in event variables
+	vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
+	vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
+	#best pv: x, y, z, ip, ipchi2
+	vars_common['BPV_X']          = F.BPVX(v2_pvs)
+	vars_common['BPV_Y']          = F.BPVY(v2_pvs)
+	vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
+	vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
+	vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
+	vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
+	vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
+	#particle id, key, truekey. The trueid is stored in MCHierarchy
+	vars_common['ID']            = F.PARTICLE_ID
+	vars_common['KEY']           = F.OBJECT_KEY
+	#get charge, min ip and min ipchi2
+	vars_common['CHARGE']        = F.CHARGE
+	vars_common['MINIP']         = F.MINIP(v2_pvs)
+	vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
+	#reco kinematics
+	vars_common += FC.Kinematics()
+	vars_common['ETA']           = F.ETA
+	vars_common['PHI']           = F.PHI
+	if MCTRUTH != 'None':
+		#mc vars
+		vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
+		vars_common['TRUEETA'] = MCTRUTH(F.ETA)
+		vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
+		#type of the origin vertex
+		vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
+		##mc truth hierarchy (done seperately)
+		#vars_common += FC.MCHierarchy(mctruth_alg = MCTRUTH)
+		#make some helper functions
+		MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
+		MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
+		vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
+		vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
+		vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
+		for i in range(2,14):
+		  prefix = "MC_GD_MOTHER_{}".format(i)
+		  vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
+		  vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
+
+	#variables for composite particles
+	vars_composite  = FunctorCollection()
+	#end vertex position and end vertex chi2
+	vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
+	vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
+	vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
+	#all pvs: dira, fd, fdchi2
+	vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
+	vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
+	vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
+	vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
+	vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
+	#best pv: dira, fd, fdchi2, corrm, ltime, dls
+	vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
+	vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
+	vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
+	vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
+	vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
+	vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
+	#mc composite vertex information
+
+	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
+	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
+	# only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
+	# the DOCA/DOCACHI2 see below.
+	vars_composite['MAX_DOCA'] = F.MAXDOCA
+	vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
+	vars_composite['MAX_SDOCA'] = F.MAXSDOCA
+	vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
+
+	#variables for Lb field
+	var_B  = FunctorCollection()
+	#var_B['TRUENU_PX'] = MCTRUTH(F.PX @ MCNEUTRINO)
+	#var_B['TRUENU_PY'] = MCTRUTH(F.PY @ MCNEUTRINO)
+	#var_B['TRUENU_PZ'] = MCTRUTH(F.PZ @ MCNEUTRINO)
+	#var_B['TRUENU_ENERGY'] = MCTRUTH(F.ENERGY @ MCNEUTRINO)
+	###Bkg category
+	##var_B["BKGCAT"] = MCTRUTH.BkgCat
+
+	#variables for basics
+	vars_basic  = FunctorCollection()
+	vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
+	vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
+	vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
+	vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
+	vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
+	vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
+	vars_basic['GHOSTPROB'] = F.GHOSTPROB
+	vars_basic['PIDpi'] = F.PID_PI
+	vars_basic['PIDk']  = F.PID_K
+	vars_basic['PIDp']  = F.PID_P
+	vars_basic['PIDe']  = F.PID_E
+	vars_basic['PIDmu'] = F.PID_MU
+	if MCTRUTH != 'None':
+		vars_basic['TRUEORIGINVERTEX_X'] = MCTRUTH(F.ORIGIN_VX)
+		vars_basic['TRUEORIGINVERTEX_Y'] = MCTRUTH(F.ORIGIN_VY)
+		vars_basic['TRUEORIGINVERTEX_Z'] = MCTRUTH(F.ORIGIN_VZ)
+
+	#variables for event
+	evt_vars = FunctorCollection()
+	#evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
+	#evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
+	#evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
+	#evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
+	#evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
+	evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
+	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
+	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
+
+	vars_brems = FunctorCollection({})
+	vars_brems.update({"HASBREM": F.HASBREM})
+	#vars_brems.update({"HASBREMADDED": F.HASBREMADDED})
+	vars_brems.update({"BREMENERGY": F.BREMENERGY})
+	vars_brems.update({"BREMBENDCORR": F.BREMBENDCORR})
+	vars_brems.update({"BREMPIDE": F.BREMPIDE})
+	vars_brems.update({"ECALPIDE": F.ECALPIDE})
+	vars_brems.update({"ECALPIDMU": F.ECALPIDMU})
+	vars_brems.update({"HCALPIDE": F.HCALPIDE})
+	vars_brems.update({"HCALPIDMU": F.HCALPIDMU})
+	vars_brems.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
+	vars_brems.update({"ELECTRONSHOWERDLL": F.ELECTRONSHOWERDLL})
+	vars_brems.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2})
+	vars_brems.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2})
+	vars_brems.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2})
+	vars_brems.update({"ELECTRONENERGY": F.ELECTRONENERGY})
+	vars_brems.update({"BREMHYPOENERGY": F.BREMHYPOENERGY})
+	vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
+	#vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
+	vars_brems.update({"INBREM": F.INBREM})
+	vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
+	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
+
+	#return all functors
+	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars,vars_brems)
+	return functors
+
+def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
+	#get functors
+	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
+	vars_common = functors[0]
+	vars_composite = functors[1]
+	var_B = functors[2]
+	vars_basic = functors[3]
+	evt_vars = functors[4]
+	vars_brems = functors[5]
+
+	#variables for Sb field
+	vars_Bst  = FunctorCollection()
+	B_child   = F.CHILD(1, F.FORWARDARG0)
+	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
+	Epi_child = F.CHILD(2, F.FORWARDARG0)
+	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+	#diff in vtx chi2 with and without extra particle
+	vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
+	#IP and IPChi2 of extra particle wrt to Sb end vertex
+	vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	#IP and IPChi2 of extra particle wrt to Lb end vertex
+	vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+	#angle between extra particle and Lb
+	vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+	#diff in fd chi2 with and without extra particle
+	vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
+	vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+	#IP chi2 of extra particle wrt PV and SV of Sb
+	vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	#IP chi2 of extra particle wrt PV and SV of Bb
+	vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+	#DOCA and DOCACHI2 b/w Lb and extra particle
+	vars_Bst['DOCA12']       = F.DOCA(1, 2)
+	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+	#vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
+	#vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
+	#DOCACHI2 of extra particle wrt to mother i.e. Sb
+	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
+	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+	#vars_Bst['Dstar_M'] = F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))
+	#vars_Bst['D0_M'] = F.MASS @ (F.FOURMOMENTUM @ D0_child)
+	#vars_Bst['test_id'] = F.PARTICLE_ID @ D0_child
+	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
+
+	#define fields
+	fields = {}
+	fields['Sb']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lb']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lc']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  {lepton}-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^{lepton}-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  {lepton}-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  {lepton}-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  {lepton}-) [pi+]CC]CC'
+
+	#add variables
+	variables = {}
+	variables["ALL"] = vars_common
+	variables["Sb"]  = vars_composite + vars_Bst
+	variables["Lb"]  = vars_composite + var_B
+	variables["Lc"]  = vars_composite
+	variables["Lep"] = vars_basic + vars_brems
+	variables["Epi"] = vars_basic + vars_brems
+	variables["Km"] = vars_basic + vars_brems
+	variables["pip"] = vars_basic + vars_brems
+
+	#define tuple
+	my_tuple = Funtuple(
+		name=f"Tuple_{lepton}",
+		tuple_name="DecayTree",
+		fields=fields,
+		variables=variables,
+		inputs=Bst)
+
+	return my_tuple
+
+def get_extra_pions():
+	"""
+	Note this function in DaVinci requires:
+	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
+	and it's related LHCb, DaVinci and Rec MRs
+	"""
+	long_pions = make_has_rich_long_pions()
+	up_pions = make_has_rich_up_pions()
+	down_pions = make_has_rich_down_pions()
+	return ParticleContainersMerger([long_pions, up_pions, down_pions],
+									name='Pions_combiner')
+
+#def main(options):
+def main(options: Options):
+	line_name = ['SpruceSLB_BuToD0MuNu_D0ToKPi_FakeMuon','SpruceSLB_BuToD0TauNu_D0ToKPi_FakeMuon']
+
+	#define filer
+	my_filter_l = create_lines_filter(name="Filter_l", lines=[line_name[0]])
+	my_filter_tau = create_lines_filter(name="Filter_tau", lines=[line_name[1]])
+
+	#get data and extra particles
+	lb_l = get_particles(f"/Event/Spruce/{line_name[0]}/Particles")
+	lb_tau = get_particles(f"/Event/Spruce/{line_name[1]}/Particles")
+	extra_particles = get_extra_pions()
+
+	#get v2_pvs and rec_summary
+	v2_pvs  = get_pvs()
+	rec_summary = get_rec_summary()
+	hadron_candidate_id = 421
+	#make sb candidate
+	Bst_l = make_Bst(lb_l, extra_particles,'mu',hadron_candidate_id,v2_pvs,False)
+	Bst_tau = make_Bst(lb_tau, extra_particles,'tau', hadron_candidate_id,v2_pvs,False)
+	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+
+
+	tuple_file_l = tuple_Bst(Bst_l,'mu', 'None', v2_pvs, rec_summary)
+	tuple_file_tau = tuple_Bst(Bst_tau,'tau', 'None', v2_pvs, rec_summary)
+
+	#define algorithms
+	user_algorithms = {}
+	user_algorithms['Alg_l'] = [my_filter_l, tuple_file_l]
+	user_algorithms['Alg_tau'] = [my_filter_tau, tuple_file_tau]
+
+	return make_config(options, user_algorithms)
-- 
GitLab


From 10755802951f5c45dff96e4ee095791d4fd65604 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Fri, 24 May 2024 10:06:38 +0200
Subject: [PATCH 30/57] add everything

---
 SL_l_nu_D0toKpi_Run3_MC/DV.py     | 377 ++++++++++++++++++++++++++++++
 SL_l_nu_D0toKpi_Run3_MC/Hlt1.py   |  26 +++
 SL_l_nu_D0toKpi_Run3_MC/Hlt2.py   | 129 ++++++++++
 SL_l_nu_D0toKpi_Run3_MC/info.yaml |  85 +++++++
 4 files changed, 617 insertions(+)
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC/DV.py
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC/Hlt1.py
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC/info.yaml

diff --git a/SL_l_nu_D0toKpi_Run3_MC/DV.py b/SL_l_nu_D0toKpi_Run3_MC/DV.py
new file mode 100644
index 0000000000..04f1272761
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC/DV.py
@@ -0,0 +1,377 @@
+import sys,os,math
+from PyConf.reading import get_pvs, get_rec_summary, get_particles
+import Functors as F
+from FunTuple import FunctorCollection
+from FunTuple import FunTuple_Particles as Funtuple
+from DaVinci.algorithms import create_lines_filter
+from DaVinci import Options,make_config
+import FunTuple.functorcollections as FC
+from DaVinciMCTools import MCTruthAndBkgCat
+from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Functors.grammar import Functor
+from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
+import numpy as np
+
+_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
+_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
+_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
+#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
+#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
+ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
+#MCNEUTRINO = F.FIND_MCDECAY("[ Lambda_b0 => Lambda_c+ mu- ^nu_mu~ ]CC")
+
+TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
+#MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(1, F.PARTICLE_ID)) == id)
+#GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(2, F.PARTICLE_ID)) == id)
+#GD_GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(3, F.PARTICLE_ID)) == id)
+
+def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
+	if do_truth_matching == True :
+		#filter B keeping only true D0 and true leptons
+		MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
+		Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
+		lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
+		Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
+		lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
+		cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
+		signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
+	else : signal_B = B
+
+	#combine to make [B*0 -> B*- pi+]cc
+	Bst_1 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_1_{lepton}',
+		DecayDescriptor='[B0 -> B- pi+]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#combine to make [B*0 -> B*- pi-]cc
+	Bst_2 = ParticleCombiner(
+		Inputs=[B, pions],
+		name=f'Bst_2_{lepton}',
+		DecayDescriptor='[B0 -> B- pi-]cc',
+		CombinationCut=F.ALL,
+		CompositeCut=F.ALL,
+		ParticleCombiner="ParticleVertexFitter",
+		PrimaryVertices=v2_pvs
+		#OutputLevel=1
+	)
+	#merge the two Bst candidates
+	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
+	return Bst
+
+def get_functors(MCTRUTH, v2_pvs, rec_summary):
+	#define common variables for all fields (composite and basic)
+	vars_common  = FunctorCollection()
+	#all pvs: ip, ipchi2. The PV positions are stored in event variables
+	vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
+	vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
+	#best pv: x, y, z, ip, ipchi2
+	vars_common['BPV_X']          = F.BPVX(v2_pvs)
+	vars_common['BPV_Y']          = F.BPVY(v2_pvs)
+	vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
+	vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
+	vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
+	vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
+	vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
+	#particle id, key, truekey. The trueid is stored in MCHierarchy
+	vars_common['ID']            = F.PARTICLE_ID
+	vars_common['KEY']           = F.OBJECT_KEY
+
+	#get charge, min ip and min ipchi2
+	vars_common['CHARGE']        = F.CHARGE
+	vars_common['MINIP']         = F.MINIP(v2_pvs)
+	vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
+	#reco kinematics
+	vars_common += FC.Kinematics()
+	vars_common['ETA']           = F.ETA
+	vars_common['PHI']           = F.PHI
+	if MCTRUTH != 'None':
+		#mc vars
+		vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
+		vars_common['TRUEETA'] = MCTRUTH(F.ETA)
+		vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
+		#type of the origin vertex
+		vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
+		##mc truth hierarchy (done seperately)
+		#vars_common += FC.MCHierarchy(mctruth_alg = MCTRUTH)
+		#make some helper functions
+		MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
+		MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
+		vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
+		vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
+		vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
+		vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
+		for i in range(2,14):
+		  prefix = "MC_GD_MOTHER_{}".format(i)
+		  vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
+		  vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
+
+	#variables for composite particles
+	vars_composite  = FunctorCollection()
+	#end vertex position and end vertex chi2
+	vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
+	vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
+	vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
+	#all pvs: dira, fd, fdchi2
+	vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
+	vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
+	vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
+	vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
+	vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
+	vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
+	#best pv: dira, fd, fdchi2, corrm, ltime, dls
+	vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
+	vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
+	vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
+	vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
+	vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
+	vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
+	#mc composite vertex information
+
+	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
+	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
+	# only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
+	# the DOCA/DOCACHI2 see below.
+	vars_composite['MAX_DOCA'] = F.MAXDOCA
+	vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
+	vars_composite['MAX_SDOCA'] = F.MAXSDOCA
+	vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
+
+	#variables for Lb field
+	var_B  = FunctorCollection()
+	#var_B['TRUENU_PX'] = MCTRUTH(F.PX @ MCNEUTRINO)
+	#var_B['TRUENU_PY'] = MCTRUTH(F.PY @ MCNEUTRINO)
+	#var_B['TRUENU_PZ'] = MCTRUTH(F.PZ @ MCNEUTRINO)
+	#var_B['TRUENU_ENERGY'] = MCTRUTH(F.ENERGY @ MCNEUTRINO)
+	###Bkg category
+	##var_B["BKGCAT"] = MCTRUTH.BkgCat
+
+	#variables for basics
+	vars_basic  = FunctorCollection()
+	vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
+	vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
+	vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
+	vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
+	vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
+	vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
+	vars_basic['GHOSTPROB'] = F.GHOSTPROB
+	vars_basic['PIDpi'] = F.PID_PI
+	vars_basic['PIDk']  = F.PID_K
+	vars_basic['PIDp']  = F.PID_P
+	vars_basic['PIDe']  = F.PID_E
+	vars_basic['PIDmu'] = F.PID_MU
+	vars_basic['PROBNNe'] = F.PROBNN_E
+	vars_basic['PROBNNpi'] = F.PROBNN_PI
+	vars_basic['PROBNNk'] = F.PROBNN_K
+	vars_basic['PROBNNmu'] = F.PROBNN_MU
+	vars_basic['PROBNNp'] = F.PROBNN_P
+	vars_basic['PROBNNghost'] = F.PROBNN_GHOST
+	if MCTRUTH != 'None':
+		vars_basic['TRUEORIGINVERTEX_X'] = MCTRUTH(F.ORIGIN_VX)
+		vars_basic['TRUEORIGINVERTEX_Y'] = MCTRUTH(F.ORIGIN_VY)
+		vars_basic['TRUEORIGINVERTEX_Z'] = MCTRUTH(F.ORIGIN_VZ)
+
+	#variables for event
+	evt_vars = FunctorCollection()
+	#evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
+	#evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
+	#evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
+	#evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
+	#evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
+	evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
+	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
+	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
+
+	vars_brems = FunctorCollection({})
+	vars_brems.update({"HASBREM": F.HASBREM})
+	#vars_brems.update({"HASBREMADDED": F.HASBREMADDED})
+	vars_brems.update({"BREMENERGY": F.BREMENERGY})
+	vars_brems.update({"BREMBENDCORR": F.BREMBENDCORR})
+	vars_brems.update({"BREMPIDE": F.BREMPIDE})
+	vars_brems.update({"ECALPIDE": F.ECALPIDE})
+	vars_brems.update({"ECALPIDMU": F.ECALPIDMU})
+	vars_brems.update({"HCALPIDE": F.HCALPIDE})
+	vars_brems.update({"HCALPIDMU": F.HCALPIDMU})
+	vars_brems.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
+	vars_brems.update({"ELECTRONSHOWERDLL": F.ELECTRONSHOWERDLL})
+	vars_brems.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2})
+	vars_brems.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2})
+	vars_brems.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2})
+	vars_brems.update({"ELECTRONENERGY": F.ELECTRONENERGY})
+	vars_brems.update({"BREMHYPOENERGY": F.BREMHYPOENERGY})
+	vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
+	#vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
+	vars_brems.update({"INBREM": F.INBREM})
+	vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
+	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
+
+	#return all functors
+	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars,vars_brems)
+	return functors
+
+def get_fitting_variable(v2_pvs,D0,lep):
+
+	B_dis = np.array([F.END_VX-F.BPVX(v2_pvs),F.END_VY-F.BPVY(v2_pvs),F.END_VZ-F.BPVZ(v2_pvs)])
+	B_dis_mag = F.SQRT @ (B_dis[0]**2+B_dis[1]**2+B_dis[2]**2)
+	B_Mod_P = F.ABS @ ((5279.65/F.MASS)*F.PZ/(B_dis[2]/B_dis_mag))
+	B_Mod_E = F.SQRT @ (B_Mod_P**2 + 5279.65**2)
+	B_4P = np.array([B_Mod_P*B_dis[0]/B_dis_mag,B_Mod_P*B_dis[1]/B_dis_mag,B_Mod_P*B_dis[2]/B_dis_mag,B_Mod_E])
+	D_4P = np.array([F.PX @ D0,F.PY @ D0,F.PZ @ D0,F.ENERGY @ D0])
+	lep_4P = np.array([F.PX @ lep,F.PY @ lep,F.PZ @ lep,F.ENERGY @ lep])
+
+	vars_fitting = FunctorCollection({})
+	vars_fitting["Mod_P"] = B_Mod_P
+	vars_fitting['missing_m2'] = (B_4P[3]-D_4P[3]-lep_4P[3])**2-(B_4P[0]-D_4P[0]-lep_4P[0])**2-(B_4P[1]-D_4P[1]-lep_4P[1])**2-(B_4P[2]-D_4P[2]-lep_4P[2])**2
+	vars_fitting['q2'] = (B_4P[3]-D_4P[3])**2-(B_4P[0]-D_4P[0])**2-(B_4P[1]-D_4P[1])**2-(B_4P[2]-D_4P[2])**2
+	B_Beta = B_Mod_P/B_Mod_E
+	B_gamma = 1/F.SQRT @ (1-B_Beta**2)
+
+	B_Lorentz = [[B_gamma,-1*B_gamma*B_4P[0]/B_4P[3],-1*B_gamma*B_4P[1]/B_4P[3],-1*B_gamma*B_4P[2]/B_4P[3]],[-1*B_gamma*B_4P[0]/B_4P[3],1+(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[0]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)],[-1*B_gamma*B_4P[1]/B_4P[3],(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)],[-1*B_gamma*B_4P[2]/B_4P[3],(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[2]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)]]
+	vars_fitting['lep_E_Brest'] = (B_Lorentz[0][0]*lep_4P[3]+B_Lorentz[0][1]*lep_4P[0]+B_Lorentz[0][2]*lep_4P[1]+B_Lorentz[0][3]*lep_4P[2])
+	return(vars_fitting)
+
+def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
+	#get functors
+	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
+	vars_common = functors[0]
+	vars_composite = functors[1]
+	var_B = functors[2]
+	vars_basic = functors[3]
+	evt_vars = functors[4]
+	vars_brems = functors[5]
+
+	#variables for Sb field
+	vars_Bst  = FunctorCollection()
+	B_child   = F.CHILD(1, F.FORWARDARG0)
+	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
+	Lep_child   = F.CHILD(1, F.CHILD(2,F.FORWARDARG0))
+	Epi_child = F.CHILD(2, F.FORWARDARG0)
+	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+	#diff in vtx chi2 with and without extra particle
+	vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
+	#IP and IPChi2 of extra particle wrt to Sb end vertex
+	vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	#IP and IPChi2 of extra particle wrt to Lb end vertex
+	vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+	#angle between extra particle and Lb
+	vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+	#diff in fd chi2 with and without extra particle
+	vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
+	vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+	#IP chi2 of extra particle wrt PV and SV of Sb
+	vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	#IP chi2 of extra particle wrt PV and SV of Bb
+	vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+	#DOCA and DOCACHI2 b/w Lb and extra particle
+	vars_Bst['DOCA12']       = F.DOCA(1, 2)
+	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+	#vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
+	#vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
+	#DOCACHI2 of extra particle wrt to mother i.e. Sb
+	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
+	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
+	#define fields
+	fit_vars = get_fitting_variable(v2_pvs,D0_child,Lep_child)
+
+
+	#define fields
+	fields = {}
+	fields['B0']    = f'[B0 ->  (B- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+	fields['Bm']    = f'[B0 -> ^(B- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+	fields['D0']    = f'[B0 ->  (B- -> ^([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B0 ->  (B- ->  ([D0 -> K- pi+]CC) ^{lepton}-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B0 ->  (B- ->  ([D0 -> K- pi+]CC)  {lepton}-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B0 ->  (B- ->  ([D0 -> ^K- pi+]CC)  {lepton}-) [pi+]CC]CC'
+	fields['pip']   = f'[B0 ->  (B- ->  ([D0 -> K- ^pi+]CC)  {lepton}-) [pi+]CC]CC'
+    
+	#add variables
+	variables = {}
+	variables["ALL"] = vars_common
+	variables["B0"]  = vars_composite + vars_Bst + fit_vars
+	variables["Bm"]  = vars_composite + var_B
+	variables["D0"]  = vars_composite
+	variables["Lep"] = vars_basic + vars_brems
+	variables["Epi"] = vars_basic + vars_brems
+	variables["Km"] = vars_basic + vars_brems
+	variables["pip"] = vars_basic + vars_brems
+
+	#define tuple
+	my_tuple = Funtuple(
+		name=f"Tuple",
+		tuple_name="DecayTree",
+		fields=fields,
+		variables=variables,
+		inputs=Bst)
+
+	return my_tuple
+
+def get_extra_pions():
+	"""
+	Note this function in DaVinci requires:
+	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
+	and it's related LHCb, DaVinci and Rec MRs
+	"""
+	long_pions = make_has_rich_long_pions()
+	up_pions = make_has_rich_up_pions()
+	down_pions = make_has_rich_down_pions()
+	return ParticleContainersMerger([long_pions, up_pions, down_pions],
+									name='Pions_combiner')
+
+#def main(options):
+def main(options: Options,line = '', lep=''):
+
+	#define filer
+	my_filter = create_lines_filter(name="Filter", lines=[line])
+
+	#get data and extra particles
+	lb = get_particles(f"/Event/HLT2/{line}/Particles")
+	extra_particles = get_extra_pions()
+
+	#get v2_pvs and rec_summary
+	v2_pvs  = get_pvs()
+	rec_summary = get_rec_summary()
+	hadron_candidate_id = 421
+	#make sb candidate
+	Bst = make_Bst(lb, extra_particles,lep,hadron_candidate_id,v2_pvs,False)
+	MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+
+
+	tuple_file = tuple_Bst(Bst,lep, MCTRUTH_Bst, v2_pvs, rec_summary)
+
+	#define algorithms
+	user_algorithms = {}
+	user_algorithms['Alg'] = [my_filter, tuple_file]
+
+	return make_config(options, user_algorithms)
+
+def SLB_BuToD0ENu_D0ToKPi(options: Options):
+	return main(options=options, line='Hlt2SLB_BToDzl',lep='e')
+
+def SLB_BuToD0MuNu_D0ToKPi(options: Options):
+	return main(options=options, line='Hlt2SLB_BuToD0MuNu_D0ToKPi',lep='mu')
+
+def SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
+	return main(options=options, line='Hlt2SLB_BToDzl',lep='e')
+
+def SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
+	return main(options=options, line='Hlt2SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu')
+
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Hlt1.py b/SL_l_nu_D0toKpi_Run3_MC/Hlt1.py
new file mode 100644
index 0000000000..e2d0622696
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC/Hlt1.py
@@ -0,0 +1,26 @@
+###############################################################################
+# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+from Moore import Options
+from Moore.config import allen_control_flow
+from RecoConf.hlt1_allen import allen_gaudi_config, get_allen_line_names
+from PyConf.application import configure_input, configure
+from RecoConf.muonid import make_muon_hits
+#need to bind geometry version to 3 for muon hits
+make_muon_hits.global_bind(geometry_version=3)
+
+def main(options: Options):
+    config = configure_input(options)
+    with allen_gaudi_config.bind(sequence="hlt1_pp_matching_no_ut_1000KHz"):
+        allen_node = allen_control_flow(options)
+        config.update(configure(options, allen_node))
+    return config
+
+
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py b/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
new file mode 100644
index 0000000000..e0d48da235
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
@@ -0,0 +1,129 @@
+###############################################################################
+# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+from Moore import Options,options, run_moore, config
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Hlt2Conf.lines.semileptonic.builders import sl_line_prefilter
+from Hlt2Conf.lines.semileptonic.builders.base_builder import make_candidate
+from Hlt2Conf.lines.semileptonic.builders.charm_hadron_builder import make_d0_tokpi
+from GaudiKernel.SystemOfUnits import MeV, GeV,mm
+from Hlt2Conf.algorithms_thor import ParticleCombiner
+from Moore.config import Hlt2Line
+from RecoConf.global_tools import stateProvider_with_simplified_geom
+from RecoConf.reconstruction_objects import reconstruction,make_pvs
+from RecoConf.decoders import default_ft_decoding_version
+from Hlt2Conf.standard_particles import (
+    make_long_electrons_with_brem,
+    make_has_rich_long_pions, 
+    make_has_rich_up_pions, 
+    make_has_rich_down_pions)
+import Functors as F
+from Functors.math import in_range
+
+#things to control
+SUFFIX_NAME = '_BToDzl'
+HLT2LINE = f'Hlt2SLB{SUFFIX_NAME}'
+CHARM_MASS = 1864.84 #D0 mass
+CHARM_BUILDER_NAME = 'Dz2KPi_combiner'
+B_BUILDER_NAME     = 'BToDzl_combiner'
+
+def get_charm_cuts():
+    #make loose cuts for D0
+    delta_mass   = 80. #80.0
+    make_d0tokpi_cuts  = {}
+    make_d0tokpi_cuts['comb_m_min']            = (CHARM_MASS - delta_mass) * MeV
+    make_d0tokpi_cuts['comb_m_max']            = (CHARM_MASS + delta_mass) * MeV
+    make_d0tokpi_cuts['comb_docachi2_max']     = 5.
+    make_d0tokpi_cuts['vchi2pdof_max']         = 6   #6 (2024) 6/4 (master e/taue)
+    make_d0tokpi_cuts['bpvfdchi2_min']         = 25  #25 (2024)
+    make_d0tokpi_cuts['bpvdira_min']           = 0.99  #0.99 (2024) 0.99/0.999 (master e/taue)
+    make_d0tokpi_cuts['comb_pt_min']           = None #None (2024) None/2000 * MeV (master e/taue)
+    make_d0tokpi_cuts['comb_pt_any_min']       = None #None (2024) None/800 * MeV (master e/taue)
+    make_d0tokpi_cuts['comb_pt_sum_min']       = None #None (2024) None/2.5 * GeV (master e/taue)
+    make_d0tokpi_cuts['comb_doca_max']         = None #None (2024) None/0.1 mm (master e/taue)
+    make_d0tokpi_cuts['daughter_pt_min']       = 600 * MeV #600 * MeV (2024) 750 * MeV (master)
+    make_d0tokpi_cuts['daughter_mipchi2_min']  = 9. #10. (2024) 10./9. (master e/taue)
+    make_d0tokpi_cuts['kaon_pid']              = (F.PID_K > 0.) #(F.PID_K > 0.) (2024) (F.PID_K > 4.) (master) 
+    make_d0tokpi_cuts['pion_pid']              = (F.PID_K < 2.)
+    return make_d0tokpi_cuts
+
+def get_electron_cuts():
+    #make loose cuts for electron and tauonic muon
+    make_electron_cuts = {}
+    make_electron_cuts["p_min"]           = 3. * GeV #3. * GeV (2024) 5. *GeV (master)
+    make_electron_cuts["pt_min"]          = 300. * MeV #300. * MeV (2024) 500. * MeV (master)
+    make_electron_cuts["mipchi2_min"]     = 9. #9. (2024) 9./16. (master e/taue) 
+    make_electron_cuts["mip_min"]         = None #0.
+    make_electron_cuts["pid"]             = (F.PID_E > 0.0) 
+    make_electron_cuts["make_particles"]  = make_long_electrons_with_brem  #does not require in calo
+    return make_electron_cuts
+
+def make_b():
+    make_d0tokpi_cuts = get_charm_cuts()
+    make_electron_cuts= get_electron_cuts()
+    pvs = make_pvs()
+    with make_candidate.bind(p_min=15. * GeV): 
+        dzs = make_d0_tokpi(**make_d0tokpi_cuts, name = CHARM_BUILDER_NAME)
+    electrons = make_candidate(**make_electron_cuts, name = "Electron_maker")
+
+    cut_vertex = F.require_all(F.CHI2DOF<9,F.BPVDIRA(pvs) >0.999,in_range(0 * MeV, F.MASS, 10000 * MeV))
+
+    rs_btodze  =  ParticleCombiner(
+        Inputs=[dzs, electrons],
+        name=f'rs_{B_BUILDER_NAME}_e',
+        DecayDescriptor='[B- -> D0 e-]cc',
+        CombinationCut=F.ALL,
+        CompositeCut=cut_vertex,
+        ParticleCombiner="ParticleVertexFitter")
+    ws_btodze  =  ParticleCombiner(
+        Inputs=[dzs, electrons],
+        name=f'ws_{B_BUILDER_NAME}_e',
+        DecayDescriptor='[B+ -> D0 e+]cc',
+        CombinationCut=F.ALL,
+        CompositeCut=cut_vertex,
+        ParticleCombiner="ParticleVertexFitter")
+    return ParticleContainersMerger([rs_btodze,ws_btodze], name = B_BUILDER_NAME)
+
+from Hlt2Conf.lines.semileptonic.hlt2_semileptonic import hlt2_butod0munu_d0tokpi_line,hlt2_butod0taunu_d0tokpi_tautomununu_line
+
+def make_lines_e():
+    def hlt2_lines(name=HLT2LINE,prescale=1):
+        Bcands = make_b()
+        return Hlt2Line(name=name, prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
+    lines = [hlt2_lines()]
+    return lines
+
+def make_lines_mu():
+   return [hlt2_butod0munu_d0tokpi_line()] 
+
+def make_lines_taumu():
+   return [hlt2_butod0taunu_d0tokpi_tautomununu_line()] 
+
+#ft decoding version 6 since MC made after 2019
+default_ft_decoding_version.global_bind(value=6)
+def SLB_BuToD0ENu_D0ToKPi(options: Options):
+  with reconstruction.bind(from_file=False):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+  return config
+
+def SLB_BuToD0MuNu_D0ToKPi(options: Options):
+  with reconstruction.bind(from_file=False):
+    config = run_moore(options, make_streams=make_lines_mu, public_tools=[stateProvider_with_simplified_geom()])
+    return config
+
+def SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
+  with reconstruction.bind(from_file=False):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+    return config
+
+def SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
+  with reconstruction.bind(from_file=False):
+    config = run_moore(options, make_streams=make_lines_taumu, public_tools=[stateProvider_with_simplified_geom()])
+    return config
diff --git a/SL_l_nu_D0toKpi_Run3_MC/info.yaml b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
new file mode 100644
index 0000000000..0982bfe288
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
@@ -0,0 +1,85 @@
+defaults:
+  inform:
+    - ching-hua.li@cern.ch
+  wg: SL
+
+{%- set evttype_lines_and_leptons = [
+  ('11584030','SLB_BuToD0ENu_D0ToKPi','e'),
+  ('11574020','SLB_BuToD0MuNu_D0ToKPi','muon'),
+  ('11584010','SLB_BuToD0TauNu_D0ToKPi_TauToENuNu','taue'),
+  ('11574010','SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu','taumuon'),
+] %}
+
+{%- set polarity_variables = [
+  ('MagDown','sim-20231017-vc-md100'),
+  ('MagUp','sim-20231017-vc-mu100'),
+]%}
+{%- for polarity, cond_tag in polarity_variables %}
+  {%- for evttype, line, lepton in evttype_lines_and_leptons %}
+HLT1_b0_dstp_{{lepton}}_{{ polarity }}:
+  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  input:
+    bk_query: "/MC/Dev/Beam6800GeV-expected-2024-{{polarity}}-Nu7.6-25ns-Pythia8/Sim10c/{{evttype}}/DIGI"
+    dq_flags:
+      - OK
+    n_test_lfns: 3 
+  output: hlt1.dst
+  options:
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC.Hlt1:main
+    extra_options:
+      input_raw_format: 0.3
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      output_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      scheduler_legacy_mode: False
+      compression:
+        algorithm: ZSTD
+        level: 1
+        max_buffer_size: 1048576
+      #evt_max: 1000
+
+HLT2_b0_dstp_{{lepton}}_{{ polarity }}:
+  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  input:
+    job_name: HLT1_b0_dstp_{{lepton}}_{{ polarity }}
+  output: hlt2.dst
+  options:
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC.Hlt2:{{line}}
+    extra_options:
+      input_raw_format: 0.5
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      output_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      scheduler_legacy_mode: False
+      output_manifest_file: "HLT2.tck.json" 
+      compression:
+        algorithm: ZSTD
+        level: 1
+        max_buffer_size: 1048576
+      #evt_max: 1000
+DV_b0_dstp_{{lepton}}_{{ polarity }}:
+  application: "DaVinci/v64r4@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  input:
+    job_name: HLT2_b0_dstp_{{lepton}}_{{ polarity }}
+  output: NTuple.root
+  options:
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC.DV:{{line}}
+    extra_options:
+      input_raw_format: 0.5
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      input_process: "Hlt2"
+      input_manifest_file: "HLT2.tck.json"
+      #evt_max: 1000
+
+  {%- endfor %}
+{%- endfor %}
-- 
GitLab


From 4ab068d7f8fe94ef6c5f333a46c61a8df0492c19 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Fri, 24 May 2024 10:42:53 +0200
Subject: [PATCH 31/57] remove SL_l_nu_D0toKpi_2024_data

---
 SL_l_nu_D0toKpi_2024_data/info.yaml  |  56 ----
 SL_l_nu_D0toKpi_2024_data/run_Dzl.py | 389 ---------------------------
 2 files changed, 445 deletions(-)
 delete mode 100644 SL_l_nu_D0toKpi_2024_data/info.yaml
 delete mode 100644 SL_l_nu_D0toKpi_2024_data/run_Dzl.py

diff --git a/SL_l_nu_D0toKpi_2024_data/info.yaml b/SL_l_nu_D0toKpi_2024_data/info.yaml
deleted file mode 100644
index 6800bd5c02..0000000000
--- a/SL_l_nu_D0toKpi_2024_data/info.yaml
+++ /dev/null
@@ -1,56 +0,0 @@
-checks:
-  hist:
-    type: range
-    expression: B0_Delta_M
-    limits:
-      min: 130
-      max: 200 
-    n_bins: 70 
-
-defaults:
-  inform:
-    - ching-hua.li@cern.ch
-  wg: SL
-
-{%- set lines_and_leptons = [
-  ('SpruceSLB_BuToD0ENu_D0ToKPi','e'),
-  ('SpruceSLB_BuToD0MuNu_D0ToKPi','muon'),
-  ('SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu','taue'),
-  ('SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu','taumuon'),
-  ('SpruceSLB_BuToD0ENu_D0ToKPi_FakeElectron','e_fake'),
-  ('SpruceSLB_BuToD0MuNu_D0ToKPi_FakeMuon','muon_fake'),
-  ('SpruceSLB_BuToD0TauNu_D0ToKPi_FakeElectron','taue_fake'),
-  ('SpruceSLB_BuToD0TauNu_D0ToKPi_FakeMuon','taumuon_fake'),
-] %}
-
-{%- set datasets = [
- ('2024Data', 'Down'),
-]%}
-{%- for evttype, polarity in datasets %}
-  {%- for spruce_line, leptons in lines_and_leptons %}
-b0_dstp_{{leptons}}_{{ evttype }}_{{ polarity }}:
-  application: "DaVinci/v64r4"
-  input:
-    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-Mag{{ polarity }}-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
-    dq_flags:
-      - UNCHECKED
-      - OK
-    keep_running: true
-    n_test_lfns: 1 
-  output: DATA.ROOT
-  options:
-    entrypoint: SL_l_nu_D0toKpi_2024_data.run_Dzl:{{spruce_line}}
-    extra_options:
-      input_raw_format: 0.5
-      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
-      simulation: False
-      #data_type: "Upgrade"
-      geometry_version: run3/2024.Q1.2-v00.00
-      conditions_version: master
-      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
-      input_stream: "sl" # for streamed data
-      #evt_max: 1000
-  checks:
-   - hist
-  {%- endfor %}
-{%- endfor %}
diff --git a/SL_l_nu_D0toKpi_2024_data/run_Dzl.py b/SL_l_nu_D0toKpi_2024_data/run_Dzl.py
deleted file mode 100644
index ed91b7a2a4..0000000000
--- a/SL_l_nu_D0toKpi_2024_data/run_Dzl.py
+++ /dev/null
@@ -1,389 +0,0 @@
-import sys,os,math
-from PyConf.reading import get_pvs, get_rec_summary, get_particles
-import Functors as F
-from FunTuple import FunctorCollection
-from FunTuple import FunTuple_Particles as Funtuple
-from DaVinci.algorithms import create_lines_filter
-from DaVinci import Options,make_config
-import FunTuple.functorcollections as FC
-from DaVinciMCTools import MCTruthAndBkgCat
-from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
-from Hlt2Conf.algorithms_thor import ParticleContainersMerger
-from Functors.grammar import Functor
-from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
-import numpy as np
-
-_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
-_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
-_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
-#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
-#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
-ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
-#MCNEUTRINO = F.FIND_MCDECAY("[ Lambda_b0 => Lambda_c+ mu- ^nu_mu~ ]CC")
-
-TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
-#MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(1, F.PARTICLE_ID)) == id)
-#GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(2, F.PARTICLE_ID)) == id)
-#GD_GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(3, F.PARTICLE_ID)) == id)
-
-def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
-	if do_truth_matching == True :
-		#filter B keeping only true D0 and true leptons
-		MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
-		Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
-		lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
-		Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
-		lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
-		cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
-		signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
-	else : signal_B = B
-
-	#combine to make [B*0 -> B*- pi+]cc
-	Bst_1 = ParticleCombiner(
-		Inputs=[B, pions],
-		name=f'Bst_1_{lepton}',
-		DecayDescriptor='[B0 -> B- pi+]cc',
-		CombinationCut=F.ALL,
-		CompositeCut=F.ALL,
-		ParticleCombiner="ParticleVertexFitter",
-		PrimaryVertices=v2_pvs
-		#OutputLevel=1
-	)
-	#combine to make [B*0 -> B*- pi-]cc
-	Bst_2 = ParticleCombiner(
-		Inputs=[B, pions],
-		name=f'Bst_2_{lepton}',
-		DecayDescriptor='[B0 -> B- pi-]cc',
-		CombinationCut=F.ALL,
-		CompositeCut=F.ALL,
-		ParticleCombiner="ParticleVertexFitter",
-		PrimaryVertices=v2_pvs
-		#OutputLevel=1
-	)
-	#merge the two Bst candidates
-	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
-	return Bst
-
-def get_functors(MCTRUTH, v2_pvs, rec_summary):
-	#define common variables for all fields (composite and basic)
-	vars_common  = FunctorCollection()
-	#all pvs: ip, ipchi2. The PV positions are stored in event variables
-	vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
-	vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
-	#best pv: x, y, z, ip, ipchi2
-	vars_common['BPV_X']          = F.BPVX(v2_pvs)
-	vars_common['BPV_Y']          = F.BPVY(v2_pvs)
-	vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
-	vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
-	vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
-	vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
-	vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
-	#particle id, key, truekey. The trueid is stored in MCHierarchy
-	vars_common['ID']            = F.PARTICLE_ID
-	vars_common['KEY']           = F.OBJECT_KEY
-
-	#get charge, min ip and min ipchi2
-	vars_common['CHARGE']        = F.CHARGE
-	vars_common['MINIP']         = F.MINIP(v2_pvs)
-	vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
-	#reco kinematics
-	vars_common += FC.Kinematics()
-	vars_common['ETA']           = F.ETA
-	vars_common['PHI']           = F.PHI
-	if MCTRUTH != 'None':
-		#mc vars
-		vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
-		vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
-		vars_common['TRUEETA'] = MCTRUTH(F.ETA)
-		vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
-		#type of the origin vertex
-		vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
-		##mc truth hierarchy (done seperately)
-		#vars_common += FC.MCHierarchy(mctruth_alg = MCTRUTH)
-		#make some helper functions
-		MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
-		MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
-		vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
-		vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
-		vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
-		vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
-		for i in range(2,14):
-		  prefix = "MC_GD_MOTHER_{}".format(i)
-		  vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
-		  vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
-
-	#variables for composite particles
-	vars_composite  = FunctorCollection()
-	#end vertex position and end vertex chi2
-	vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
-	vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
-	vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
-	#all pvs: dira, fd, fdchi2
-	vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
-	vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
-	vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
-	vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
-	vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
-	vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
-	vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
-	vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
-	#best pv: dira, fd, fdchi2, corrm, ltime, dls
-	vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
-	vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
-	vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
-	vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
-	vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
-	vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
-	#mc composite vertex information
-
-	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
-	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
-	# only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
-	# the DOCA/DOCACHI2 see below.
-	vars_composite['MAX_DOCA'] = F.MAXDOCA
-	vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
-	vars_composite['MAX_SDOCA'] = F.MAXSDOCA
-	vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
-
-	#variables for Lb field
-	var_B  = FunctorCollection()
-	#var_B['TRUENU_PX'] = MCTRUTH(F.PX @ MCNEUTRINO)
-	#var_B['TRUENU_PY'] = MCTRUTH(F.PY @ MCNEUTRINO)
-	#var_B['TRUENU_PZ'] = MCTRUTH(F.PZ @ MCNEUTRINO)
-	#var_B['TRUENU_ENERGY'] = MCTRUTH(F.ENERGY @ MCNEUTRINO)
-	###Bkg category
-	##var_B["BKGCAT"] = MCTRUTH.BkgCat
-
-	#variables for basics
-	vars_basic  = FunctorCollection()
-	vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
-	vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
-	vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
-	vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
-	vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
-	vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
-	vars_basic['GHOSTPROB'] = F.GHOSTPROB
-	vars_basic['PIDpi'] = F.PID_PI
-	vars_basic['PIDk']  = F.PID_K
-	vars_basic['PIDp']  = F.PID_P
-	vars_basic['PIDe']  = F.PID_E
-	vars_basic['PIDmu'] = F.PID_MU
-	vars_basic['PROBNNe'] = F.PROBNN_E
-	vars_basic['PROBNNpi'] = F.PROBNN_PI
-	vars_basic['PROBNNk'] = F.PROBNN_K
-	vars_basic['PROBNNmu'] = F.PROBNN_MU
-	vars_basic['PROBNNp'] = F.PROBNN_P
-	vars_basic['PROBNNghost'] = F.PROBNN_GHOST
-	if MCTRUTH != 'None':
-		vars_basic['TRUEORIGINVERTEX_X'] = MCTRUTH(F.ORIGIN_VX)
-		vars_basic['TRUEORIGINVERTEX_Y'] = MCTRUTH(F.ORIGIN_VY)
-		vars_basic['TRUEORIGINVERTEX_Z'] = MCTRUTH(F.ORIGIN_VZ)
-
-	#variables for event
-	evt_vars = FunctorCollection()
-	#evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
-	#evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
-	#evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
-	#evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
-	#evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
-	evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
-	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
-	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
-
-	vars_brems = FunctorCollection({})
-	vars_brems.update({"HASBREM": F.HASBREM})
-	#vars_brems.update({"HASBREMADDED": F.HASBREMADDED})
-	vars_brems.update({"BREMENERGY": F.BREMENERGY})
-	vars_brems.update({"BREMBENDCORR": F.BREMBENDCORR})
-	vars_brems.update({"BREMPIDE": F.BREMPIDE})
-	vars_brems.update({"ECALPIDE": F.ECALPIDE})
-	vars_brems.update({"ECALPIDMU": F.ECALPIDMU})
-	vars_brems.update({"HCALPIDE": F.HCALPIDE})
-	vars_brems.update({"HCALPIDMU": F.HCALPIDMU})
-	vars_brems.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
-	vars_brems.update({"ELECTRONSHOWERDLL": F.ELECTRONSHOWERDLL})
-	vars_brems.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2})
-	vars_brems.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2})
-	vars_brems.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2})
-	vars_brems.update({"ELECTRONENERGY": F.ELECTRONENERGY})
-	vars_brems.update({"BREMHYPOENERGY": F.BREMHYPOENERGY})
-	vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
-	#vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
-	vars_brems.update({"INBREM": F.INBREM})
-	vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
-	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
-
-	#return all functors
-	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars,vars_brems)
-	return functors
-
-def get_fitting_variable(v2_pvs,D0,lep):
-
-	B_dis = np.array([F.END_VX-F.BPVX(v2_pvs),F.END_VY-F.BPVY(v2_pvs),F.END_VZ-F.BPVZ(v2_pvs)])
-	B_dis_mag = F.SQRT @ (B_dis[0]**2+B_dis[1]**2+B_dis[2]**2)
-	B_Mod_P = F.ABS @ ((5279.65/F.MASS)*F.PZ/(B_dis[2]/B_dis_mag))
-	B_Mod_E = F.SQRT @ (B_Mod_P**2 + 5279.65**2)
-	B_4P = np.array([B_Mod_P*B_dis[0]/B_dis_mag,B_Mod_P*B_dis[1]/B_dis_mag,B_Mod_P*B_dis[2]/B_dis_mag,B_Mod_E])
-	D_4P = np.array([F.PX @ D0,F.PY @ D0,F.PZ @ D0,F.ENERGY @ D0])
-	lep_4P = np.array([F.PX @ lep,F.PY @ lep,F.PZ @ lep,F.ENERGY @ lep])
-
-	vars_fitting = FunctorCollection({})
-	vars_fitting["Mod_P"] = B_Mod_P
-	vars_fitting['missing_m2'] = (B_4P[3]-D_4P[3]-lep_4P[3])**2-(B_4P[0]-D_4P[0]-lep_4P[0])**2-(B_4P[1]-D_4P[1]-lep_4P[1])**2-(B_4P[2]-D_4P[2]-lep_4P[2])**2
-	vars_fitting['q2'] = (B_4P[3]-D_4P[3])**2-(B_4P[0]-D_4P[0])**2-(B_4P[1]-D_4P[1])**2-(B_4P[2]-D_4P[2])**2
-	B_Beta = B_Mod_P/B_Mod_E
-	B_gamma = 1/F.SQRT @ (1-B_Beta**2)
-
-	B_Lorentz = [[B_gamma,-1*B_gamma*B_4P[0]/B_4P[3],-1*B_gamma*B_4P[1]/B_4P[3],-1*B_gamma*B_4P[2]/B_4P[3]],[-1*B_gamma*B_4P[0]/B_4P[3],1+(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[0]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)],[-1*B_gamma*B_4P[1]/B_4P[3],(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)],[-1*B_gamma*B_4P[2]/B_4P[3],(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[2]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)]]
-	vars_fitting['lep_E_Brest'] = (B_Lorentz[0][0]*lep_4P[3]+B_Lorentz[0][1]*lep_4P[0]+B_Lorentz[0][2]*lep_4P[1]+B_Lorentz[0][3]*lep_4P[2])
-	return(vars_fitting)
-
-def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
-	#get functors
-	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
-	vars_common = functors[0]
-	vars_composite = functors[1]
-	var_B = functors[2]
-	vars_basic = functors[3]
-	evt_vars = functors[4]
-	vars_brems = functors[5]
-
-	#variables for Sb field
-	vars_Bst  = FunctorCollection()
-	B_child   = F.CHILD(1, F.FORWARDARG0)
-	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
-	Lep_child   = F.CHILD(1, F.CHILD(2,F.FORWARDARG0))
-	Epi_child = F.CHILD(2, F.FORWARDARG0)
-	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
-	#diff in vtx chi2 with and without extra particle
-	vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
-	#IP and IPChi2 of extra particle wrt to Sb end vertex
-	vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
-	vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
-	#IP and IPChi2 of extra particle wrt to Lb end vertex
-	vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
-	vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
-	#angle between extra particle and Lb
-	vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
-	#diff in fd chi2 with and without extra particle
-	vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
-	vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
-	#IP chi2 of extra particle wrt PV and SV of Sb
-	vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
-	vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
-	#IP chi2 of extra particle wrt PV and SV of Bb
-	vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
-	vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
-	#DOCA and DOCACHI2 b/w Lb and extra particle
-	vars_Bst['DOCA12']       = F.DOCA(1, 2)
-	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
-	#vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
-	#vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
-	#DOCACHI2 of extra particle wrt to mother i.e. Sb
-	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
-	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
-	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
-	#define fields
-	fit_vars = get_fitting_variable(v2_pvs,D0_child,Lep_child)
-
-
-	#define fields
-	fields = {}
-	fields['B0']    = f'[B0 ->  (B- ->  (D0 -> K- pi+)  [{lepton}-]CC)  [pi+]CC]CC'
-	fields['Bm']    = f'[B0 -> ^(B- ->  (D0 -> K- pi+)  [{lepton}-]CC)  [pi+]CC]CC'
-	fields['D0']    = f'[B0 ->  (B- -> ^(D0 -> K- pi+)  [{lepton}-]CC)  [pi+]CC]CC'
-	fields['Lep']   = f'[B0 ->  (B- ->  (D0 -> K- pi+) ^[{lepton}-]CC)  [pi+]CC]CC'
-	fields['Epi']   = f'[B0 ->  (B- ->  (D0 -> K- pi+)  [{lepton}-]CC) ^[pi+]CC]CC'
-	fields['Km']   = f'[B0 ->  (B- ->  (D0 -> ^K- pi+)  [{lepton}-]CC) [pi+]CC]CC'
-	fields['pip']   = f'[B0 ->  (B- ->  (D0 -> K- ^pi+)  [{lepton}-]CC) [pi+]CC]CC'
-
-	#add variables
-	variables = {}
-	variables["ALL"] = vars_common
-	variables["B0"]  = vars_composite + vars_Bst + fit_vars
-	variables["Bm"]  = vars_composite + var_B
-	variables["D0"]  = vars_composite
-	variables["Lep"] = vars_basic + vars_brems
-	variables["Epi"] = vars_basic + vars_brems
-	variables["Km"] = vars_basic + vars_brems
-	variables["pip"] = vars_basic + vars_brems
-
-	#define tuple
-	my_tuple = Funtuple(
-		name=f"Tuple",
-		tuple_name="DecayTree",
-		fields=fields,
-		variables=variables,
-		inputs=Bst)
-
-	return my_tuple
-
-def get_extra_pions():
-	"""
-	Note this function in DaVinci requires:
-	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
-	and it's related LHCb, DaVinci and Rec MRs
-	"""
-	long_pions = make_has_rich_long_pions()
-	up_pions = make_has_rich_up_pions()
-	down_pions = make_has_rich_down_pions()
-	return ParticleContainersMerger([long_pions, up_pions, down_pions],
-									name='Pions_combiner')
-
-#def main(options):
-def main(options: Options,line = '', lep=''):
-
-	#define filer
-	my_filter = create_lines_filter(name="Filter", lines=[line])
-
-	#get data and extra particles
-	lb = get_particles(f"/Event/Spruce/{line}/Particles")
-	extra_particles = get_extra_pions()
-
-	#get v2_pvs and rec_summary
-	v2_pvs  = get_pvs()
-	rec_summary = get_rec_summary()
-	hadron_candidate_id = 421
-	#make sb candidate
-	Bst = make_Bst(lb, extra_particles,lep,hadron_candidate_id,v2_pvs,False)
-	#MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
-
-
-	tuple_file = tuple_Bst(Bst,lep, 'None', v2_pvs, rec_summary)
-
-	#define algorithms
-	user_algorithms = {}
-	user_algorithms['Alg'] = [my_filter, tuple_file]
-
-	return make_config(options, user_algorithms)
-
-def SpruceSLB_BuToD0ENu_D0ToKPi(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0ENu_D0ToKPi',lep='e')
-
-def SpruceSLB_BuToD0MuNu_D0ToKPi(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu')
-
-def SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu',lep='e')
-
-def SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu')
-
-def SpruceSLB_BuToD0ENu_D0ToKPi_FakeElectron(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0ENu_D0ToKPi_FakeElectron',lep='e')
-
-def SpruceSLB_BuToD0MuNu_D0ToKPi_FakeMuon(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi_FakeMuon',lep='mu')
-
-def SpruceSLB_BuToD0TauNu_D0ToKPi_FakeElectron(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_FakeElectron',lep='e')
-
-def SpruceSLB_BuToD0TauNu_D0ToKPi_FakeMuon(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_FakeMuon',lep='mu')
-
-- 
GitLab


From 5951888c2ec0a3892dd2aa08f378131f0711fd94 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 27 May 2024 12:08:47 +0200
Subject: [PATCH 32/57] Remove ft decoding version. Add spruce, totCandidate
 vars, BKGcat, isolation mva and delta D* mass pre-cut

---
 SL_l_nu_D0toKpi_Run3_MC/DV.py     | 49 ++++++++++------------
 SL_l_nu_D0toKpi_Run3_MC/Hlt2.py   |  2 -
 SL_l_nu_D0toKpi_Run3_MC/Spruce.py | 70 +++++++++++++++++++++++++++++++
 SL_l_nu_D0toKpi_Run3_MC/info.yaml | 34 ++++++++++++---
 4 files changed, 120 insertions(+), 35 deletions(-)
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC/Spruce.py

diff --git a/SL_l_nu_D0toKpi_Run3_MC/DV.py b/SL_l_nu_D0toKpi_Run3_MC/DV.py
index 04f1272761..11d4c83109 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC/DV.py
@@ -12,6 +12,7 @@ from Hlt2Conf.algorithms_thor import ParticleContainersMerger
 from Functors.grammar import Functor
 from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
 import numpy as np
+from Hlt2Conf.lines.semileptonic.isolationMVA import mva_functor_e_inclusive,mva_functor_mu_inclusive
 
 _BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
 _allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
@@ -25,12 +26,8 @@ ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORW
 ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
 ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
 ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
-#MCNEUTRINO = F.FIND_MCDECAY("[ Lambda_b0 => Lambda_c+ mu- ^nu_mu~ ]CC")
 
 TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
-#MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(1, F.PARTICLE_ID)) == id)
-#GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(2, F.PARTICLE_ID)) == id)
-#GD_GD_MCMOTHER_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.MC_MOTHER(3, F.PARTICLE_ID)) == id)
 
 def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
 	if do_truth_matching == True :
@@ -44,12 +41,17 @@ def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = Tru
 		signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
 	else : signal_B = B
 
+	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
+	Epi_child = F.CHILD(2, F.FORWARDARG0)
+	#D* mass - D0 mass cut
+	cut_combine = F.require_all(((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))<200)
+
 	#combine to make [B*0 -> B*- pi+]cc
 	Bst_1 = ParticleCombiner(
 		Inputs=[B, pions],
 		name=f'Bst_1_{lepton}',
 		DecayDescriptor='[B0 -> B- pi+]cc',
-		CombinationCut=F.ALL,
+		CombinationCut=cut_combine,
 		CompositeCut=F.ALL,
 		ParticleCombiner="ParticleVertexFitter",
 		PrimaryVertices=v2_pvs
@@ -60,7 +62,7 @@ def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = Tru
 		Inputs=[B, pions],
 		name=f'Bst_2_{lepton}',
 		DecayDescriptor='[B0 -> B- pi-]cc',
-		CombinationCut=F.ALL,
+		CombinationCut=cut_combine,
 		CompositeCut=F.ALL,
 		ParticleCombiner="ParticleVertexFitter",
 		PrimaryVertices=v2_pvs
@@ -98,14 +100,13 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	vars_common['PHI']           = F.PHI
 	if MCTRUTH != 'None':
 		#mc vars
+		vars_common['BKGCAT'] = MCTRUTH.BkgCat
 		vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
 		vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
 		vars_common['TRUEETA'] = MCTRUTH(F.ETA)
 		vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
 		#type of the origin vertex
 		vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
-		##mc truth hierarchy (done seperately)
-		#vars_common += FC.MCHierarchy(mctruth_alg = MCTRUTH)
 		#make some helper functions
 		MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
 		MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
@@ -151,15 +152,6 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	vars_composite['MAX_SDOCA'] = F.MAXSDOCA
 	vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
 
-	#variables for Lb field
-	var_B  = FunctorCollection()
-	#var_B['TRUENU_PX'] = MCTRUTH(F.PX @ MCNEUTRINO)
-	#var_B['TRUENU_PY'] = MCTRUTH(F.PY @ MCNEUTRINO)
-	#var_B['TRUENU_PZ'] = MCTRUTH(F.PZ @ MCNEUTRINO)
-	#var_B['TRUENU_ENERGY'] = MCTRUTH(F.ENERGY @ MCNEUTRINO)
-	###Bkg category
-	##var_B["BKGCAT"] = MCTRUTH.BkgCat
-
 	#variables for basics
 	vars_basic  = FunctorCollection()
 	vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
@@ -220,7 +212,7 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
 
 	#return all functors
-	functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars,vars_brems)
+	functors = (vars_common, vars_composite, vars_basic, evt_vars,vars_brems)
 	return functors
 
 def get_fitting_variable(v2_pvs,D0,lep):
@@ -249,10 +241,9 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
 	vars_common = functors[0]
 	vars_composite = functors[1]
-	var_B = functors[2]
-	vars_basic = functors[3]
-	evt_vars = functors[4]
-	vars_brems = functors[5]
+	vars_basic = functors[2]
+	evt_vars = functors[3]
+	vars_brems = functors[4]
 
 	#variables for Sb field
 	vars_Bst  = FunctorCollection()
@@ -289,6 +280,7 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
 	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
 	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
+	vars_Bst['iso_mva'] = mva_functor_e_inclusive(v2_pvs)[0] if lepton == 'e' else mva_functor_mu_inclusive(v2_pvs)[0]
 	#define fields
 	fit_vars = get_fitting_variable(v2_pvs,D0_child,Lep_child)
 
@@ -307,7 +299,7 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	variables = {}
 	variables["ALL"] = vars_common
 	variables["B0"]  = vars_composite + vars_Bst + fit_vars
-	variables["Bm"]  = vars_composite + var_B
+	variables["Bm"]  = vars_composite
 	variables["D0"]  = vars_composite
 	variables["Lep"] = vars_basic + vars_brems
 	variables["Epi"] = vars_basic + vars_brems
@@ -320,6 +312,7 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 		tuple_name="DecayTree",
 		fields=fields,
 		variables=variables,
+        store_multiple_cand_info=True,
 		inputs=Bst)
 
 	return my_tuple
@@ -343,7 +336,7 @@ def main(options: Options,line = '', lep=''):
 	my_filter = create_lines_filter(name="Filter", lines=[line])
 
 	#get data and extra particles
-	lb = get_particles(f"/Event/HLT2/{line}/Particles")
+	lb = get_particles(f"/Event/Spruce/{line}/Particles")
 	extra_particles = get_extra_pions()
 
 	#get v2_pvs and rec_summary
@@ -364,14 +357,14 @@ def main(options: Options,line = '', lep=''):
 	return make_config(options, user_algorithms)
 
 def SLB_BuToD0ENu_D0ToKPi(options: Options):
-	return main(options=options, line='Hlt2SLB_BToDzl',lep='e')
+	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
 
 def SLB_BuToD0MuNu_D0ToKPi(options: Options):
-	return main(options=options, line='Hlt2SLB_BuToD0MuNu_D0ToKPi',lep='mu')
+	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu')
 
 def SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
-	return main(options=options, line='Hlt2SLB_BToDzl',lep='e')
+	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
 
 def SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
-	return main(options=options, line='Hlt2SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu')
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu')
 
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py b/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
index e0d48da235..c7133e1dac 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
+++ b/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
@@ -106,8 +106,6 @@ def make_lines_mu():
 def make_lines_taumu():
    return [hlt2_butod0taunu_d0tokpi_tautomununu_line()] 
 
-#ft decoding version 6 since MC made after 2019
-default_ft_decoding_version.global_bind(value=6)
 def SLB_BuToD0ENu_D0ToKPi(options: Options):
   with reconstruction.bind(from_file=False):
     config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Spruce.py b/SL_l_nu_D0toKpi_Run3_MC/Spruce.py
new file mode 100644
index 0000000000..7a10321fb5
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC/Spruce.py
@@ -0,0 +1,70 @@
+###############################################################################
+# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+#Example follows from hlt2_with_hlt1_decision.py
+from Moore import Options,options, run_moore, config
+from Hlt2Conf.lines.semileptonic.builders import sl_line_prefilter
+from Moore.config import SpruceLine
+from .Hlt2 import make_b
+from PyConf.application import configure_input, configure, default_raw_event
+from RecoConf.global_tools import stateProvider_with_simplified_geom
+from RecoConf.reconstruction_objects import reconstruction
+from RecoConf.decoders import default_ft_decoding_version
+from RecoConf.hlt2_global_reco import reconstruction as hlt2_reconstruction, make_fastest_reconstruction
+from Hlt2Conf.lines.semileptonic.spruce_semileptonic import spruce_butod0munu_d0tokpi_line,spruce_butod0taunu_d0tokpi_tautomununu_line
+from Hlt2Conf.lines.semileptonic.HbToHcTauNu_TauToLNuNu import make_butod0taunu_d0tokpi_tautolnunu
+from Hlt2Conf.lines.semileptonic.HbToHcLNu import make_butod0lnu_d0tokpi
+
+def make_lines_e():
+    def spruce_lines(name='SpruceSLB_BToDzl',prescale=1):
+        Bcands = make_b()
+        return SpruceLine(name=name,  hlt2_filter_code=[
+        f"{name.replace('Spruce','Hlt2')}Decision",
+        "Hlt2Topo2BodyDecision", "Hlt2Topo3BodyDecision"]
+        ,prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
+    return [spruce_lines()]
+
+def make_lines_taumu():
+    def spruce_lines(name='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',prescale=1):
+        line_alg = make_butod0taunu_d0tokpi_tautolnunu(process='spruce', lepton="mu")
+        return SpruceLine(name=name,  hlt2_filter_code=[
+        f"{name.replace('Spruce','Hlt2')}Decision",
+        "Hlt2Topo2BodyDecision", "Hlt2Topo3BodyDecision"]
+        ,prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [line_alg])
+    return [spruce_lines()]
+
+def make_lines_mu():
+    def spruce_lines(name="SpruceSLB_BuToD0MuNu_D0ToKPi",prescale=1):
+        line_alg = make_butod0lnu_d0tokpi(process='spruce', lepton="mu")
+        return SpruceLine(name=name,  hlt2_filter_code=[
+        f"{name.replace('Spruce','Hlt2')}Decision",
+        "Hlt2Topo2BodyDecision", "Hlt2Topo3BodyDecision"]
+        ,prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [line_alg])
+    return [spruce_lines()]
+
+def SLB_BuToD0ENu_D0ToKPi(options: Options):
+  with reconstruction.bind(from_file=True, spruce=True):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+    return config
+
+def SLB_BuToD0MuNu_D0ToKPi(options: Options):
+  with reconstruction.bind(from_file=True, spruce=True):
+    config = run_moore(options, make_streams=make_lines_mu, public_tools=[stateProvider_with_simplified_geom()])
+    return config
+
+def SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
+  with reconstruction.bind(from_file=True, spruce=True):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+    return config
+
+def SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
+  with reconstruction.bind(from_file=True, spruce=True):
+    config = run_moore(options, make_streams=make_lines_taumu, public_tools=[stateProvider_with_simplified_geom()])
+    return config
diff --git a/SL_l_nu_D0toKpi_Run3_MC/info.yaml b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
index 0982bfe288..4cff9509f0 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/info.yaml
+++ b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
@@ -22,7 +22,7 @@ HLT1_b0_dstp_{{lepton}}_{{ polarity }}:
     bk_query: "/MC/Dev/Beam6800GeV-expected-2024-{{polarity}}-Nu7.6-25ns-Pythia8/Sim10c/{{evttype}}/DIGI"
     dq_flags:
       - OK
-    n_test_lfns: 3 
+    n_test_lfns: 2
   output: hlt1.dst
   options:
     entrypoint: SL_l_nu_D0toKpi_Run3_MC.Hlt1:main
@@ -63,22 +63,46 @@ HLT2_b0_dstp_{{lepton}}_{{ polarity }}:
         level: 1
         max_buffer_size: 1048576
       #evt_max: 1000
-DV_b0_dstp_{{lepton}}_{{ polarity }}:
-  application: "DaVinci/v64r4@x86_64_v3-el9-gcc13+detdesc-opt+g"
+SPRUCE_b0_dstp_{{lepton}}_{{ polarity }}:
+  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     job_name: HLT2_b0_dstp_{{lepton}}_{{ polarity }}
-  output: NTuple.root
+  output: spruce.dst
   options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC.DV:{{line}}
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC.Spruce:{{line}}
     extra_options:
       input_raw_format: 0.5
       conddb_tag: {{cond_tag}}
       dddb_tag: dddb-20231017
       input_type: ROOT
+      output_type: ROOT
       simulation: True
       data_type: "Upgrade"
+      scheduler_legacy_mode: False
       input_process: "Hlt2"
       input_manifest_file: "HLT2.tck.json"
+      output_manifest_file: "SPRUCE.tck.json" 
+      compression:
+        algorithm: ZSTD
+        level: 1
+        max_buffer_size: 1048576
+      #evt_max: 1000
+DV_b0_dstp_{{lepton}}_{{ polarity }}:
+  application: "DaVinci/v64r5@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  input:
+    job_name: SPRUCE_b0_dstp_{{lepton}}_{{ polarity }}
+  output: NTuple.root
+  options:
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC.DV:{{line}}
+    extra_options:
+      input_raw_format: 0.5
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      input_process: "Spruce"
+      input_manifest_file: "SPRUCE.tck.json"
       #evt_max: 1000
 
   {%- endfor %}
-- 
GitLab


From 9bb431a5a86d05bf6a96a67337b4843d08c53100 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Thu, 30 May 2024 15:13:26 +0200
Subject: [PATCH 33/57] Add variables and new MC sample

---
 SL_l_nu_D0toKpi_Run3_MC/DV.py         | 116 ++++++++++++++++++--------
 SL_l_nu_D0toKpi_Run3_MC/Hlt2.py       |  20 +++++
 SL_l_nu_D0toKpi_Run3_MC/MC_Matcher.py |  26 ++++++
 SL_l_nu_D0toKpi_Run3_MC/Spruce.py     |  36 ++++----
 SL_l_nu_D0toKpi_Run3_MC/info.yaml     |  34 ++++----
 5 files changed, 168 insertions(+), 64 deletions(-)
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC/MC_Matcher.py

diff --git a/SL_l_nu_D0toKpi_Run3_MC/DV.py b/SL_l_nu_D0toKpi_Run3_MC/DV.py
index 11d4c83109..19a333dfa6 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC/DV.py
@@ -13,12 +13,13 @@ from Functors.grammar import Functor
 from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
 import numpy as np
 from Hlt2Conf.lines.semileptonic.isolationMVA import mva_functor_e_inclusive,mva_functor_mu_inclusive
+from .MC_Matcher import trail_seeker
 
 _BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
 _allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
 _allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
-#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
-#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
+ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
+ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
 ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
 ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
 ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
@@ -43,6 +44,7 @@ def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = Tru
 
 	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
 	Epi_child = F.CHILD(2, F.FORWARDARG0)
+
 	#D* mass - D0 mass cut
 	cut_combine = F.require_all(((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))<200)
 
@@ -72,7 +74,7 @@ def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = Tru
 	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
 	return Bst
 
-def get_functors(MCTRUTH, v2_pvs, rec_summary):
+def get_functors(MCTRUTH, v2_pvs, rec_summary,line):
 	#define common variables for all fields (composite and basic)
 	vars_common  = FunctorCollection()
 	#all pvs: ip, ipchi2. The PV positions are stored in event variables
@@ -141,8 +143,8 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
 	vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
 	vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
-	#mc composite vertex information
 
+	#mc composite vertex information
 	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
 	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
 	# only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
@@ -161,6 +163,12 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
 	vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
 	vars_basic['GHOSTPROB'] = F.GHOSTPROB
+	vars_basic['NHITS'] = F.VALUE_OR(-1) @F.NHITS @ F.TRACK
+	vars_basic['NUTHITS'] = F.VALUE_OR(-1) @F.NUTHITS @ F.TRACK
+	vars_basic['NVPHITS'] = F.VALUE_OR(-1) @F.NVPHITS @ F.TRACK
+	vars_basic['NFTHITS'] = F.VALUE_OR(-1) @ F.NFTHITS @ F.TRACK
+	vars_basic['TRACKHASUT'] = F.VALUE_OR(-1) @ F.TRACKHASUT @ F.TRACK
+	vars_basic['TRACKHASVELO'] = F.VALUE_OR(-1) @ F.TRACKHASVELO @ F.TRACK
 	vars_basic['PIDpi'] = F.PID_PI
 	vars_basic['PIDk']  = F.PID_K
 	vars_basic['PIDp']  = F.PID_P
@@ -172,21 +180,23 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	vars_basic['PROBNNmu'] = F.PROBNN_MU
 	vars_basic['PROBNNp'] = F.PROBNN_P
 	vars_basic['PROBNNghost'] = F.PROBNN_GHOST
-	if MCTRUTH != 'None':
-		vars_basic['TRUEORIGINVERTEX_X'] = MCTRUTH(F.ORIGIN_VX)
-		vars_basic['TRUEORIGINVERTEX_Y'] = MCTRUTH(F.ORIGIN_VY)
-		vars_basic['TRUEORIGINVERTEX_Z'] = MCTRUTH(F.ORIGIN_VZ)
+	if MCTRUTH != 'None': vars_basic += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
 
 	#variables for event
-	evt_vars = FunctorCollection()
-	#evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
-	#evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
-	#evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
-	#evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
-	#evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
-	evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
-	evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
-	evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
+	#Collection includes tis_tos, nPVs,nHits/clusters,BUNCHCROSSING and GPS var
+	evt_collections = [
+		FC.EventInfo(),
+		FC.SelectionInfo(selection_type="Hlt2", trigger_lines=[line.replace("Spruce","HLT2")]),
+		FC.RecSummary(),
+	]
+	evt_vars = FunctorCollection({})
+	evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
+	evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
+	evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
+	evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
+	evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
+
+	for coll in evt_collections:evt_vars += coll
 
 	vars_brems = FunctorCollection({})
 	vars_brems.update({"HASBREM": F.HASBREM})
@@ -208,6 +218,7 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
 	#vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
 	vars_brems.update({"INBREM": F.INBREM})
+	vars_brems.update({"INECAL": F.INECAL})
 	vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
 	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
 
@@ -236,9 +247,9 @@ def get_fitting_variable(v2_pvs,D0,lep):
 	vars_fitting['lep_E_Brest'] = (B_Lorentz[0][0]*lep_4P[3]+B_Lorentz[0][1]*lep_4P[0]+B_Lorentz[0][2]*lep_4P[1]+B_Lorentz[0][3]*lep_4P[2])
 	return(vars_fitting)
 
-def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
+def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
 	#get functors
-	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
+	functors = get_functors(MCTRUTH, v2_pvs, rec_summary,line)
 	vars_common = functors[0]
 	vars_composite = functors[1]
 	vars_basic = functors[2]
@@ -254,23 +265,23 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
 	#diff in vtx chi2 with and without extra particle
 	vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
-	#IP and IPChi2 of extra particle wrt to Sb end vertex
-	vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
-	vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
-	#IP and IPChi2 of extra particle wrt to Lb end vertex
-	vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+	#IP and IPChi2 of extra particle wrt to B0 end vertex
+	vars_Bst['Epi_IP_WRT_B0ENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_B0ENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+	#IP and IPChi2 of extra particle wrt to Bm end vertex
+	vars_Bst['Epi_IP_WRT_BmENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
 	vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
-	#angle between extra particle and Lb
-	vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+	#angle between extra particle and Bm
+	vars_Bst['Epi_COSANGLE_Bm']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
 	#diff in fd chi2 with and without extra particle
 	vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
 	vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
-	#IP chi2 of extra particle wrt PV and SV of Sb
-	vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
-	vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
-	#IP chi2 of extra particle wrt PV and SV of Bb
-	vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
-	vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+	#IP chi2 of extra particle wrt PV and SV of B0
+	vars_Bst['Epi_IP_WRT_B0BPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_B0BPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+	#IP chi2 of extra particle wrt PV and SV of Bm
+	vars_Bst['Epi_IP_WRT_BmBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+	vars_Bst['Epi_IPCHI2_WRT_BmBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
 	#DOCA and DOCACHI2 b/w Lb and extra particle
 	vars_Bst['DOCA12']       = F.DOCA(1, 2)
 	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
@@ -281,9 +292,28 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
 	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
 	vars_Bst['iso_mva'] = mva_functor_e_inclusive(v2_pvs)[0] if lepton == 'e' else mva_functor_mu_inclusive(v2_pvs)[0]
+	vars_Bst += trail_seeker(MCTRUTH)
+
+
 	#define fields
 	fit_vars = get_fitting_variable(v2_pvs,D0_child,Lep_child)
-
+	#TIS and TOS
+	Hlt1_decisions = ['Hlt1TrackMVA',
+	'Hlt1TwoTrackMVA',
+	'Hlt1D2KK',
+	'Hlt1D2KPi',
+	'Hlt1D2PiPi',
+	'Hlt1KsToPiPi',
+	'Hlt1TrackMuonMVA',
+	'Hlt1SingleHighPtMuon',
+	'Hlt1TrackElectronMVA',
+	'Hlt1SingleHighPtElectron',
+	'Hlt1DiElectronDisplaced',
+	'Hlt1DiPhotonHighMass',
+	'Hlt1Pi02GammaGamma',
+	'Hlt1DiElectronHighMass_SS',
+	'Hlt1DiElectronHighMass']
+	variables_tistos = FC.HltTisTos(selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=Bst)
 
 	#define fields
 	fields = {}
@@ -298,7 +328,7 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 	#add variables
 	variables = {}
 	variables["ALL"] = vars_common
-	variables["B0"]  = vars_composite + vars_Bst + fit_vars
+	variables["B0"]  = vars_composite + vars_Bst + fit_vars + variables_tistos
 	variables["Bm"]  = vars_composite
 	variables["D0"]  = vars_composite
 	variables["Lep"] = vars_basic + vars_brems
@@ -312,6 +342,7 @@ def tuple_Bst(Bst,lepton, MCTRUTH, v2_pvs, rec_summary):
 		tuple_name="DecayTree",
 		fields=fields,
 		variables=variables,
+		event_variables=evt_vars,
         store_multiple_cand_info=True,
 		inputs=Bst)
 
@@ -348,7 +379,7 @@ def main(options: Options,line = '', lep=''):
 	MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
 
 
-	tuple_file = tuple_Bst(Bst,lep, MCTRUTH_Bst, v2_pvs, rec_summary)
+	tuple_file = tuple_Bst(Bst,lep,line, MCTRUTH_Bst, v2_pvs, rec_summary)
 
 	#define algorithms
 	user_algorithms = {}
@@ -356,15 +387,30 @@ def main(options: Options,line = '', lep=''):
 
 	return make_config(options, user_algorithms)
 
+def test(options: Options):
+	return main(options=options, line='Hlt2_Test_line',lep='e')
+
 def SLB_BuToD0ENu_D0ToKPi(options: Options):
 	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
 
+def SLB_BuToDststENu(options: Options):
+	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
+
+def SLB_BdToDststENu(options: Options):
+	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
+
 def SLB_BuToD0MuNu_D0ToKPi(options: Options):
 	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu')
 
 def SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
 	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
 
+def SLB_BuToDststTauNu_TauToENuNu(options: Options):
+	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
+
+def SLB_BdToDststTauNu_TauToENuNu(options: Options):
+	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
+
 def SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
 	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu')
 
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py b/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
index c7133e1dac..8361952e5f 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
+++ b/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
@@ -111,6 +111,16 @@ def SLB_BuToD0ENu_D0ToKPi(options: Options):
     config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
   return config
 
+def SLB_BuToDststENu(options: Options):
+  with reconstruction.bind(from_file=False):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+  return config
+
+def SLB_BdToDststENu(options: Options):
+  with reconstruction.bind(from_file=False):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+  return config
+
 def SLB_BuToD0MuNu_D0ToKPi(options: Options):
   with reconstruction.bind(from_file=False):
     config = run_moore(options, make_streams=make_lines_mu, public_tools=[stateProvider_with_simplified_geom()])
@@ -121,6 +131,16 @@ def SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
     config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
     return config
 
+def SLB_BuToDststTauNu_TauToENuNu(options: Options):
+  with reconstruction.bind(from_file=False):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+    return config
+
+def SLB_BdToDststTauNu_TauToENuNu(options: Options):
+  with reconstruction.bind(from_file=False):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+    return config
+
 def SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
   with reconstruction.bind(from_file=False):
     config = run_moore(options, make_streams=make_lines_taumu, public_tools=[stateProvider_with_simplified_geom()])
diff --git a/SL_l_nu_D0toKpi_Run3_MC/MC_Matcher.py b/SL_l_nu_D0toKpi_Run3_MC/MC_Matcher.py
new file mode 100644
index 0000000000..e3b279805b
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC/MC_Matcher.py
@@ -0,0 +1,26 @@
+from FunTuple import FunctorCollection
+import Functors as F
+def trail_seeker(MCTRUTH):
+	mcMatch = lambda decay_descriptor: (F.HAS_VALUE @ MCTRUTH(F.FIND_MCDECAY(decay_descriptor)))
+	mcMatch_both = lambda decay_descriptor1,decay_descriptor2: (F.HAS_VALUE @ MCTRUTH(F.FIND_MCDECAY(decay_descriptor1))+F.HAS_VALUE @ MCTRUTH(F.FIND_MCDECAY(decay_descriptor2)))
+	
+	variables = FunctorCollection({
+		'IS_Dtaunu':mcMatch_both("[B0 -> D*(2010)- tau+ nu_tau]CC","[B~0 -> D*(2010)- tau+ nu_tau]CC"),
+		'IS_Denu':mcMatch_both("[B0 -> D*(2010)- e+ nu_e]CC","[B~0 -> D*(2010)- e+ nu_e]CC"),	
+		'IS_Dstar_2460enu':mcMatch_both("[B0 -> D*(2640)- e+ nu_e]CC","[B~0 -> D*(2640)- e+ nu_e]CC"),
+		'IS_D_2Senu':mcMatch_both("[B0 -> D(2S)- e+ nu_e]CC","[B~0 -> D(2S)- e+ nu_e]CC"),
+		'IS_Dstar_2460_2enu':mcMatch_both("[B0 -> D*_2(2460)- e+ nu_e]CC","[B~0 -> D*_2(2460)- e+ nu_e]CC"),
+		'IS_D_2460_1enu':mcMatch_both("[B0 -> D_1(2420)- e+ nu_e]CC","[B~0 -> D_1(2420)- e+ nu_e]CC"),
+		'IS_Dstar_0taunu':mcMatch_both("[B0 -> D*_0- tau+ nu_tau]CC","[B~0 -> D*_0- tau+ nu_tau]CC"),
+		'IS_D_H_1taunu':mcMatch_both("[B0 -> D_1(H)- tau+ nu_tau]CC","[B~0 -> D_1(H)- tau+ nu_tau]CC"),
+		'IS_D_2420_1taunu':mcMatch_both("[B0 -> D_1(2420)- tau+ nu_tau]CC","[B~0 -> D_1(2420)- tau+ nu_tau]CC"),
+		'IS_Dstar_2460_2taunu':mcMatch_both("[B0 -> D*_2(2460)- tau+ nu_tau]CC","[B~0 -> D*_2(2460)- tau+ nu_tau]CC"),
+		'IS_Dstar0_2640enu':mcMatch("[B- -> D*(2640)0 e- nu_e~]CC"),	
+		'IS_D0_2Senu':mcMatch("[B- -> D(2S)0 e- nu_e~]CC"),	
+		'IS_Dstar0_2460_2enu':mcMatch("[B- -> D*_2(2460)0 e- nu_e~]CC"),	
+		'IS_D0_2460_1enu':mcMatch("[B- -> D_1(2420)0 e- nu_e~]CC"),	
+		'IS_D0_H_1taunu':mcMatch("[B- -> D_1(H)0 tau- nu_tau~]CC"),	
+		'IS_D0_2420_1taunu':mcMatch("[B- -> D_1(2420)0 tau- nu_tau~]CC"),	
+		'IS_Dstar0_2460_2taunu':mcMatch("[B- -> D*_2(2460)0 tau- nu_tau~]CC"),	
+		})
+	return(variables)
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Spruce.py b/SL_l_nu_D0toKpi_Run3_MC/Spruce.py
index 7a10321fb5..8e11e66a60 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/Spruce.py
+++ b/SL_l_nu_D0toKpi_Run3_MC/Spruce.py
@@ -32,28 +32,26 @@ def make_lines_e():
     return [spruce_lines()]
 
 def make_lines_taumu():
-    def spruce_lines(name='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',prescale=1):
-        line_alg = make_butod0taunu_d0tokpi_tautolnunu(process='spruce', lepton="mu")
-        return SpruceLine(name=name,  hlt2_filter_code=[
-        f"{name.replace('Spruce','Hlt2')}Decision",
-        "Hlt2Topo2BodyDecision", "Hlt2Topo3BodyDecision"]
-        ,prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [line_alg])
-    return [spruce_lines()]
+    return [spruce_butod0taunu_d0tokpi_tautomununu_line()]
 
 def make_lines_mu():
-    def spruce_lines(name="SpruceSLB_BuToD0MuNu_D0ToKPi",prescale=1):
-        line_alg = make_butod0lnu_d0tokpi(process='spruce', lepton="mu")
-        return SpruceLine(name=name,  hlt2_filter_code=[
-        f"{name.replace('Spruce','Hlt2')}Decision",
-        "Hlt2Topo2BodyDecision", "Hlt2Topo3BodyDecision"]
-        ,prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [line_alg])
-    return [spruce_lines()]
+    return [spruce_butod0munu_d0tokpi_line()]
 
 def SLB_BuToD0ENu_D0ToKPi(options: Options):
   with reconstruction.bind(from_file=True, spruce=True):
     config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
     return config
 
+def SLB_BuToDststENu(options: Options):
+  with reconstruction.bind(from_file=True, spruce=True):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+    return config
+
+def SLB_BdToDststENu(options: Options):
+  with reconstruction.bind(from_file=True, spruce=True):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+    return config
+
 def SLB_BuToD0MuNu_D0ToKPi(options: Options):
   with reconstruction.bind(from_file=True, spruce=True):
     config = run_moore(options, make_streams=make_lines_mu, public_tools=[stateProvider_with_simplified_geom()])
@@ -64,6 +62,16 @@ def SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
     config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
     return config
 
+def SLB_BuToDststTauNu_TauToENuNu(options: Options):
+  with reconstruction.bind(from_file=True, spruce=True):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+    return config
+
+def SLB_BdToDststTauNu_TauToENuNu(options: Options):
+  with reconstruction.bind(from_file=True, spruce=True):
+    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
+    return config
+
 def SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
   with reconstruction.bind(from_file=True, spruce=True):
     config = run_moore(options, make_streams=make_lines_taumu, public_tools=[stateProvider_with_simplified_geom()])
diff --git a/SL_l_nu_D0toKpi_Run3_MC/info.yaml b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
index 4cff9509f0..8d3007e1f6 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/info.yaml
+++ b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
@@ -4,10 +4,14 @@ defaults:
   wg: SL
 
 {%- set evttype_lines_and_leptons = [
-  ('11584030','SLB_BuToD0ENu_D0ToKPi','e'),
-  ('11574020','SLB_BuToD0MuNu_D0ToKPi','muon'),
-  ('11584010','SLB_BuToD0TauNu_D0ToKPi_TauToENuNu','taue'),
-  ('11574010','SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu','taumuon'),
+  ('11584030','SLB_BuToD0ENu_D0ToKPi','b0_dstp_e'),
+  ('11574020','SLB_BuToD0MuNu_D0ToKPi','b0_dstp_muon'),
+  ('11584010','SLB_BuToD0TauNu_D0ToKPi_TauToENuNu','b0_dstp_taue'),
+  ('11574010','SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu','b0_dstp_taumuon'),
+  ('12685400','SLB_BuToDststENu','bp_dstst_e'),
+  ('12883000','SLB_BuToDststTauNu_TauToENuNu','bp_dstst_taue'),
+  ('11686000','SLB_BdToDststENu','b0_dststp_e'),
+  ('11883000','SLB_BdToDststTauNu_TauToENuNu','b0_dststp_taue'),
 ] %}
 
 {%- set polarity_variables = [
@@ -15,9 +19,9 @@ defaults:
   ('MagUp','sim-20231017-vc-mu100'),
 ]%}
 {%- for polarity, cond_tag in polarity_variables %}
-  {%- for evttype, line, lepton in evttype_lines_and_leptons %}
-HLT1_b0_dstp_{{lepton}}_{{ polarity }}:
-  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  {%- for evttype, line, dk in evttype_lines_and_leptons %}
+HLT1_{{dk}}_{{ polarity }}:
+  application: "Moore/v55r7@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     bk_query: "/MC/Dev/Beam6800GeV-expected-2024-{{polarity}}-Nu7.6-25ns-Pythia8/Sim10c/{{evttype}}/DIGI"
     dq_flags:
@@ -41,10 +45,10 @@ HLT1_b0_dstp_{{lepton}}_{{ polarity }}:
         max_buffer_size: 1048576
       #evt_max: 1000
 
-HLT2_b0_dstp_{{lepton}}_{{ polarity }}:
-  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
+HLT2_{{dk}}_{{ polarity }}:
+  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
-    job_name: HLT1_b0_dstp_{{lepton}}_{{ polarity }}
+    job_name: HLT1_{{dk}}_{{ polarity }}
   output: hlt2.dst
   options:
     entrypoint: SL_l_nu_D0toKpi_Run3_MC.Hlt2:{{line}}
@@ -63,10 +67,10 @@ HLT2_b0_dstp_{{lepton}}_{{ polarity }}:
         level: 1
         max_buffer_size: 1048576
       #evt_max: 1000
-SPRUCE_b0_dstp_{{lepton}}_{{ polarity }}:
-  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
+SPRUCE_{{dk}}_{{ polarity }}:
+  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
-    job_name: HLT2_b0_dstp_{{lepton}}_{{ polarity }}
+    job_name: HLT2_{{dk}}_{{ polarity }}
   output: spruce.dst
   options:
     entrypoint: SL_l_nu_D0toKpi_Run3_MC.Spruce:{{line}}
@@ -87,10 +91,10 @@ SPRUCE_b0_dstp_{{lepton}}_{{ polarity }}:
         level: 1
         max_buffer_size: 1048576
       #evt_max: 1000
-DV_b0_dstp_{{lepton}}_{{ polarity }}:
+DV_{{dk}}_{{ polarity }}:
   application: "DaVinci/v64r5@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
-    job_name: SPRUCE_b0_dstp_{{lepton}}_{{ polarity }}
+    job_name: SPRUCE_{{dk}}_{{ polarity }}
   output: NTuple.root
   options:
     entrypoint: SL_l_nu_D0toKpi_Run3_MC.DV:{{line}}
-- 
GitLab


From 683e06ea4c2821817ab20e7b3ca5c623b59c2a4a Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Fri, 31 May 2024 14:18:18 +0200
Subject: [PATCH 34/57] Use mu iso mva for everything

---
 SL_l_nu_D0toKpi_Run3_MC/DV.py | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC/DV.py b/SL_l_nu_D0toKpi_Run3_MC/DV.py
index 19a333dfa6..7da86855e1 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC/DV.py
@@ -74,7 +74,7 @@ def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = Tru
 	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
 	return Bst
 
-def get_functors(MCTRUTH, v2_pvs, rec_summary,line):
+def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	#define common variables for all fields (composite and basic)
 	vars_common  = FunctorCollection()
 	#all pvs: ip, ipchi2. The PV positions are stored in event variables
@@ -186,7 +186,6 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary,line):
 	#Collection includes tis_tos, nPVs,nHits/clusters,BUNCHCROSSING and GPS var
 	evt_collections = [
 		FC.EventInfo(),
-		FC.SelectionInfo(selection_type="Hlt2", trigger_lines=[line.replace("Spruce","HLT2")]),
 		FC.RecSummary(),
 	]
 	evt_vars = FunctorCollection({})
@@ -249,7 +248,7 @@ def get_fitting_variable(v2_pvs,D0,lep):
 
 def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
 	#get functors
-	functors = get_functors(MCTRUTH, v2_pvs, rec_summary,line)
+	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
 	vars_common = functors[0]
 	vars_composite = functors[1]
 	vars_basic = functors[2]
@@ -291,7 +290,7 @@ def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
 	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
 	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
 	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
-	vars_Bst['iso_mva'] = mva_functor_e_inclusive(v2_pvs)[0] if lepton == 'e' else mva_functor_mu_inclusive(v2_pvs)[0]
+	vars_Bst['iso_mva'] = mva_functor_mu_inclusive(v2_pvs)[0]
 	vars_Bst += trail_seeker(MCTRUTH)
 
 
@@ -313,7 +312,14 @@ def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
 	'Hlt1Pi02GammaGamma',
 	'Hlt1DiElectronHighMass_SS',
 	'Hlt1DiElectronHighMass']
-	variables_tistos = FC.HltTisTos(selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=Bst)
+	variables_tistos_hlt1 = FC.HltTisTos(selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=Bst)
+	evt_vars += FC.SelectionInfo(selection_type="Hlt1", trigger_lines=Hlt1_decisions)
+
+
+	Hlt2_decisions = ['Hlt2Topo2BodyDecision','Hlt2Topo3BodyDecision']
+	variables_tistos_hlt2 = FC.HltTisTos(selection_type="Hlt2", trigger_lines=Hlt2_decisions, data=Bst)
+	evt_vars += FC.SelectionInfo(selection_type="Hlt2", trigger_lines=Hlt2_decisions)
+
 
 	#define fields
 	fields = {}
@@ -327,8 +333,8 @@ def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
     
 	#add variables
 	variables = {}
-	variables["ALL"] = vars_common
-	variables["B0"]  = vars_composite + vars_Bst + fit_vars + variables_tistos
+	variables["ALL"] = vars_common + variables_tistos_hlt1 + variables_tistos_hlt2
+	variables["B0"]  = vars_composite + vars_Bst + fit_vars
 	variables["Bm"]  = vars_composite
 	variables["D0"]  = vars_composite
 	variables["Lep"] = vars_basic + vars_brems
@@ -369,6 +375,7 @@ def main(options: Options,line = '', lep=''):
 	#get data and extra particles
 	lb = get_particles(f"/Event/Spruce/{line}/Particles")
 	extra_particles = get_extra_pions()
+	#extra_particles = get_particles(f"/Event/Spruce/{line}/{line}_extra_tracks/Particles")
 
 	#get v2_pvs and rec_summary
 	v2_pvs  = get_pvs()
-- 
GitLab


From af2d722720a9e2b9797d3f100e2d80219d61e21d Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Thu, 6 Jun 2024 11:04:51 +0200
Subject: [PATCH 35/57] Edit comments in Hlt2 cuts

---
 SL_l_nu_D0toKpi_Run3_MC/Hlt2.py | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py b/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
index 8361952e5f..f2dffdd01d 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
+++ b/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
@@ -41,25 +41,25 @@ def get_charm_cuts():
     make_d0tokpi_cuts['comb_m_min']            = (CHARM_MASS - delta_mass) * MeV
     make_d0tokpi_cuts['comb_m_max']            = (CHARM_MASS + delta_mass) * MeV
     make_d0tokpi_cuts['comb_docachi2_max']     = 5.
-    make_d0tokpi_cuts['vchi2pdof_max']         = 6   #6 (2024) 6/4 (master e/taue)
-    make_d0tokpi_cuts['bpvfdchi2_min']         = 25  #25 (2024)
-    make_d0tokpi_cuts['bpvdira_min']           = 0.99  #0.99 (2024) 0.99/0.999 (master e/taue)
-    make_d0tokpi_cuts['comb_pt_min']           = None #None (2024) None/2000 * MeV (master e/taue)
-    make_d0tokpi_cuts['comb_pt_any_min']       = None #None (2024) None/800 * MeV (master e/taue)
-    make_d0tokpi_cuts['comb_pt_sum_min']       = None #None (2024) None/2.5 * GeV (master e/taue)
-    make_d0tokpi_cuts['comb_doca_max']         = None #None (2024) None/0.1 mm (master e/taue)
-    make_d0tokpi_cuts['daughter_pt_min']       = 600 * MeV #600 * MeV (2024) 750 * MeV (master)
-    make_d0tokpi_cuts['daughter_mipchi2_min']  = 9. #10. (2024) 10./9. (master e/taue)
-    make_d0tokpi_cuts['kaon_pid']              = (F.PID_K > 0.) #(F.PID_K > 0.) (2024) (F.PID_K > 4.) (master) 
+    make_d0tokpi_cuts['vchi2pdof_max']         = 6   #6 (Now) 6/4 (v55r7 e/taue)
+    make_d0tokpi_cuts['bpvfdchi2_min']         = 25  #25 (Now)
+    make_d0tokpi_cuts['bpvdira_min']           = 0.99  #0.99 (Now) 0.99/0.999 (v55r7 e/taue)
+    make_d0tokpi_cuts['comb_pt_min']           = None #None (Now) None/2000 * MeV (v55r7 e/taue)
+    make_d0tokpi_cuts['comb_pt_any_min']       = None #None (Now) None/800 * MeV (v55r7 e/taue)
+    make_d0tokpi_cuts['comb_pt_sum_min']       = None #None (Now) None/2.5 * GeV (v55r7 e/taue)
+    make_d0tokpi_cuts['comb_doca_max']         = None #None (Now) None/0.1 mm (v55r7 e/taue)
+    make_d0tokpi_cuts['daughter_pt_min']       = 600 * MeV #600 * MeV (Now) 750 * MeV (v55r7)
+    make_d0tokpi_cuts['daughter_mipchi2_min']  = 9. #10. (Now) 10./9. (v55r7 e/taue)
+    make_d0tokpi_cuts['kaon_pid']              = (F.PID_K > 0.) #(F.PID_K > 0.) (Now) (F.PID_K > 4.) (v55r7) 
     make_d0tokpi_cuts['pion_pid']              = (F.PID_K < 2.)
     return make_d0tokpi_cuts
 
 def get_electron_cuts():
     #make loose cuts for electron and tauonic muon
     make_electron_cuts = {}
-    make_electron_cuts["p_min"]           = 3. * GeV #3. * GeV (2024) 5. *GeV (master)
-    make_electron_cuts["pt_min"]          = 300. * MeV #300. * MeV (2024) 500. * MeV (master)
-    make_electron_cuts["mipchi2_min"]     = 9. #9. (2024) 9./16. (master e/taue) 
+    make_electron_cuts["p_min"]           = 3. * GeV #3. * GeV (Now) 5. *GeV (v55r7)
+    make_electron_cuts["pt_min"]          = 300. * MeV #300. * MeV (Now) 500. * MeV (v55r7)
+    make_electron_cuts["mipchi2_min"]     = 9. #9. (Now) 9./16. (v55r7 e/taue) 
     make_electron_cuts["mip_min"]         = None #0.
     make_electron_cuts["pid"]             = (F.PID_E > 0.0) 
     make_electron_cuts["make_particles"]  = make_long_electrons_with_brem  #does not require in calo
-- 
GitLab


From b33f7909f5383c1bb6dca5b5e861cb4047b6b02f Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Thu, 13 Jun 2024 13:44:04 +0200
Subject: [PATCH 36/57] Fix tis_tos issue

---
 SL_l_nu_D0toKpi_Run3_MC/DV.py     |  38 ++++++---
 SL_l_nu_D0toKpi_Run3_MC/Hlt1.py   |  16 +---
 SL_l_nu_D0toKpi_Run3_MC/Hlt2.py   | 136 ++++++++++++++++--------------
 SL_l_nu_D0toKpi_Run3_MC/Spruce.py |  94 ++++++++-------------
 SL_l_nu_D0toKpi_Run3_MC/info.yaml |  12 +--
 5 files changed, 144 insertions(+), 152 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC/DV.py b/SL_l_nu_D0toKpi_Run3_MC/DV.py
index 7da86855e1..216f7e7f3d 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC/DV.py
@@ -147,7 +147,7 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	#mc composite vertex information
 	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
 	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
-	# only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
+	# only two daughters of B0 particles, the maximum DOCA/DOCACHI2 is 
 	# the DOCA/DOCACHI2 see below.
 	vars_composite['MAX_DOCA'] = F.MAXDOCA
 	vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
@@ -255,7 +255,7 @@ def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
 	evt_vars = functors[3]
 	vars_brems = functors[4]
 
-	#variables for Sb field
+	#variables for B0 field
 	vars_Bst  = FunctorCollection()
 	B_child   = F.CHILD(1, F.FORWARDARG0)
 	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
@@ -286,7 +286,7 @@ def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
 	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
 	#vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
 	#vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
-	#DOCACHI2 of extra particle wrt to mother i.e. Sb
+	#DOCACHI2 of extra particle wrt to mother i.e. B0
 	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
 	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
 	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
@@ -315,8 +315,20 @@ def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
 	variables_tistos_hlt1 = FC.HltTisTos(selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=Bst)
 	evt_vars += FC.SelectionInfo(selection_type="Hlt1", trigger_lines=Hlt1_decisions)
 
+	Hlt2_decisions = ['Hlt2SLB_BuToD0MuNu_D0ToKPi',
+    'Hlt2SLB_BuToD0MuNu_D0ToKPi_FakeMuon',
+    'Hlt2SLB_BuToD0ENu_D0ToKPi',
+    'Hlt2SLB_BuToD0ENu_D0ToKPi_FakeElectron',
+    'Hlt2SLB_B0ToDpTauNu_DpToKPiPi_TauToENuNu',
+    'Hlt2SLB_B0ToDpTauNu_DpToKPiPi_TauToMuNuNu',
+    'Hlt2SLB_BuToD0TauNu_D0ToKPi_TauToENuNu',
+    'Hlt2SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',
+    'Hlt2SLB_BuToD0TauNu_D0ToKPi_FakeMuon',
+    'Hlt2SLB_BuToD0TauNu_D0ToKPi_FakeElectron',
+    'Hlt2SLB_myBuToD0ENu_D0ToKPi',
+    'Hlt2Topo2Body',
+    'Hlt2Topo3Body']
 
-	Hlt2_decisions = ['Hlt2Topo2BodyDecision','Hlt2Topo3BodyDecision']
 	variables_tistos_hlt2 = FC.HltTisTos(selection_type="Hlt2", trigger_lines=Hlt2_decisions, data=Bst)
 	evt_vars += FC.SelectionInfo(selection_type="Hlt2", trigger_lines=Hlt2_decisions)
 
@@ -373,7 +385,7 @@ def main(options: Options,line = '', lep=''):
 	my_filter = create_lines_filter(name="Filter", lines=[line])
 
 	#get data and extra particles
-	lb = get_particles(f"/Event/Spruce/{line}/Particles")
+	Bm = get_particles(f"/Event/Spruce/{line}/Particles")
 	extra_particles = get_extra_pions()
 	#extra_particles = get_particles(f"/Event/Spruce/{line}/{line}_extra_tracks/Particles")
 
@@ -381,8 +393,8 @@ def main(options: Options,line = '', lep=''):
 	v2_pvs  = get_pvs()
 	rec_summary = get_rec_summary()
 	hadron_candidate_id = 421
-	#make sb candidate
-	Bst = make_Bst(lb, extra_particles,lep,hadron_candidate_id,v2_pvs,False)
+	#make B0 candidate
+	Bst = make_Bst(Bm, extra_particles,lep,hadron_candidate_id,v2_pvs,False)
 	MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
 
 
@@ -398,25 +410,25 @@ def test(options: Options):
 	return main(options=options, line='Hlt2_Test_line',lep='e')
 
 def SLB_BuToD0ENu_D0ToKPi(options: Options):
-	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
 
 def SLB_BuToDststENu(options: Options):
-	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
 
 def SLB_BdToDststENu(options: Options):
-	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
 
 def SLB_BuToD0MuNu_D0ToKPi(options: Options):
 	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu')
 
 def SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
 
 def SLB_BuToDststTauNu_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
 
 def SLB_BdToDststTauNu_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_BToDzl',lep='e')
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
 
 def SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
 	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu')
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Hlt1.py b/SL_l_nu_D0toKpi_Run3_MC/Hlt1.py
index e2d0622696..eeabcc4913 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/Hlt1.py
+++ b/SL_l_nu_D0toKpi_Run3_MC/Hlt1.py
@@ -9,18 +9,10 @@
 # or submit itself to any jurisdiction.                                       #
 ###############################################################################
 from Moore import Options
-from Moore.config import allen_control_flow
-from RecoConf.hlt1_allen import allen_gaudi_config, get_allen_line_names
-from PyConf.application import configure_input, configure
-from RecoConf.muonid import make_muon_hits
-#need to bind geometry version to 3 for muon hits
-make_muon_hits.global_bind(geometry_version=3)
+from Moore.config import run_allen
+from RecoConf.hlt1_allen import allen_gaudi_config as allen_sequence
 
 def main(options: Options):
-    config = configure_input(options)
-    with allen_gaudi_config.bind(sequence="hlt1_pp_matching_no_ut_1000KHz"):
-        allen_node = allen_control_flow(options)
-        config.update(configure(options, allen_node))
-    return config
-
+    with allen_sequence.bind(sequence="hlt1_pp_matching_no_ut_1000KHz"):
+        return run_allen(options)
 
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py b/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
index f2dffdd01d..40ddb823ea 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
+++ b/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
@@ -8,6 +8,9 @@
 # granted to it by virtue of its status as an Intergovernmental Organization  #
 # or submit itself to any jurisdiction.                                       #
 ###############################################################################
+"""
+Stolen and adapted from Hlt/Hlt2Conf/options/hlt2_pp_expected_24_without_UT.py from v55r7.
+"""
 from Moore import Options,options, run_moore, config
 from Hlt2Conf.algorithms_thor import ParticleContainersMerger
 from Hlt2Conf.lines.semileptonic.builders import sl_line_prefilter
@@ -15,10 +18,22 @@ from Hlt2Conf.lines.semileptonic.builders.base_builder import make_candidate
 from Hlt2Conf.lines.semileptonic.builders.charm_hadron_builder import make_d0_tokpi
 from GaudiKernel.SystemOfUnits import MeV, GeV,mm
 from Hlt2Conf.algorithms_thor import ParticleCombiner
-from Moore.config import Hlt2Line
-from RecoConf.global_tools import stateProvider_with_simplified_geom
+from Hlt2Conf.settings.defaults import get_default_hlt1_filter_code_for_hlt2
+from Hlt2Conf.lines.semileptonic import all_lines as slb_lines  
+from Hlt2Conf.lines.topological_b import all_lines as topo_lines
+from Moore.config import Hlt2Line,register_line_builder
+from Moore.streams import Stream, Streams, DETECTORS
+from RecoConf.event_filters import require_gec
+from RecoConf.global_tools import stateProvider_with_simplified_geom, trackMasterExtrapolator_with_simplified_geom
+from RecoConf.hlt2_global_reco import reconstruction as hlt2_reconstruction, make_light_reco_pr_kf_without_UT
 from RecoConf.reconstruction_objects import reconstruction,make_pvs
-from RecoConf.decoders import default_ft_decoding_version
+from RecoConf.decoders import default_ft_decoding_version,default_VeloCluster_source
+from RecoConf.hlt2_tracking import (
+    make_TrackBestTrackCreator_tracks,
+    make_PrKalmanFilter_noUT_tracks,
+    make_PrKalmanFilter_Velo_tracks,
+    make_PrKalmanFilter_Seed_tracks,
+)
 from Hlt2Conf.standard_particles import (
     make_long_electrons_with_brem,
     make_has_rich_long_pions, 
@@ -26,10 +41,11 @@ from Hlt2Conf.standard_particles import (
     make_has_rich_down_pions)
 import Functors as F
 from Functors.math import in_range
+import sys
 
 #things to control
 SUFFIX_NAME = '_BToDzl'
-HLT2LINE = f'Hlt2SLB{SUFFIX_NAME}'
+HLT2LINE = f'Hlt2SLB_myBuToD0ENu_D0ToKPi'
 CHARM_MASS = 1864.84 #D0 mass
 CHARM_BUILDER_NAME = 'Dz2KPi_combiner'
 B_BUILDER_NAME     = 'BToDzl_combiner'
@@ -80,68 +96,60 @@ def make_b():
         name=f'rs_{B_BUILDER_NAME}_e',
         DecayDescriptor='[B- -> D0 e-]cc',
         CombinationCut=F.ALL,
-        CompositeCut=cut_vertex,
-        ParticleCombiner="ParticleVertexFitter")
+        CompositeCut=cut_vertex)
+
     ws_btodze  =  ParticleCombiner(
         Inputs=[dzs, electrons],
         name=f'ws_{B_BUILDER_NAME}_e',
         DecayDescriptor='[B+ -> D0 e+]cc',
         CombinationCut=F.ALL,
-        CompositeCut=cut_vertex,
-        ParticleCombiner="ParticleVertexFitter")
-    return ParticleContainersMerger([rs_btodze,ws_btodze], name = B_BUILDER_NAME)
-
-from Hlt2Conf.lines.semileptonic.hlt2_semileptonic import hlt2_butod0munu_d0tokpi_line,hlt2_butod0taunu_d0tokpi_tautomununu_line
-
-def make_lines_e():
-    def hlt2_lines(name=HLT2LINE,prescale=1):
-        Bcands = make_b()
-        return Hlt2Line(name=name, prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
-    lines = [hlt2_lines()]
-    return lines
-
-def make_lines_mu():
-   return [hlt2_butod0munu_d0tokpi_line()] 
-
-def make_lines_taumu():
-   return [hlt2_butod0taunu_d0tokpi_tautomununu_line()] 
-
-def SLB_BuToD0ENu_D0ToKPi(options: Options):
-  with reconstruction.bind(from_file=False):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-  return config
-
-def SLB_BuToDststENu(options: Options):
-  with reconstruction.bind(from_file=False):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-  return config
-
-def SLB_BdToDststENu(options: Options):
-  with reconstruction.bind(from_file=False):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-  return config
-
-def SLB_BuToD0MuNu_D0ToKPi(options: Options):
-  with reconstruction.bind(from_file=False):
-    config = run_moore(options, make_streams=make_lines_mu, public_tools=[stateProvider_with_simplified_geom()])
-    return config
-
-def SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
-  with reconstruction.bind(from_file=False):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-    return config
-
-def SLB_BuToDststTauNu_TauToENuNu(options: Options):
-  with reconstruction.bind(from_file=False):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-    return config
-
-def SLB_BdToDststTauNu_TauToENuNu(options: Options):
-  with reconstruction.bind(from_file=False):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-    return config
-
-def SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
-  with reconstruction.bind(from_file=False):
-    config = run_moore(options, make_streams=make_lines_taumu, public_tools=[stateProvider_with_simplified_geom()])
-    return config
+        CompositeCut=cut_vertex)
+
+    return ParticleContainersMerger([rs_btodze,ws_btodze])
+
+@register_line_builder(slb_lines)
+def hlt2_mybutod0enu_d0tokpi_line(name=HLT2LINE,prescale=1):
+    Bcands = make_b()
+    return Hlt2Line(name=name, prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
+
+def pass_through_line(name="Hlt2Passthrough"):
+    """Return a HLT2 line that performs no selection but runs and persists the reconstruction
+    """
+    return Hlt2Line(name=name, prescale=1, algs=[], persistreco=True)
+
+from Hlt2Conf.lines.topological_b import *
+
+def _make_lines():
+    ret = []     
+    for line_dict in [slb_lines]: 
+        for line_name, builder in line_dict.items() : 
+            if "D0ToKPi" in line_name and "TauToPiPiPi" not in line_name and "Bc" not in line_name: 
+                print(line_name)
+                ret.append(builder())
+    ret += [twobody_line(),threebody_line(),pass_through_line()]
+    return ret   
+
+def make_streams():
+    streams = [
+        Stream(lines=_make_lines(), routing_bit=98, detectors=DETECTORS)
+    ]
+    return Streams(streams=streams)
+
+public_tools = [
+    trackMasterExtrapolator_with_simplified_geom(),
+    stateProvider_with_simplified_geom(),
+]
+
+def main(options: Options):
+    # NOTE: the TBTC does not apply a chi2 cut because it is applied by the PrKF
+    with reconstruction.bind(from_file=False),\
+         hlt2_reconstruction.bind(make_reconstruction=make_light_reco_pr_kf_without_UT),\
+         require_gec.bind(skipUT=True),\
+         default_VeloCluster_source.bind(bank_type="VPRetinaCluster"),\
+         make_TrackBestTrackCreator_tracks.bind(max_ghost_prob=0.7, max_chi2ndof=sys.float_info.max),\
+         make_PrKalmanFilter_Velo_tracks.bind(max_chi2ndof=5.),\
+         make_PrKalmanFilter_noUT_tracks.bind(max_chi2ndof=4.),\
+         make_PrKalmanFilter_Seed_tracks.bind(max_chi2ndof=6.),\
+         get_default_hlt1_filter_code_for_hlt2.bind(code=r"Hlt1(?!PassthroughLargeEvent).*Decision"):
+        return run_moore(options, make_streams, public_tools=[])
+
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Spruce.py b/SL_l_nu_D0toKpi_Run3_MC/Spruce.py
index 8e11e66a60..964714aba8 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/Spruce.py
+++ b/SL_l_nu_D0toKpi_Run3_MC/Spruce.py
@@ -11,68 +11,48 @@
 #Example follows from hlt2_with_hlt1_decision.py
 from Moore import Options,options, run_moore, config
 from Hlt2Conf.lines.semileptonic.builders import sl_line_prefilter
-from Moore.config import SpruceLine
+from Moore.config import SpruceLine,register_line_builder
 from .Hlt2 import make_b
+from Moore.streams import DETECTORS, Stream, Streams
 from PyConf.application import configure_input, configure, default_raw_event
 from RecoConf.global_tools import stateProvider_with_simplified_geom
 from RecoConf.reconstruction_objects import reconstruction
+from PyConf.reading import reconstruction as reco_spruce, upfront_reconstruction as upfront_spruce
 from RecoConf.decoders import default_ft_decoding_version
-from RecoConf.hlt2_global_reco import reconstruction as hlt2_reconstruction, make_fastest_reconstruction
 from Hlt2Conf.lines.semileptonic.spruce_semileptonic import spruce_butod0munu_d0tokpi_line,spruce_butod0taunu_d0tokpi_tautomununu_line
 from Hlt2Conf.lines.semileptonic.HbToHcTauNu_TauToLNuNu import make_butod0taunu_d0tokpi_tautolnunu
 from Hlt2Conf.lines.semileptonic.HbToHcLNu import make_butod0lnu_d0tokpi
-
-def make_lines_e():
-    def spruce_lines(name='SpruceSLB_BToDzl',prescale=1):
-        Bcands = make_b()
-        return SpruceLine(name=name,  hlt2_filter_code=[
-        f"{name.replace('Spruce','Hlt2')}Decision",
-        "Hlt2Topo2BodyDecision", "Hlt2Topo3BodyDecision"]
-        ,prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
-    return [spruce_lines()]
-
-def make_lines_taumu():
-    return [spruce_butod0taunu_d0tokpi_tautomununu_line()]
-
-def make_lines_mu():
-    return [spruce_butod0munu_d0tokpi_line()]
-
-def SLB_BuToD0ENu_D0ToKPi(options: Options):
-  with reconstruction.bind(from_file=True, spruce=True):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-    return config
-
-def SLB_BuToDststENu(options: Options):
-  with reconstruction.bind(from_file=True, spruce=True):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-    return config
-
-def SLB_BdToDststENu(options: Options):
-  with reconstruction.bind(from_file=True, spruce=True):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-    return config
-
-def SLB_BuToD0MuNu_D0ToKPi(options: Options):
-  with reconstruction.bind(from_file=True, spruce=True):
-    config = run_moore(options, make_streams=make_lines_mu, public_tools=[stateProvider_with_simplified_geom()])
-    return config
-
-def SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
-  with reconstruction.bind(from_file=True, spruce=True):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-    return config
-
-def SLB_BuToDststTauNu_TauToENuNu(options: Options):
-  with reconstruction.bind(from_file=True, spruce=True):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-    return config
-
-def SLB_BdToDststTauNu_TauToENuNu(options: Options):
-  with reconstruction.bind(from_file=True, spruce=True):
-    config = run_moore(options, make_streams=make_lines_e, public_tools=[stateProvider_with_simplified_geom()])
-    return config
-
-def SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
-  with reconstruction.bind(from_file=True, spruce=True):
-    config = run_moore(options, make_streams=make_lines_taumu, public_tools=[stateProvider_with_simplified_geom()])
-    return config
+from Moore.persistence.hlt2_tistos import list_of_full_stream_lines
+from Hlt2Conf.lines.semileptonic import all_lines as slb_lines
+from Hlt2Conf.lines.topological_b import all_lines as topo_lines
+from Hlt2Conf.lines.semileptonic import sprucing_lines as slb_sprucing_lines
+def lines_for_tistos():
+    """
+    Nikole Comment : 
+    This TISTOS part is only needed for exclusive Sprucing 
+    and it saves the candidates of the FULL HLT2 lines that fired for each event. 
+    You need to make sure its only FULL HLT2 lines in the lines_for_tistos 
+    and they are the ones you care about ie. RD inclusive lines
+    """
+    return [linename for line_dict in [slb_lines,topo_lines] for linename in line_dict.keys()]
+
+@register_line_builder(slb_sprucing_lines)
+def spruce_mybutod0enu_d0tokpi_line(name='SpruceSLB_myBuToD0ENu_D0ToKPi',prescale=1):
+    Bcands = make_b()
+    return SpruceLine(name=name,  hlt2_filter_code=[
+    f"{name.replace('Spruce','Hlt2')}Decision",
+    "Hlt2Topo2BodyDecision", "Hlt2Topo3BodyDecision"]
+    ,prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
+
+def make_full_streams():
+    lines = [builder() for builder in slb_sprucing_lines.values()]
+    streams = [Stream(lines=lines, detectors=[])]
+    return Streams(streams=streams)
+
+def main(options: Options):
+    public_tools = [stateProvider_with_simplified_geom()]
+    with reconstruction.bind(from_file=True, spruce=True),\
+      reco_spruce.bind(simulation=True),\
+      upfront_spruce.bind(simulation=True),\
+      list_of_full_stream_lines.bind(lines=lines_for_tistos()):
+        return run_moore(options, make_full_streams, public_tools=public_tools)
diff --git a/SL_l_nu_D0toKpi_Run3_MC/info.yaml b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
index 8d3007e1f6..7e1d75701c 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/info.yaml
+++ b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
@@ -26,7 +26,7 @@ HLT1_{{dk}}_{{ polarity }}:
     bk_query: "/MC/Dev/Beam6800GeV-expected-2024-{{polarity}}-Nu7.6-25ns-Pythia8/Sim10c/{{evttype}}/DIGI"
     dq_flags:
       - OK
-    n_test_lfns: 2
+    n_test_lfns: 3
   output: hlt1.dst
   options:
     entrypoint: SL_l_nu_D0toKpi_Run3_MC.Hlt1:main
@@ -43,15 +43,15 @@ HLT1_{{dk}}_{{ polarity }}:
         algorithm: ZSTD
         level: 1
         max_buffer_size: 1048576
-      #evt_max: 1000
+      #evt_max: 1000 
 
 HLT2_{{dk}}_{{ polarity }}:
-  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  application: "Moore/v55r7@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     job_name: HLT1_{{dk}}_{{ polarity }}
   output: hlt2.dst
   options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC.Hlt2:{{line}}
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC.Hlt2:main
     extra_options:
       input_raw_format: 0.5
       conddb_tag: {{cond_tag}}
@@ -68,12 +68,12 @@ HLT2_{{dk}}_{{ polarity }}:
         max_buffer_size: 1048576
       #evt_max: 1000
 SPRUCE_{{dk}}_{{ polarity }}:
-  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  application: "Moore/v55r7@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     job_name: HLT2_{{dk}}_{{ polarity }}
   output: spruce.dst
   options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC.Spruce:{{line}}
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC.Spruce:main
     extra_options:
       input_raw_format: 0.5
       conddb_tag: {{cond_tag}}
-- 
GitLab


From 26f6e9d7c40147d14db89284080ab3c643aadc49 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Thu, 13 Jun 2024 13:53:37 +0200
Subject: [PATCH 37/57] Fix Moore version

---
 SL_l_nu_D0toKpi_Run3_MC/info.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC/info.yaml b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
index 7e1d75701c..10fa5c59e4 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/info.yaml
+++ b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
@@ -46,7 +46,7 @@ HLT1_{{dk}}_{{ polarity }}:
       #evt_max: 1000 
 
 HLT2_{{dk}}_{{ polarity }}:
-  application: "Moore/v55r7@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     job_name: HLT1_{{dk}}_{{ polarity }}
   output: hlt2.dst
@@ -68,7 +68,7 @@ HLT2_{{dk}}_{{ polarity }}:
         max_buffer_size: 1048576
       #evt_max: 1000
 SPRUCE_{{dk}}_{{ polarity }}:
-  application: "Moore/v55r7@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     job_name: HLT2_{{dk}}_{{ polarity }}
   output: spruce.dst
-- 
GitLab


From 81aa30c372c822868cef2255192c59f404a285f5 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 17 Jun 2024 12:03:35 +0200
Subject: [PATCH 38/57] Try to reduce memory usage

---
 SL_l_nu_D0toKpi_Run3_MC/info.yaml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC/info.yaml b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
index 10fa5c59e4..a77ff06360 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/info.yaml
+++ b/SL_l_nu_D0toKpi_Run3_MC/info.yaml
@@ -26,7 +26,7 @@ HLT1_{{dk}}_{{ polarity }}:
     bk_query: "/MC/Dev/Beam6800GeV-expected-2024-{{polarity}}-Nu7.6-25ns-Pythia8/Sim10c/{{evttype}}/DIGI"
     dq_flags:
       - OK
-    n_test_lfns: 3
+    n_test_lfns: 1
   output: hlt1.dst
   options:
     entrypoint: SL_l_nu_D0toKpi_Run3_MC.Hlt1:main
@@ -105,6 +105,7 @@ DV_{{dk}}_{{ polarity }}:
       input_type: ROOT
       simulation: True
       data_type: "Upgrade"
+      #geometry_version: run3/2024.Q1.2-v00.00
       input_process: "Spruce"
       input_manifest_file: "SPRUCE.tck.json"
       #evt_max: 1000
-- 
GitLab


From 9df520b577619b70c7b2fd1d209bb026159e4bf6 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 24 Jun 2024 03:31:31 +0200
Subject: [PATCH 39/57] add everything

---
 .../DV.py                                     | 241 +++++++++++-------
 .../Hlt1.py                                   |   0
 .../Hlt2.py                                   |   2 +-
 .../MC_Matcher.py                             |   0
 .../Spruce.py                                 |   0
 .../info.yaml                                 |  51 +++-
 6 files changed, 201 insertions(+), 93 deletions(-)
 rename {SL_l_nu_D0toKpi_Run3_MC => SL_l_nu_D0toKpi_Run3_MC_data}/DV.py (70%)
 rename {SL_l_nu_D0toKpi_Run3_MC => SL_l_nu_D0toKpi_Run3_MC_data}/Hlt1.py (100%)
 rename {SL_l_nu_D0toKpi_Run3_MC => SL_l_nu_D0toKpi_Run3_MC_data}/Hlt2.py (99%)
 rename {SL_l_nu_D0toKpi_Run3_MC => SL_l_nu_D0toKpi_Run3_MC_data}/MC_Matcher.py (100%)
 rename {SL_l_nu_D0toKpi_Run3_MC => SL_l_nu_D0toKpi_Run3_MC_data}/Spruce.py (100%)
 rename {SL_l_nu_D0toKpi_Run3_MC => SL_l_nu_D0toKpi_Run3_MC_data}/info.yaml (64%)

diff --git a/SL_l_nu_D0toKpi_Run3_MC/DV.py b/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
similarity index 70%
rename from SL_l_nu_D0toKpi_Run3_MC/DV.py
rename to SL_l_nu_D0toKpi_Run3_MC_data/DV.py
index 216f7e7f3d..e71c5d49f3 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
@@ -1,5 +1,6 @@
 import sys,os,math
 from PyConf.reading import get_pvs, get_rec_summary, get_particles
+from PyConf.Algorithms import ThOrParticleSelection
 import Functors as F
 from FunTuple import FunctorCollection
 from FunTuple import FunTuple_Particles as Funtuple
@@ -31,48 +32,88 @@ ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_F
 TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
 
 def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
-	if do_truth_matching == True :
-		#filter B keeping only true D0 and true leptons
-		MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
-		Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
-		lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
-		Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
-		lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
-		cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
-		signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
-	else : signal_B = B
-
-	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
-	Epi_child = F.CHILD(2, F.FORWARDARG0)
-
-	#D* mass - D0 mass cut
-	cut_combine = F.require_all(((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))<200)
-
-	#combine to make [B*0 -> B*- pi+]cc
-	Bst_1 = ParticleCombiner(
-		Inputs=[B, pions],
-		name=f'Bst_1_{lepton}',
-		DecayDescriptor='[B0 -> B- pi+]cc',
-		CombinationCut=cut_combine,
-		CompositeCut=F.ALL,
-		ParticleCombiner="ParticleVertexFitter",
-		PrimaryVertices=v2_pvs
-		#OutputLevel=1
-	)
-	#combine to make [B*0 -> B*- pi-]cc
-	Bst_2 = ParticleCombiner(
-		Inputs=[B, pions],
-		name=f'Bst_2_{lepton}',
-		DecayDescriptor='[B0 -> B- pi-]cc',
-		CombinationCut=cut_combine,
-		CompositeCut=F.ALL,
-		ParticleCombiner="ParticleVertexFitter",
-		PrimaryVertices=v2_pvs
-		#OutputLevel=1
-	)
-	#merge the two Bst candidates
-	Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
-	return Bst
+    if do_truth_matching == True :
+        #filter B keeping only true D0 and true leptons
+        MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
+        Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
+        lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
+        Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
+        lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
+        cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
+        signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
+    else : signal_B = B
+
+    hadron_cut = F.IS_ABS_ID('D0')  # Getting the hadron candidates
+
+    code_hadron = F.FILTER(hadron_cut) @ F.GET_CHILDREN()
+    hadron_TES = ThOrParticleSelection(
+        name="hadron_iso",
+        InputParticles=signal_B,
+        Functor=code_hadron).OutputSelection
+
+    lepton_cut = F.IS_ABS_ID(f'{lepton}-')
+    code_lepton = F.FILTER(lepton_cut) @ F.GET_CHILDREN()
+    lepton_TES = ThOrParticleSelection(
+        name="lepton_iso",
+        InputParticles=signal_B,
+        Functor=code_lepton).OutputSelection
+
+
+    #combine to make [B*- -> D0 lep-]cc
+    Bstm_1 = ParticleCombiner(
+        Inputs=[hadron_TES, lepton_TES],
+        name=f'Bstm_1_{lepton}',
+        DecayDescriptor=f'[B*- -> D0 {lepton}-]cc',
+        CombinationCut=F.ALL,
+        CompositeCut=F.ALL,
+        ParticleCombiner="ParticleVertexFitter",
+        #PrimaryVertices=v2_pvs
+        #OutputLevel=1
+    )
+    #combine to make [B*+ -> D0 lep+]cc
+    Bstm_2 = ParticleCombiner(
+        Inputs=[hadron_TES, lepton_TES],
+        name=f'Bstm_2_{lepton}',
+        DecayDescriptor=f'[B*+ -> D0 {lepton}+]cc',
+        CombinationCut=F.ALL,
+        CompositeCut=F.ALL,
+        ParticleCombiner="ParticleVertexFitter",
+        #PrimaryVertices=v2_pvs
+        #OutputLevel=1
+    )
+    Bstm = ParticleContainersMerger([Bstm_1, Bstm_2], name = f'Bstm_combiner_{lepton}')
+
+    D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
+    Epi_child = F.CHILD(2, F.FORWARDARG0)
+
+    #D* mass - D0 mass cut
+    cut_combine = F.require_all(((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))<200)
+
+    #combine to make [B*0 -> B*- pi+]cc
+    Bst_1 = ParticleCombiner(
+        Inputs=[Bstm, pions],
+        name=f'Bst_1_{lepton}',
+        DecayDescriptor='[B*0 -> B*- pi+]cc',
+        CombinationCut=cut_combine,
+        CompositeCut=F.ALL,
+        ParticleCombiner="ParticleVertexFitter",
+        PrimaryVertices=v2_pvs
+        #OutputLevel=1
+    )
+    #combine to make [B*0 -> B*- pi-]cc
+    Bst_2 = ParticleCombiner(
+        Inputs=[Bstm, pions],
+        name=f'Bst_2_{lepton}',
+        DecayDescriptor='[B*0 -> B*- pi-]cc',
+        CombinationCut=cut_combine,
+        CompositeCut=F.ALL,
+        ParticleCombiner="ParticleVertexFitter",
+        PrimaryVertices=v2_pvs
+        #OutputLevel=1
+    )
+    #merge the two Bst candidates
+    Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
+    return Bst
 
 def get_functors(MCTRUTH, v2_pvs, rec_summary):
 	#define common variables for all fields (composite and basic)
@@ -291,7 +332,7 @@ def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
 	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
 	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
 	vars_Bst['iso_mva'] = mva_functor_mu_inclusive(v2_pvs)[0]
-	vars_Bst += trail_seeker(MCTRUTH)
+	if MCTRUTH != 'None': vars_Bst += trail_seeker(MCTRUTH)
 
 
 	#define fields
@@ -335,13 +376,13 @@ def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
 
 	#define fields
 	fields = {}
-	fields['B0']    = f'[B0 ->  (B- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
-	fields['Bm']    = f'[B0 -> ^(B- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
-	fields['D0']    = f'[B0 ->  (B- -> ^([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
-	fields['Lep']   = f'[B0 ->  (B- ->  ([D0 -> K- pi+]CC) ^{lepton}-)  [pi+]CC]CC'
-	fields['Epi']   = f'[B0 ->  (B- ->  ([D0 -> K- pi+]CC)  {lepton}-) ^[pi+]CC]CC'
-	fields['Km']   = f'[B0 ->  (B- ->  ([D0 -> ^K- pi+]CC)  {lepton}-) [pi+]CC]CC'
-	fields['pip']   = f'[B0 ->  (B- ->  ([D0 -> K- ^pi+]CC)  {lepton}-) [pi+]CC]CC'
+	fields['B0']    = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+	fields['Bm']    = f'[B*0 -> ^(B*- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+	fields['D0']    = f'[B*0 ->  (B*- -> ^([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+	fields['Lep']   = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC) ^{lepton}-)  [pi+]CC]CC'
+	fields['Epi']   = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC)  {lepton}-) ^[pi+]CC]CC'
+	fields['Km']   = f'[B*0 ->  (B*- ->  ([D0 -> ^K- pi+]CC)  {lepton}-) [pi+]CC]CC'
+	fields['pip']   = f'[B*0 ->  (B*- ->  ([D0 -> K- ^pi+]CC)  {lepton}-) [pi+]CC]CC'
     
 	#add variables
 	variables = {}
@@ -379,57 +420,83 @@ def get_extra_pions():
 									name='Pions_combiner')
 
 #def main(options):
-def main(options: Options,line = '', lep=''):
+def main(options: Options,line = '', lep='',data_or_mc='mc'):
+
+    #define filer
+    my_filter = create_lines_filter(name="Filter", lines=[line])
+
+    #get data and extra particles
+    Bm = get_particles(f"/Event/Spruce/{line}/Particles")
+    extra_particles = get_extra_pions()
+    #extra_particles = get_particles(f"/Event/Spruce/{line}/{line}_extra_tracks/Particles")
+
+    #get v2_pvs and rec_summary
+    v2_pvs  = get_pvs()
+    rec_summary = get_rec_summary()
+    hadron_candidate_id = 421
+    #make B0 candidate
+    Bst = make_Bst(Bm, extra_particles,lep,hadron_candidate_id,v2_pvs,False)
+
+    if data_or_mc == 'mc':
+        MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+        tuple_file = tuple_Bst(Bst,lep,line, MCTRUTH_Bst, v2_pvs, rec_summary)
+    elif data_or_mc == 'data':
+        tuple_file = tuple_Bst(Bst,lep,line, 'None', v2_pvs, rec_summary)
+    else:
+        raise ValueError(f"Decay channel {decay_channel} not supported")
+    #define algorithms
+    user_algorithms = {}
+    user_algorithms['Alg'] = [my_filter, tuple_file]
+
+    return make_config(options, user_algorithms)
 
-	#define filer
-	my_filter = create_lines_filter(name="Filter", lines=[line])
+def test(options: Options):
+	return main(options=options, line='Hlt2_Test_line',lep='e',data_or_mc='data')
 
-	#get data and extra particles
-	Bm = get_particles(f"/Event/Spruce/{line}/Particles")
-	extra_particles = get_extra_pions()
-	#extra_particles = get_particles(f"/Event/Spruce/{line}/{line}_extra_tracks/Particles")
+def MC_SLB_BuToD0ENu_D0ToKPi(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
 
-	#get v2_pvs and rec_summary
-	v2_pvs  = get_pvs()
-	rec_summary = get_rec_summary()
-	hadron_candidate_id = 421
-	#make B0 candidate
-	Bst = make_Bst(Bm, extra_particles,lep,hadron_candidate_id,v2_pvs,False)
-	MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+def MC_SLB_BuToDststENu(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
 
+def MC_SLB_BdToDststENu(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
 
-	tuple_file = tuple_Bst(Bst,lep,line, MCTRUTH_Bst, v2_pvs, rec_summary)
+def MC_SLB_BuToD0MuNu_D0ToKPi(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu',data_or_mc='mc')
 
-	#define algorithms
-	user_algorithms = {}
-	user_algorithms['Alg'] = [my_filter, tuple_file]
+def MC_SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
 
-	return make_config(options, user_algorithms)
+def MC_SLB_BuToDststTauNu_TauToENuNu(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
 
-def test(options: Options):
-	return main(options=options, line='Hlt2_Test_line',lep='e')
+def MC_SLB_BdToDststTauNu_TauToENuNu(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
 
-def SLB_BuToD0ENu_D0ToKPi(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
+def MC_SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu',data_or_mc='mc')
 
-def SLB_BuToDststENu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
+def Data_SLB_BuToD0ENu_D0ToKPi(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0ENu_D0ToKPi',lep='e',data_or_mc='data')
 
-def SLB_BdToDststENu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
+def Data_SLB_BuToD0MuNu_D0ToKPi(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu',data_or_mc='data')
 
-def SLB_BuToD0MuNu_D0ToKPi(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu')
+def Data_SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu',lep='e',data_or_mc='data')
 
-def SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
+def Data_SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu',data_or_mc='data')
 
-def SLB_BuToDststTauNu_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
+def Data_SLB_BuToD0ENu_D0ToKPi_FakeElectron(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0ENu_D0ToKPi_FakeElectron',lep='e',data_or_mc='data')
 
-def SLB_BdToDststTauNu_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e')
+def Data_SLB_BuToD0MuNu_D0ToKPi_FakeMuon(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi_FakeMuon',lep='mu',data_or_mc='data')
 
-def SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu')
+def Data_SLB_BuToD0TauNu_D0ToKPi_FakeElectron(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_FakeElectron',lep='e',data_or_mc='data')
 
+def Data_SLB_BuToD0TauNu_D0ToKPi_FakeMuon(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_FakeMuon',lep='mu',data_or_mc='data')
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Hlt1.py b/SL_l_nu_D0toKpi_Run3_MC_data/Hlt1.py
similarity index 100%
rename from SL_l_nu_D0toKpi_Run3_MC/Hlt1.py
rename to SL_l_nu_D0toKpi_Run3_MC_data/Hlt1.py
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py b/SL_l_nu_D0toKpi_Run3_MC_data/Hlt2.py
similarity index 99%
rename from SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
rename to SL_l_nu_D0toKpi_Run3_MC_data/Hlt2.py
index 40ddb823ea..be2bda5d70 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/Hlt2.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data/Hlt2.py
@@ -77,7 +77,7 @@ def get_electron_cuts():
     make_electron_cuts["pt_min"]          = 300. * MeV #300. * MeV (Now) 500. * MeV (v55r7)
     make_electron_cuts["mipchi2_min"]     = 9. #9. (Now) 9./16. (v55r7 e/taue) 
     make_electron_cuts["mip_min"]         = None #0.
-    make_electron_cuts["pid"]             = (F.PID_E > 0.0) 
+    make_electron_cuts["pid"]             = (F.PID_E > 0.) 
     make_electron_cuts["make_particles"]  = make_long_electrons_with_brem  #does not require in calo
     return make_electron_cuts
 
diff --git a/SL_l_nu_D0toKpi_Run3_MC/MC_Matcher.py b/SL_l_nu_D0toKpi_Run3_MC_data/MC_Matcher.py
similarity index 100%
rename from SL_l_nu_D0toKpi_Run3_MC/MC_Matcher.py
rename to SL_l_nu_D0toKpi_Run3_MC_data/MC_Matcher.py
diff --git a/SL_l_nu_D0toKpi_Run3_MC/Spruce.py b/SL_l_nu_D0toKpi_Run3_MC_data/Spruce.py
similarity index 100%
rename from SL_l_nu_D0toKpi_Run3_MC/Spruce.py
rename to SL_l_nu_D0toKpi_Run3_MC_data/Spruce.py
diff --git a/SL_l_nu_D0toKpi_Run3_MC/info.yaml b/SL_l_nu_D0toKpi_Run3_MC_data/info.yaml
similarity index 64%
rename from SL_l_nu_D0toKpi_Run3_MC/info.yaml
rename to SL_l_nu_D0toKpi_Run3_MC_data/info.yaml
index a77ff06360..18abc3e05c 100644
--- a/SL_l_nu_D0toKpi_Run3_MC/info.yaml
+++ b/SL_l_nu_D0toKpi_Run3_MC_data/info.yaml
@@ -22,6 +22,7 @@ defaults:
   {%- for evttype, line, dk in evttype_lines_and_leptons %}
 HLT1_{{dk}}_{{ polarity }}:
   application: "Moore/v55r7@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     bk_query: "/MC/Dev/Beam6800GeV-expected-2024-{{polarity}}-Nu7.6-25ns-Pythia8/Sim10c/{{evttype}}/DIGI"
     dq_flags:
@@ -29,7 +30,7 @@ HLT1_{{dk}}_{{ polarity }}:
     n_test_lfns: 1
   output: hlt1.dst
   options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC.Hlt1:main
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data.Hlt1:main
     extra_options:
       input_raw_format: 0.3
       conddb_tag: {{cond_tag}}
@@ -43,15 +44,16 @@ HLT1_{{dk}}_{{ polarity }}:
         algorithm: ZSTD
         level: 1
         max_buffer_size: 1048576
-      #evt_max: 1000 
+      evt_max: 1000 
 
 HLT2_{{dk}}_{{ polarity }}:
   application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     job_name: HLT1_{{dk}}_{{ polarity }}
   output: hlt2.dst
   options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC.Hlt2:main
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data.Hlt2:main
     extra_options:
       input_raw_format: 0.5
       conddb_tag: {{cond_tag}}
@@ -69,11 +71,12 @@ HLT2_{{dk}}_{{ polarity }}:
       #evt_max: 1000
 SPRUCE_{{dk}}_{{ polarity }}:
   application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     job_name: HLT2_{{dk}}_{{ polarity }}
   output: spruce.dst
   options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC.Spruce:main
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data.Spruce:main
     extra_options:
       input_raw_format: 0.5
       conddb_tag: {{cond_tag}}
@@ -97,7 +100,7 @@ DV_{{dk}}_{{ polarity }}:
     job_name: SPRUCE_{{dk}}_{{ polarity }}
   output: NTuple.root
   options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC.DV:{{line}}
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data.DV:MC_{{line}}
     extra_options:
       input_raw_format: 0.5
       conddb_tag: {{cond_tag}}
@@ -112,3 +115,41 @@ DV_{{dk}}_{{ polarity }}:
 
   {%- endfor %}
 {%- endfor %}
+
+
+{%- set lines_and_decays = [
+  ('SLB_BuToD0ENu_D0ToKPi','b0_dstp_e'),
+  ('SLB_BuToD0MuNu_D0ToKPi','b0_dstp_muon'),
+  ('SLB_BuToD0TauNu_D0ToKPi_TauToENuNu','b0_dstp_taue'),
+  ('SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu','b0_dstp_taumuon'),
+  ('SLB_BuToD0ENu_D0ToKPi_FakeElectron','b0_dstp_e_fake'),
+  ('SLB_BuToD0MuNu_D0ToKPi_FakeMuon','b0_dstp_muon_fake'),
+  ('SLB_BuToD0TauNu_D0ToKPi_FakeElectron','b0_dstp_taue_fake'),
+  ('SLB_BuToD0TauNu_D0ToKPi_FakeMuon','b0_dstp_taumuon_fake'),
+] %}
+
+{%- for spruce_line, decay in lines_and_decays %}
+data_{{decay}}:
+  application: "DaVinci/v64r5"
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-MagDown-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    keep_running: true
+    n_test_lfns: 1 
+  output: DATA.ROOT
+  options:
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data.DV:Data_{{spruce_line}}
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
+      simulation: False
+      #data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "sl" # for streamed data
+      #evt_max: 1000
+{%- endfor %}
+
-- 
GitLab


From ae8154388cf24ef85f32312f2db244e36f1d9ae7 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 24 Jun 2024 11:55:12 +0200
Subject: [PATCH 40/57] Fix info.yaml

---
 SL_l_nu_D0toKpi_Run3_MC_data/info.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data/info.yaml b/SL_l_nu_D0toKpi_Run3_MC_data/info.yaml
index 18abc3e05c..47634c4fa3 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data/info.yaml
+++ b/SL_l_nu_D0toKpi_Run3_MC_data/info.yaml
@@ -44,7 +44,7 @@ HLT1_{{dk}}_{{ polarity }}:
         algorithm: ZSTD
         level: 1
         max_buffer_size: 1048576
-      evt_max: 1000 
+      #evt_max: 1000 
 
 HLT2_{{dk}}_{{ polarity }}:
   application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
-- 
GitLab


From f2edf471b4f0217afc75bed48a7bab92f3ad9088 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 24 Jun 2024 12:48:12 +0200
Subject: [PATCH 41/57] remove brems variables for non-lepton particles

---
 SL_l_nu_D0toKpi_Run3_MC_data/DV.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data/DV.py b/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
index e71c5d49f3..1bb78a3745 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
@@ -391,9 +391,9 @@ def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
 	variables["Bm"]  = vars_composite
 	variables["D0"]  = vars_composite
 	variables["Lep"] = vars_basic + vars_brems
-	variables["Epi"] = vars_basic + vars_brems
-	variables["Km"] = vars_basic + vars_brems
-	variables["pip"] = vars_basic + vars_brems
+	variables["Epi"] = vars_basic
+	variables["Km"] = vars_basic
+	variables["pip"] = vars_basic
 
 	#define tuple
 	my_tuple = Funtuple(
-- 
GitLab


From 3a000d89fd5c23c21a8e755ea151c90c255c3627 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 24 Jun 2024 12:50:08 +0200
Subject: [PATCH 42/57] tighten D* mass cut

---
 SL_l_nu_D0toKpi_Run3_MC_data/DV.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data/DV.py b/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
index 1bb78a3745..0d0ab03967 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
@@ -87,7 +87,7 @@ def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = Tru
     Epi_child = F.CHILD(2, F.FORWARDARG0)
 
     #D* mass - D0 mass cut
-    cut_combine = F.require_all(((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))<200)
+    cut_combine = F.require_all(((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))<160)
 
     #combine to make [B*0 -> B*- pi+]cc
     Bst_1 = ParticleCombiner(
-- 
GitLab


From 1b98d561e95b11cac8a8a6f25a4b7135a5bc3257 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 24 Jun 2024 14:53:40 +0200
Subject: [PATCH 43/57] Try not to include mva in MC

---
 SL_l_nu_D0toKpi_Run3_MC_data/DV.py | 208 +++++++++++++++--------------
 1 file changed, 105 insertions(+), 103 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data/DV.py b/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
index 0d0ab03967..d4ad252f3c 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
@@ -288,75 +288,77 @@ def get_fitting_variable(v2_pvs,D0,lep):
 	return(vars_fitting)
 
 def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
-	#get functors
-	functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
-	vars_common = functors[0]
-	vars_composite = functors[1]
-	vars_basic = functors[2]
-	evt_vars = functors[3]
-	vars_brems = functors[4]
-
-	#variables for B0 field
-	vars_Bst  = FunctorCollection()
-	B_child   = F.CHILD(1, F.FORWARDARG0)
-	D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
-	Lep_child   = F.CHILD(1, F.CHILD(2,F.FORWARDARG0))
-	Epi_child = F.CHILD(2, F.FORWARDARG0)
-	bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
-	#diff in vtx chi2 with and without extra particle
-	vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
-	#IP and IPChi2 of extra particle wrt to B0 end vertex
-	vars_Bst['Epi_IP_WRT_B0ENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
-	vars_Bst['Epi_IPCHI2_WRT_B0ENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
-	#IP and IPChi2 of extra particle wrt to Bm end vertex
-	vars_Bst['Epi_IP_WRT_BmENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
-	vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
-	#angle between extra particle and Bm
-	vars_Bst['Epi_COSANGLE_Bm']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
-	#diff in fd chi2 with and without extra particle
-	vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
-	vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
-	#IP chi2 of extra particle wrt PV and SV of B0
-	vars_Bst['Epi_IP_WRT_B0BPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
-	vars_Bst['Epi_IPCHI2_WRT_B0BPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
-	#IP chi2 of extra particle wrt PV and SV of Bm
-	vars_Bst['Epi_IP_WRT_BmBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
-	vars_Bst['Epi_IPCHI2_WRT_BmBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
-	#DOCA and DOCACHI2 b/w Lb and extra particle
-	vars_Bst['DOCA12']       = F.DOCA(1, 2)
-	vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
-	#vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
-	#vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
-	#DOCACHI2 of extra particle wrt to mother i.e. B0
-	vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
-	vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
-	vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
-	vars_Bst['iso_mva'] = mva_functor_mu_inclusive(v2_pvs)[0]
-	if MCTRUTH != 'None': vars_Bst += trail_seeker(MCTRUTH)
-
-
-	#define fields
-	fit_vars = get_fitting_variable(v2_pvs,D0_child,Lep_child)
-	#TIS and TOS
-	Hlt1_decisions = ['Hlt1TrackMVA',
-	'Hlt1TwoTrackMVA',
-	'Hlt1D2KK',
-	'Hlt1D2KPi',
-	'Hlt1D2PiPi',
-	'Hlt1KsToPiPi',
-	'Hlt1TrackMuonMVA',
-	'Hlt1SingleHighPtMuon',
-	'Hlt1TrackElectronMVA',
-	'Hlt1SingleHighPtElectron',
-	'Hlt1DiElectronDisplaced',
-	'Hlt1DiPhotonHighMass',
-	'Hlt1Pi02GammaGamma',
-	'Hlt1DiElectronHighMass_SS',
-	'Hlt1DiElectronHighMass']
-	variables_tistos_hlt1 = FC.HltTisTos(selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=Bst)
-	evt_vars += FC.SelectionInfo(selection_type="Hlt1", trigger_lines=Hlt1_decisions)
-
-	Hlt2_decisions = ['Hlt2SLB_BuToD0MuNu_D0ToKPi',
+    #get functors
+    functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
+    vars_common = functors[0]
+    vars_composite = functors[1]
+    vars_basic = functors[2]
+    evt_vars = functors[3]
+    vars_brems = functors[4]
+
+    #variables for B0 field
+    vars_Bst  = FunctorCollection()
+    B_child   = F.CHILD(1, F.FORWARDARG0)
+    D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
+    Lep_child   = F.CHILD(1, F.CHILD(2,F.FORWARDARG0))
+    Epi_child = F.CHILD(2, F.FORWARDARG0)
+    bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+    #diff in vtx chi2 with and without extra particle
+    vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
+    #IP and IPChi2 of extra particle wrt to B0 end vertex
+    vars_Bst['Epi_IP_WRT_B0ENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_B0ENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+    #IP and IPChi2 of extra particle wrt to Bm end vertex
+    vars_Bst['Epi_IP_WRT_BmENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+    #angle between extra particle and Bm
+    vars_Bst['Epi_COSANGLE_Bm']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+    #diff in fd chi2 with and without extra particle
+    vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
+    vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+    #IP chi2 of extra particle wrt PV and SV of B0
+    vars_Bst['Epi_IP_WRT_B0BPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_B0BPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+    #IP chi2 of extra particle wrt PV and SV of Bm
+    vars_Bst['Epi_IP_WRT_BmBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_BmBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+    #DOCA and DOCACHI2 b/w Lb and extra particle
+    vars_Bst['DOCA12']       = F.DOCA(1, 2)
+    vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+    #vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
+    #vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
+    #DOCACHI2 of extra particle wrt to mother i.e. B0
+    vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
+    vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+    vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
+    #vars_Bst['iso_mva'] = mva_functor_mu_inclusive(v2_pvs)[0]
+    if MCTRUTH != 'None': 
+        vars_Bst += trail_seeker(MCTRUTH)
+    elif MCTRUTH == 'None':
+        vars_Bst['iso_mva'] = mva_functor_mu_inclusive(v2_pvs)[0]
+
+    #define fields
+    fit_vars = get_fitting_variable(v2_pvs,D0_child,Lep_child)
+    #TIS and TOS
+    Hlt1_decisions = ['Hlt1TrackMVA',
+    'Hlt1TwoTrackMVA',
+    'Hlt1D2KK',
+    'Hlt1D2KPi',
+    'Hlt1D2PiPi',
+    'Hlt1KsToPiPi',
+    'Hlt1TrackMuonMVA',
+    'Hlt1SingleHighPtMuon',
+    'Hlt1TrackElectronMVA',
+    'Hlt1SingleHighPtElectron',
+    'Hlt1DiElectronDisplaced',
+    'Hlt1DiPhotonHighMass',
+    'Hlt1Pi02GammaGamma',
+    'Hlt1DiElectronHighMass_SS',
+    'Hlt1DiElectronHighMass']
+    variables_tistos_hlt1 = FC.HltTisTos(selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=Bst)
+    evt_vars += FC.SelectionInfo(selection_type="Hlt1", trigger_lines=Hlt1_decisions)
+
+    Hlt2_decisions = ['Hlt2SLB_BuToD0MuNu_D0ToKPi',
     'Hlt2SLB_BuToD0MuNu_D0ToKPi_FakeMuon',
     'Hlt2SLB_BuToD0ENu_D0ToKPi',
     'Hlt2SLB_BuToD0ENu_D0ToKPi_FakeElectron',
@@ -370,42 +372,42 @@ def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
     'Hlt2Topo2Body',
     'Hlt2Topo3Body']
 
-	variables_tistos_hlt2 = FC.HltTisTos(selection_type="Hlt2", trigger_lines=Hlt2_decisions, data=Bst)
-	evt_vars += FC.SelectionInfo(selection_type="Hlt2", trigger_lines=Hlt2_decisions)
-
-
-	#define fields
-	fields = {}
-	fields['B0']    = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
-	fields['Bm']    = f'[B*0 -> ^(B*- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
-	fields['D0']    = f'[B*0 ->  (B*- -> ^([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
-	fields['Lep']   = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC) ^{lepton}-)  [pi+]CC]CC'
-	fields['Epi']   = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC)  {lepton}-) ^[pi+]CC]CC'
-	fields['Km']   = f'[B*0 ->  (B*- ->  ([D0 -> ^K- pi+]CC)  {lepton}-) [pi+]CC]CC'
-	fields['pip']   = f'[B*0 ->  (B*- ->  ([D0 -> K- ^pi+]CC)  {lepton}-) [pi+]CC]CC'
-    
-	#add variables
-	variables = {}
-	variables["ALL"] = vars_common + variables_tistos_hlt1 + variables_tistos_hlt2
-	variables["B0"]  = vars_composite + vars_Bst + fit_vars
-	variables["Bm"]  = vars_composite
-	variables["D0"]  = vars_composite
-	variables["Lep"] = vars_basic + vars_brems
-	variables["Epi"] = vars_basic
-	variables["Km"] = vars_basic
-	variables["pip"] = vars_basic
-
-	#define tuple
-	my_tuple = Funtuple(
-		name=f"Tuple",
-		tuple_name="DecayTree",
-		fields=fields,
-		variables=variables,
-		event_variables=evt_vars,
+    variables_tistos_hlt2 = FC.HltTisTos(selection_type="Hlt2", trigger_lines=Hlt2_decisions, data=Bst)
+    evt_vars += FC.SelectionInfo(selection_type="Hlt2", trigger_lines=Hlt2_decisions)
+
+
+    #define fields
+    fields = {}
+    fields['B0']    = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+    fields['Bm']    = f'[B*0 -> ^(B*- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+    fields['D0']    = f'[B*0 ->  (B*- -> ^([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+    fields['Lep']   = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC) ^{lepton}-)  [pi+]CC]CC'
+    fields['Epi']   = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC)  {lepton}-) ^[pi+]CC]CC'
+    fields['Km']   = f'[B*0 ->  (B*- ->  ([D0 -> ^K- pi+]CC)  {lepton}-) [pi+]CC]CC'
+    fields['pip']   = f'[B*0 ->  (B*- ->  ([D0 -> K- ^pi+]CC)  {lepton}-) [pi+]CC]CC'
+
+    #add variables
+    variables = {}
+    variables["ALL"] = vars_common + variables_tistos_hlt1 + variables_tistos_hlt2
+    variables["B0"]  = vars_composite + vars_Bst + fit_vars
+    variables["Bm"]  = vars_composite
+    variables["D0"]  = vars_composite
+    variables["Lep"] = vars_basic + vars_brems
+    variables["Epi"] = vars_basic
+    variables["Km"] = vars_basic
+    variables["pip"] = vars_basic
+
+    #define tuple
+    my_tuple = Funtuple(
+        name=f"Tuple",
+        tuple_name="DecayTree",
+        fields=fields,
+        variables=variables,
+        event_variables=evt_vars,
         store_multiple_cand_info=True,
-		inputs=Bst)
+        inputs=Bst)
 
-	return my_tuple
+    return my_tuple
 
 def get_extra_pions():
 	"""
-- 
GitLab


From 644a3835b05ed5dc462aa337646cd10712102a9a Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Wed, 10 Jul 2024 21:31:22 +0200
Subject: [PATCH 44/57] add everything

---
 SL_l_nu_D0toKpi_Run3_MC_data/DV.py         | 504 ---------------------
 SL_l_nu_D0toKpi_Run3_MC_data/Hlt1.py       |  18 -
 SL_l_nu_D0toKpi_Run3_MC_data/Hlt2.py       | 155 -------
 SL_l_nu_D0toKpi_Run3_MC_data/MC_Matcher.py |  26 --
 SL_l_nu_D0toKpi_Run3_MC_data/Spruce.py     |  58 ---
 SL_l_nu_D0toKpi_Run3_MC_data/info.yaml     | 155 -------
 lb_lc_mu_2024data/DV.py                    | 299 ++++++++++++
 lb_lc_mu_2024data/info.yaml                |  28 ++
 8 files changed, 327 insertions(+), 916 deletions(-)
 delete mode 100644 SL_l_nu_D0toKpi_Run3_MC_data/DV.py
 delete mode 100644 SL_l_nu_D0toKpi_Run3_MC_data/Hlt1.py
 delete mode 100644 SL_l_nu_D0toKpi_Run3_MC_data/Hlt2.py
 delete mode 100644 SL_l_nu_D0toKpi_Run3_MC_data/MC_Matcher.py
 delete mode 100644 SL_l_nu_D0toKpi_Run3_MC_data/Spruce.py
 delete mode 100644 SL_l_nu_D0toKpi_Run3_MC_data/info.yaml
 create mode 100644 lb_lc_mu_2024data/DV.py
 create mode 100644 lb_lc_mu_2024data/info.yaml

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data/DV.py b/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
deleted file mode 100644
index d4ad252f3c..0000000000
--- a/SL_l_nu_D0toKpi_Run3_MC_data/DV.py
+++ /dev/null
@@ -1,504 +0,0 @@
-import sys,os,math
-from PyConf.reading import get_pvs, get_rec_summary, get_particles
-from PyConf.Algorithms import ThOrParticleSelection
-import Functors as F
-from FunTuple import FunctorCollection
-from FunTuple import FunTuple_Particles as Funtuple
-from DaVinci.algorithms import create_lines_filter
-from DaVinci import Options,make_config
-import FunTuple.functorcollections as FC
-from DaVinciMCTools import MCTruthAndBkgCat
-from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
-from Hlt2Conf.algorithms_thor import ParticleContainersMerger
-from Functors.grammar import Functor
-from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
-import numpy as np
-from Hlt2Conf.lines.semileptonic.isolationMVA import mva_functor_e_inclusive,mva_functor_mu_inclusive
-from .MC_Matcher import trail_seeker
-
-_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
-_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
-_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
-ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
-ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
-ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
-
-TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
-
-def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
-    if do_truth_matching == True :
-        #filter B keeping only true D0 and true leptons
-        MCTRUTH_B = MCTruthAndBkgCat(B, name='MCTRUTH_Bu')
-        Dz_child  = F.CHILD(1, F.FORWARDARG0) #get the first child of B*- which is D0
-        lep_child = F.CHILD(2, F.FORWARDARG0) #get the second child of B*- which is lepton
-        Dz_truth_cut  = TRUE_ID_IS(hadron_candidate_id, MCTRUTH_B) @ Dz_child #require that D0 is true
-        lep_truth_cut = F.require_any(TRUE_ID_IS(11, MCTRUTH_B) @ lep_child , TRUE_ID_IS(13, MCTRUTH_B) @ lep_child) #require that lepton is true i.e. electron or muon
-        cut_b    = F.require_all(Dz_truth_cut, lep_truth_cut) #make a cut
-        signal_B = ParticleFilter(Input=B, Cut=F.FILTER(cut_b), name='signal_Dzmu') #filter the B candidates
-    else : signal_B = B
-
-    hadron_cut = F.IS_ABS_ID('D0')  # Getting the hadron candidates
-
-    code_hadron = F.FILTER(hadron_cut) @ F.GET_CHILDREN()
-    hadron_TES = ThOrParticleSelection(
-        name="hadron_iso",
-        InputParticles=signal_B,
-        Functor=code_hadron).OutputSelection
-
-    lepton_cut = F.IS_ABS_ID(f'{lepton}-')
-    code_lepton = F.FILTER(lepton_cut) @ F.GET_CHILDREN()
-    lepton_TES = ThOrParticleSelection(
-        name="lepton_iso",
-        InputParticles=signal_B,
-        Functor=code_lepton).OutputSelection
-
-
-    #combine to make [B*- -> D0 lep-]cc
-    Bstm_1 = ParticleCombiner(
-        Inputs=[hadron_TES, lepton_TES],
-        name=f'Bstm_1_{lepton}',
-        DecayDescriptor=f'[B*- -> D0 {lepton}-]cc',
-        CombinationCut=F.ALL,
-        CompositeCut=F.ALL,
-        ParticleCombiner="ParticleVertexFitter",
-        #PrimaryVertices=v2_pvs
-        #OutputLevel=1
-    )
-    #combine to make [B*+ -> D0 lep+]cc
-    Bstm_2 = ParticleCombiner(
-        Inputs=[hadron_TES, lepton_TES],
-        name=f'Bstm_2_{lepton}',
-        DecayDescriptor=f'[B*+ -> D0 {lepton}+]cc',
-        CombinationCut=F.ALL,
-        CompositeCut=F.ALL,
-        ParticleCombiner="ParticleVertexFitter",
-        #PrimaryVertices=v2_pvs
-        #OutputLevel=1
-    )
-    Bstm = ParticleContainersMerger([Bstm_1, Bstm_2], name = f'Bstm_combiner_{lepton}')
-
-    D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
-    Epi_child = F.CHILD(2, F.FORWARDARG0)
-
-    #D* mass - D0 mass cut
-    cut_combine = F.require_all(((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))<160)
-
-    #combine to make [B*0 -> B*- pi+]cc
-    Bst_1 = ParticleCombiner(
-        Inputs=[Bstm, pions],
-        name=f'Bst_1_{lepton}',
-        DecayDescriptor='[B*0 -> B*- pi+]cc',
-        CombinationCut=cut_combine,
-        CompositeCut=F.ALL,
-        ParticleCombiner="ParticleVertexFitter",
-        PrimaryVertices=v2_pvs
-        #OutputLevel=1
-    )
-    #combine to make [B*0 -> B*- pi-]cc
-    Bst_2 = ParticleCombiner(
-        Inputs=[Bstm, pions],
-        name=f'Bst_2_{lepton}',
-        DecayDescriptor='[B*0 -> B*- pi-]cc',
-        CombinationCut=cut_combine,
-        CompositeCut=F.ALL,
-        ParticleCombiner="ParticleVertexFitter",
-        PrimaryVertices=v2_pvs
-        #OutputLevel=1
-    )
-    #merge the two Bst candidates
-    Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
-    return Bst
-
-def get_functors(MCTRUTH, v2_pvs, rec_summary):
-	#define common variables for all fields (composite and basic)
-	vars_common  = FunctorCollection()
-	#all pvs: ip, ipchi2. The PV positions are stored in event variables
-	vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
-	vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
-	#best pv: x, y, z, ip, ipchi2
-	vars_common['BPV_X']          = F.BPVX(v2_pvs)
-	vars_common['BPV_Y']          = F.BPVY(v2_pvs)
-	vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
-	vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
-	vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
-	vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
-	vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
-	#particle id, key, truekey. The trueid is stored in MCHierarchy
-	vars_common['ID']            = F.PARTICLE_ID
-	vars_common['KEY']           = F.OBJECT_KEY
-
-	#get charge, min ip and min ipchi2
-	vars_common['CHARGE']        = F.CHARGE
-	vars_common['MINIP']         = F.MINIP(v2_pvs)
-	vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
-	#reco kinematics
-	vars_common += FC.Kinematics()
-	vars_common['ETA']           = F.ETA
-	vars_common['PHI']           = F.PHI
-	if MCTRUTH != 'None':
-		#mc vars
-		vars_common['BKGCAT'] = MCTRUTH.BkgCat
-		vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
-		vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
-		vars_common['TRUEETA'] = MCTRUTH(F.ETA)
-		vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
-		#type of the origin vertex
-		vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
-		#make some helper functions
-		MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
-		MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
-		vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
-		vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
-		vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
-		vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
-		for i in range(2,14):
-		  prefix = "MC_GD_MOTHER_{}".format(i)
-		  vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
-		  vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
-
-	#variables for composite particles
-	vars_composite  = FunctorCollection()
-	#end vertex position and end vertex chi2
-	vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
-	vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
-	vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
-	#all pvs: dira, fd, fdchi2
-	vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
-	vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
-	vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
-	vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
-	vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
-	vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
-	vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
-	vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
-	#best pv: dira, fd, fdchi2, corrm, ltime, dls
-	vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
-	vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
-	vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
-	vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
-	vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
-	vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
-
-	#mc composite vertex information
-	if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
-	#Compute maximum DOCA and maximum DOCACHI2. Since there are 
-	# only two daughters of B0 particles, the maximum DOCA/DOCACHI2 is 
-	# the DOCA/DOCACHI2 see below.
-	vars_composite['MAX_DOCA'] = F.MAXDOCA
-	vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
-	vars_composite['MAX_SDOCA'] = F.MAXSDOCA
-	vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
-
-	#variables for basics
-	vars_basic  = FunctorCollection()
-	vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
-	vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
-	vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
-	vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
-	vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
-	vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
-	vars_basic['GHOSTPROB'] = F.GHOSTPROB
-	vars_basic['NHITS'] = F.VALUE_OR(-1) @F.NHITS @ F.TRACK
-	vars_basic['NUTHITS'] = F.VALUE_OR(-1) @F.NUTHITS @ F.TRACK
-	vars_basic['NVPHITS'] = F.VALUE_OR(-1) @F.NVPHITS @ F.TRACK
-	vars_basic['NFTHITS'] = F.VALUE_OR(-1) @ F.NFTHITS @ F.TRACK
-	vars_basic['TRACKHASUT'] = F.VALUE_OR(-1) @ F.TRACKHASUT @ F.TRACK
-	vars_basic['TRACKHASVELO'] = F.VALUE_OR(-1) @ F.TRACKHASVELO @ F.TRACK
-	vars_basic['PIDpi'] = F.PID_PI
-	vars_basic['PIDk']  = F.PID_K
-	vars_basic['PIDp']  = F.PID_P
-	vars_basic['PIDe']  = F.PID_E
-	vars_basic['PIDmu'] = F.PID_MU
-	vars_basic['PROBNNe'] = F.PROBNN_E
-	vars_basic['PROBNNpi'] = F.PROBNN_PI
-	vars_basic['PROBNNk'] = F.PROBNN_K
-	vars_basic['PROBNNmu'] = F.PROBNN_MU
-	vars_basic['PROBNNp'] = F.PROBNN_P
-	vars_basic['PROBNNghost'] = F.PROBNN_GHOST
-	if MCTRUTH != 'None': vars_basic += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
-
-	#variables for event
-	#Collection includes tis_tos, nPVs,nHits/clusters,BUNCHCROSSING and GPS var
-	evt_collections = [
-		FC.EventInfo(),
-		FC.RecSummary(),
-	]
-	evt_vars = FunctorCollection({})
-	evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
-	evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
-	evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
-	evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
-	evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
-
-	for coll in evt_collections:evt_vars += coll
-
-	vars_brems = FunctorCollection({})
-	vars_brems.update({"HASBREM": F.HASBREM})
-	#vars_brems.update({"HASBREMADDED": F.HASBREMADDED})
-	vars_brems.update({"BREMENERGY": F.BREMENERGY})
-	vars_brems.update({"BREMBENDCORR": F.BREMBENDCORR})
-	vars_brems.update({"BREMPIDE": F.BREMPIDE})
-	vars_brems.update({"ECALPIDE": F.ECALPIDE})
-	vars_brems.update({"ECALPIDMU": F.ECALPIDMU})
-	vars_brems.update({"HCALPIDE": F.HCALPIDE})
-	vars_brems.update({"HCALPIDMU": F.HCALPIDMU})
-	vars_brems.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
-	vars_brems.update({"ELECTRONSHOWERDLL": F.ELECTRONSHOWERDLL})
-	vars_brems.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2})
-	vars_brems.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2})
-	vars_brems.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2})
-	vars_brems.update({"ELECTRONENERGY": F.ELECTRONENERGY})
-	vars_brems.update({"BREMHYPOENERGY": F.BREMHYPOENERGY})
-	vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
-	#vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
-	vars_brems.update({"INBREM": F.INBREM})
-	vars_brems.update({"INECAL": F.INECAL})
-	vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
-	vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
-
-	#return all functors
-	functors = (vars_common, vars_composite, vars_basic, evt_vars,vars_brems)
-	return functors
-
-def get_fitting_variable(v2_pvs,D0,lep):
-
-	B_dis = np.array([F.END_VX-F.BPVX(v2_pvs),F.END_VY-F.BPVY(v2_pvs),F.END_VZ-F.BPVZ(v2_pvs)])
-	B_dis_mag = F.SQRT @ (B_dis[0]**2+B_dis[1]**2+B_dis[2]**2)
-	B_Mod_P = F.ABS @ ((5279.65/F.MASS)*F.PZ/(B_dis[2]/B_dis_mag))
-	B_Mod_E = F.SQRT @ (B_Mod_P**2 + 5279.65**2)
-	B_4P = np.array([B_Mod_P*B_dis[0]/B_dis_mag,B_Mod_P*B_dis[1]/B_dis_mag,B_Mod_P*B_dis[2]/B_dis_mag,B_Mod_E])
-	D_4P = np.array([F.PX @ D0,F.PY @ D0,F.PZ @ D0,F.ENERGY @ D0])
-	lep_4P = np.array([F.PX @ lep,F.PY @ lep,F.PZ @ lep,F.ENERGY @ lep])
-
-	vars_fitting = FunctorCollection({})
-	vars_fitting["Mod_P"] = B_Mod_P
-	vars_fitting['missing_m2'] = (B_4P[3]-D_4P[3]-lep_4P[3])**2-(B_4P[0]-D_4P[0]-lep_4P[0])**2-(B_4P[1]-D_4P[1]-lep_4P[1])**2-(B_4P[2]-D_4P[2]-lep_4P[2])**2
-	vars_fitting['q2'] = (B_4P[3]-D_4P[3])**2-(B_4P[0]-D_4P[0])**2-(B_4P[1]-D_4P[1])**2-(B_4P[2]-D_4P[2])**2
-	B_Beta = B_Mod_P/B_Mod_E
-	B_gamma = 1/F.SQRT @ (1-B_Beta**2)
-
-	B_Lorentz = [[B_gamma,-1*B_gamma*B_4P[0]/B_4P[3],-1*B_gamma*B_4P[1]/B_4P[3],-1*B_gamma*B_4P[2]/B_4P[3]],[-1*B_gamma*B_4P[0]/B_4P[3],1+(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[0]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)],[-1*B_gamma*B_4P[1]/B_4P[3],(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)],[-1*B_gamma*B_4P[2]/B_4P[3],(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[2]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)]]
-	vars_fitting['lep_E_Brest'] = (B_Lorentz[0][0]*lep_4P[3]+B_Lorentz[0][1]*lep_4P[0]+B_Lorentz[0][2]*lep_4P[1]+B_Lorentz[0][3]*lep_4P[2])
-	return(vars_fitting)
-
-def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
-    #get functors
-    functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
-    vars_common = functors[0]
-    vars_composite = functors[1]
-    vars_basic = functors[2]
-    evt_vars = functors[3]
-    vars_brems = functors[4]
-
-    #variables for B0 field
-    vars_Bst  = FunctorCollection()
-    B_child   = F.CHILD(1, F.FORWARDARG0)
-    D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
-    Lep_child   = F.CHILD(1, F.CHILD(2,F.FORWARDARG0))
-    Epi_child = F.CHILD(2, F.FORWARDARG0)
-    bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
-    #diff in vtx chi2 with and without extra particle
-    vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
-    #IP and IPChi2 of extra particle wrt to B0 end vertex
-    vars_Bst['Epi_IP_WRT_B0ENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
-    vars_Bst['Epi_IPCHI2_WRT_B0ENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
-    #IP and IPChi2 of extra particle wrt to Bm end vertex
-    vars_Bst['Epi_IP_WRT_BmENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
-    vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
-    #angle between extra particle and Bm
-    vars_Bst['Epi_COSANGLE_Bm']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
-    #diff in fd chi2 with and without extra particle
-    vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
-    vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
-    #IP chi2 of extra particle wrt PV and SV of B0
-    vars_Bst['Epi_IP_WRT_B0BPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
-    vars_Bst['Epi_IPCHI2_WRT_B0BPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
-    #IP chi2 of extra particle wrt PV and SV of Bm
-    vars_Bst['Epi_IP_WRT_BmBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
-    vars_Bst['Epi_IPCHI2_WRT_BmBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
-    #DOCA and DOCACHI2 b/w Lb and extra particle
-    vars_Bst['DOCA12']       = F.DOCA(1, 2)
-    vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
-    #vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
-    #vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
-    #DOCACHI2 of extra particle wrt to mother i.e. B0
-    vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
-    vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
-    vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
-    #vars_Bst['iso_mva'] = mva_functor_mu_inclusive(v2_pvs)[0]
-    if MCTRUTH != 'None': 
-        vars_Bst += trail_seeker(MCTRUTH)
-    elif MCTRUTH == 'None':
-        vars_Bst['iso_mva'] = mva_functor_mu_inclusive(v2_pvs)[0]
-
-    #define fields
-    fit_vars = get_fitting_variable(v2_pvs,D0_child,Lep_child)
-    #TIS and TOS
-    Hlt1_decisions = ['Hlt1TrackMVA',
-    'Hlt1TwoTrackMVA',
-    'Hlt1D2KK',
-    'Hlt1D2KPi',
-    'Hlt1D2PiPi',
-    'Hlt1KsToPiPi',
-    'Hlt1TrackMuonMVA',
-    'Hlt1SingleHighPtMuon',
-    'Hlt1TrackElectronMVA',
-    'Hlt1SingleHighPtElectron',
-    'Hlt1DiElectronDisplaced',
-    'Hlt1DiPhotonHighMass',
-    'Hlt1Pi02GammaGamma',
-    'Hlt1DiElectronHighMass_SS',
-    'Hlt1DiElectronHighMass']
-    variables_tistos_hlt1 = FC.HltTisTos(selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=Bst)
-    evt_vars += FC.SelectionInfo(selection_type="Hlt1", trigger_lines=Hlt1_decisions)
-
-    Hlt2_decisions = ['Hlt2SLB_BuToD0MuNu_D0ToKPi',
-    'Hlt2SLB_BuToD0MuNu_D0ToKPi_FakeMuon',
-    'Hlt2SLB_BuToD0ENu_D0ToKPi',
-    'Hlt2SLB_BuToD0ENu_D0ToKPi_FakeElectron',
-    'Hlt2SLB_B0ToDpTauNu_DpToKPiPi_TauToENuNu',
-    'Hlt2SLB_B0ToDpTauNu_DpToKPiPi_TauToMuNuNu',
-    'Hlt2SLB_BuToD0TauNu_D0ToKPi_TauToENuNu',
-    'Hlt2SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',
-    'Hlt2SLB_BuToD0TauNu_D0ToKPi_FakeMuon',
-    'Hlt2SLB_BuToD0TauNu_D0ToKPi_FakeElectron',
-    'Hlt2SLB_myBuToD0ENu_D0ToKPi',
-    'Hlt2Topo2Body',
-    'Hlt2Topo3Body']
-
-    variables_tistos_hlt2 = FC.HltTisTos(selection_type="Hlt2", trigger_lines=Hlt2_decisions, data=Bst)
-    evt_vars += FC.SelectionInfo(selection_type="Hlt2", trigger_lines=Hlt2_decisions)
-
-
-    #define fields
-    fields = {}
-    fields['B0']    = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
-    fields['Bm']    = f'[B*0 -> ^(B*- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
-    fields['D0']    = f'[B*0 ->  (B*- -> ^([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
-    fields['Lep']   = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC) ^{lepton}-)  [pi+]CC]CC'
-    fields['Epi']   = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC)  {lepton}-) ^[pi+]CC]CC'
-    fields['Km']   = f'[B*0 ->  (B*- ->  ([D0 -> ^K- pi+]CC)  {lepton}-) [pi+]CC]CC'
-    fields['pip']   = f'[B*0 ->  (B*- ->  ([D0 -> K- ^pi+]CC)  {lepton}-) [pi+]CC]CC'
-
-    #add variables
-    variables = {}
-    variables["ALL"] = vars_common + variables_tistos_hlt1 + variables_tistos_hlt2
-    variables["B0"]  = vars_composite + vars_Bst + fit_vars
-    variables["Bm"]  = vars_composite
-    variables["D0"]  = vars_composite
-    variables["Lep"] = vars_basic + vars_brems
-    variables["Epi"] = vars_basic
-    variables["Km"] = vars_basic
-    variables["pip"] = vars_basic
-
-    #define tuple
-    my_tuple = Funtuple(
-        name=f"Tuple",
-        tuple_name="DecayTree",
-        fields=fields,
-        variables=variables,
-        event_variables=evt_vars,
-        store_multiple_cand_info=True,
-        inputs=Bst)
-
-    return my_tuple
-
-def get_extra_pions():
-	"""
-	Note this function in DaVinci requires:
-	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
-	and it's related LHCb, DaVinci and Rec MRs
-	"""
-	long_pions = make_has_rich_long_pions()
-	up_pions = make_has_rich_up_pions()
-	down_pions = make_has_rich_down_pions()
-	return ParticleContainersMerger([long_pions, up_pions, down_pions],
-									name='Pions_combiner')
-
-#def main(options):
-def main(options: Options,line = '', lep='',data_or_mc='mc'):
-
-    #define filer
-    my_filter = create_lines_filter(name="Filter", lines=[line])
-
-    #get data and extra particles
-    Bm = get_particles(f"/Event/Spruce/{line}/Particles")
-    extra_particles = get_extra_pions()
-    #extra_particles = get_particles(f"/Event/Spruce/{line}/{line}_extra_tracks/Particles")
-
-    #get v2_pvs and rec_summary
-    v2_pvs  = get_pvs()
-    rec_summary = get_rec_summary()
-    hadron_candidate_id = 421
-    #make B0 candidate
-    Bst = make_Bst(Bm, extra_particles,lep,hadron_candidate_id,v2_pvs,False)
-
-    if data_or_mc == 'mc':
-        MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
-        tuple_file = tuple_Bst(Bst,lep,line, MCTRUTH_Bst, v2_pvs, rec_summary)
-    elif data_or_mc == 'data':
-        tuple_file = tuple_Bst(Bst,lep,line, 'None', v2_pvs, rec_summary)
-    else:
-        raise ValueError(f"Decay channel {decay_channel} not supported")
-    #define algorithms
-    user_algorithms = {}
-    user_algorithms['Alg'] = [my_filter, tuple_file]
-
-    return make_config(options, user_algorithms)
-
-def test(options: Options):
-	return main(options=options, line='Hlt2_Test_line',lep='e',data_or_mc='data')
-
-def MC_SLB_BuToD0ENu_D0ToKPi(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
-
-def MC_SLB_BuToDststENu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
-
-def MC_SLB_BdToDststENu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
-
-def MC_SLB_BuToD0MuNu_D0ToKPi(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu',data_or_mc='mc')
-
-def MC_SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
-
-def MC_SLB_BuToDststTauNu_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
-
-def MC_SLB_BdToDststTauNu_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
-
-def MC_SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu',data_or_mc='mc')
-
-def Data_SLB_BuToD0ENu_D0ToKPi(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0ENu_D0ToKPi',lep='e',data_or_mc='data')
-
-def Data_SLB_BuToD0MuNu_D0ToKPi(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu',data_or_mc='data')
-
-def Data_SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu',lep='e',data_or_mc='data')
-
-def Data_SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu',data_or_mc='data')
-
-def Data_SLB_BuToD0ENu_D0ToKPi_FakeElectron(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0ENu_D0ToKPi_FakeElectron',lep='e',data_or_mc='data')
-
-def Data_SLB_BuToD0MuNu_D0ToKPi_FakeMuon(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi_FakeMuon',lep='mu',data_or_mc='data')
-
-def Data_SLB_BuToD0TauNu_D0ToKPi_FakeElectron(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_FakeElectron',lep='e',data_or_mc='data')
-
-def Data_SLB_BuToD0TauNu_D0ToKPi_FakeMuon(options: Options):
-	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_FakeMuon',lep='mu',data_or_mc='data')
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data/Hlt1.py b/SL_l_nu_D0toKpi_Run3_MC_data/Hlt1.py
deleted file mode 100644
index eeabcc4913..0000000000
--- a/SL_l_nu_D0toKpi_Run3_MC_data/Hlt1.py
+++ /dev/null
@@ -1,18 +0,0 @@
-###############################################################################
-# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
-#                                                                             #
-# This software is distributed under the terms of the GNU General Public      #
-# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
-#                                                                             #
-# In applying this licence, CERN does not waive the privileges and immunities #
-# granted to it by virtue of its status as an Intergovernmental Organization  #
-# or submit itself to any jurisdiction.                                       #
-###############################################################################
-from Moore import Options
-from Moore.config import run_allen
-from RecoConf.hlt1_allen import allen_gaudi_config as allen_sequence
-
-def main(options: Options):
-    with allen_sequence.bind(sequence="hlt1_pp_matching_no_ut_1000KHz"):
-        return run_allen(options)
-
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data/Hlt2.py b/SL_l_nu_D0toKpi_Run3_MC_data/Hlt2.py
deleted file mode 100644
index be2bda5d70..0000000000
--- a/SL_l_nu_D0toKpi_Run3_MC_data/Hlt2.py
+++ /dev/null
@@ -1,155 +0,0 @@
-###############################################################################
-# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
-#                                                                             #
-# This software is distributed under the terms of the GNU General Public      #
-# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
-#                                                                             #
-# In applying this licence, CERN does not waive the privileges and immunities #
-# granted to it by virtue of its status as an Intergovernmental Organization  #
-# or submit itself to any jurisdiction.                                       #
-###############################################################################
-"""
-Stolen and adapted from Hlt/Hlt2Conf/options/hlt2_pp_expected_24_without_UT.py from v55r7.
-"""
-from Moore import Options,options, run_moore, config
-from Hlt2Conf.algorithms_thor import ParticleContainersMerger
-from Hlt2Conf.lines.semileptonic.builders import sl_line_prefilter
-from Hlt2Conf.lines.semileptonic.builders.base_builder import make_candidate
-from Hlt2Conf.lines.semileptonic.builders.charm_hadron_builder import make_d0_tokpi
-from GaudiKernel.SystemOfUnits import MeV, GeV,mm
-from Hlt2Conf.algorithms_thor import ParticleCombiner
-from Hlt2Conf.settings.defaults import get_default_hlt1_filter_code_for_hlt2
-from Hlt2Conf.lines.semileptonic import all_lines as slb_lines  
-from Hlt2Conf.lines.topological_b import all_lines as topo_lines
-from Moore.config import Hlt2Line,register_line_builder
-from Moore.streams import Stream, Streams, DETECTORS
-from RecoConf.event_filters import require_gec
-from RecoConf.global_tools import stateProvider_with_simplified_geom, trackMasterExtrapolator_with_simplified_geom
-from RecoConf.hlt2_global_reco import reconstruction as hlt2_reconstruction, make_light_reco_pr_kf_without_UT
-from RecoConf.reconstruction_objects import reconstruction,make_pvs
-from RecoConf.decoders import default_ft_decoding_version,default_VeloCluster_source
-from RecoConf.hlt2_tracking import (
-    make_TrackBestTrackCreator_tracks,
-    make_PrKalmanFilter_noUT_tracks,
-    make_PrKalmanFilter_Velo_tracks,
-    make_PrKalmanFilter_Seed_tracks,
-)
-from Hlt2Conf.standard_particles import (
-    make_long_electrons_with_brem,
-    make_has_rich_long_pions, 
-    make_has_rich_up_pions, 
-    make_has_rich_down_pions)
-import Functors as F
-from Functors.math import in_range
-import sys
-
-#things to control
-SUFFIX_NAME = '_BToDzl'
-HLT2LINE = f'Hlt2SLB_myBuToD0ENu_D0ToKPi'
-CHARM_MASS = 1864.84 #D0 mass
-CHARM_BUILDER_NAME = 'Dz2KPi_combiner'
-B_BUILDER_NAME     = 'BToDzl_combiner'
-
-def get_charm_cuts():
-    #make loose cuts for D0
-    delta_mass   = 80. #80.0
-    make_d0tokpi_cuts  = {}
-    make_d0tokpi_cuts['comb_m_min']            = (CHARM_MASS - delta_mass) * MeV
-    make_d0tokpi_cuts['comb_m_max']            = (CHARM_MASS + delta_mass) * MeV
-    make_d0tokpi_cuts['comb_docachi2_max']     = 5.
-    make_d0tokpi_cuts['vchi2pdof_max']         = 6   #6 (Now) 6/4 (v55r7 e/taue)
-    make_d0tokpi_cuts['bpvfdchi2_min']         = 25  #25 (Now)
-    make_d0tokpi_cuts['bpvdira_min']           = 0.99  #0.99 (Now) 0.99/0.999 (v55r7 e/taue)
-    make_d0tokpi_cuts['comb_pt_min']           = None #None (Now) None/2000 * MeV (v55r7 e/taue)
-    make_d0tokpi_cuts['comb_pt_any_min']       = None #None (Now) None/800 * MeV (v55r7 e/taue)
-    make_d0tokpi_cuts['comb_pt_sum_min']       = None #None (Now) None/2.5 * GeV (v55r7 e/taue)
-    make_d0tokpi_cuts['comb_doca_max']         = None #None (Now) None/0.1 mm (v55r7 e/taue)
-    make_d0tokpi_cuts['daughter_pt_min']       = 600 * MeV #600 * MeV (Now) 750 * MeV (v55r7)
-    make_d0tokpi_cuts['daughter_mipchi2_min']  = 9. #10. (Now) 10./9. (v55r7 e/taue)
-    make_d0tokpi_cuts['kaon_pid']              = (F.PID_K > 0.) #(F.PID_K > 0.) (Now) (F.PID_K > 4.) (v55r7) 
-    make_d0tokpi_cuts['pion_pid']              = (F.PID_K < 2.)
-    return make_d0tokpi_cuts
-
-def get_electron_cuts():
-    #make loose cuts for electron and tauonic muon
-    make_electron_cuts = {}
-    make_electron_cuts["p_min"]           = 3. * GeV #3. * GeV (Now) 5. *GeV (v55r7)
-    make_electron_cuts["pt_min"]          = 300. * MeV #300. * MeV (Now) 500. * MeV (v55r7)
-    make_electron_cuts["mipchi2_min"]     = 9. #9. (Now) 9./16. (v55r7 e/taue) 
-    make_electron_cuts["mip_min"]         = None #0.
-    make_electron_cuts["pid"]             = (F.PID_E > 0.) 
-    make_electron_cuts["make_particles"]  = make_long_electrons_with_brem  #does not require in calo
-    return make_electron_cuts
-
-def make_b():
-    make_d0tokpi_cuts = get_charm_cuts()
-    make_electron_cuts= get_electron_cuts()
-    pvs = make_pvs()
-    with make_candidate.bind(p_min=15. * GeV): 
-        dzs = make_d0_tokpi(**make_d0tokpi_cuts, name = CHARM_BUILDER_NAME)
-    electrons = make_candidate(**make_electron_cuts, name = "Electron_maker")
-
-    cut_vertex = F.require_all(F.CHI2DOF<9,F.BPVDIRA(pvs) >0.999,in_range(0 * MeV, F.MASS, 10000 * MeV))
-
-    rs_btodze  =  ParticleCombiner(
-        Inputs=[dzs, electrons],
-        name=f'rs_{B_BUILDER_NAME}_e',
-        DecayDescriptor='[B- -> D0 e-]cc',
-        CombinationCut=F.ALL,
-        CompositeCut=cut_vertex)
-
-    ws_btodze  =  ParticleCombiner(
-        Inputs=[dzs, electrons],
-        name=f'ws_{B_BUILDER_NAME}_e',
-        DecayDescriptor='[B+ -> D0 e+]cc',
-        CombinationCut=F.ALL,
-        CompositeCut=cut_vertex)
-
-    return ParticleContainersMerger([rs_btodze,ws_btodze])
-
-@register_line_builder(slb_lines)
-def hlt2_mybutod0enu_d0tokpi_line(name=HLT2LINE,prescale=1):
-    Bcands = make_b()
-    return Hlt2Line(name=name, prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
-
-def pass_through_line(name="Hlt2Passthrough"):
-    """Return a HLT2 line that performs no selection but runs and persists the reconstruction
-    """
-    return Hlt2Line(name=name, prescale=1, algs=[], persistreco=True)
-
-from Hlt2Conf.lines.topological_b import *
-
-def _make_lines():
-    ret = []     
-    for line_dict in [slb_lines]: 
-        for line_name, builder in line_dict.items() : 
-            if "D0ToKPi" in line_name and "TauToPiPiPi" not in line_name and "Bc" not in line_name: 
-                print(line_name)
-                ret.append(builder())
-    ret += [twobody_line(),threebody_line(),pass_through_line()]
-    return ret   
-
-def make_streams():
-    streams = [
-        Stream(lines=_make_lines(), routing_bit=98, detectors=DETECTORS)
-    ]
-    return Streams(streams=streams)
-
-public_tools = [
-    trackMasterExtrapolator_with_simplified_geom(),
-    stateProvider_with_simplified_geom(),
-]
-
-def main(options: Options):
-    # NOTE: the TBTC does not apply a chi2 cut because it is applied by the PrKF
-    with reconstruction.bind(from_file=False),\
-         hlt2_reconstruction.bind(make_reconstruction=make_light_reco_pr_kf_without_UT),\
-         require_gec.bind(skipUT=True),\
-         default_VeloCluster_source.bind(bank_type="VPRetinaCluster"),\
-         make_TrackBestTrackCreator_tracks.bind(max_ghost_prob=0.7, max_chi2ndof=sys.float_info.max),\
-         make_PrKalmanFilter_Velo_tracks.bind(max_chi2ndof=5.),\
-         make_PrKalmanFilter_noUT_tracks.bind(max_chi2ndof=4.),\
-         make_PrKalmanFilter_Seed_tracks.bind(max_chi2ndof=6.),\
-         get_default_hlt1_filter_code_for_hlt2.bind(code=r"Hlt1(?!PassthroughLargeEvent).*Decision"):
-        return run_moore(options, make_streams, public_tools=[])
-
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data/MC_Matcher.py b/SL_l_nu_D0toKpi_Run3_MC_data/MC_Matcher.py
deleted file mode 100644
index e3b279805b..0000000000
--- a/SL_l_nu_D0toKpi_Run3_MC_data/MC_Matcher.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from FunTuple import FunctorCollection
-import Functors as F
-def trail_seeker(MCTRUTH):
-	mcMatch = lambda decay_descriptor: (F.HAS_VALUE @ MCTRUTH(F.FIND_MCDECAY(decay_descriptor)))
-	mcMatch_both = lambda decay_descriptor1,decay_descriptor2: (F.HAS_VALUE @ MCTRUTH(F.FIND_MCDECAY(decay_descriptor1))+F.HAS_VALUE @ MCTRUTH(F.FIND_MCDECAY(decay_descriptor2)))
-	
-	variables = FunctorCollection({
-		'IS_Dtaunu':mcMatch_both("[B0 -> D*(2010)- tau+ nu_tau]CC","[B~0 -> D*(2010)- tau+ nu_tau]CC"),
-		'IS_Denu':mcMatch_both("[B0 -> D*(2010)- e+ nu_e]CC","[B~0 -> D*(2010)- e+ nu_e]CC"),	
-		'IS_Dstar_2460enu':mcMatch_both("[B0 -> D*(2640)- e+ nu_e]CC","[B~0 -> D*(2640)- e+ nu_e]CC"),
-		'IS_D_2Senu':mcMatch_both("[B0 -> D(2S)- e+ nu_e]CC","[B~0 -> D(2S)- e+ nu_e]CC"),
-		'IS_Dstar_2460_2enu':mcMatch_both("[B0 -> D*_2(2460)- e+ nu_e]CC","[B~0 -> D*_2(2460)- e+ nu_e]CC"),
-		'IS_D_2460_1enu':mcMatch_both("[B0 -> D_1(2420)- e+ nu_e]CC","[B~0 -> D_1(2420)- e+ nu_e]CC"),
-		'IS_Dstar_0taunu':mcMatch_both("[B0 -> D*_0- tau+ nu_tau]CC","[B~0 -> D*_0- tau+ nu_tau]CC"),
-		'IS_D_H_1taunu':mcMatch_both("[B0 -> D_1(H)- tau+ nu_tau]CC","[B~0 -> D_1(H)- tau+ nu_tau]CC"),
-		'IS_D_2420_1taunu':mcMatch_both("[B0 -> D_1(2420)- tau+ nu_tau]CC","[B~0 -> D_1(2420)- tau+ nu_tau]CC"),
-		'IS_Dstar_2460_2taunu':mcMatch_both("[B0 -> D*_2(2460)- tau+ nu_tau]CC","[B~0 -> D*_2(2460)- tau+ nu_tau]CC"),
-		'IS_Dstar0_2640enu':mcMatch("[B- -> D*(2640)0 e- nu_e~]CC"),	
-		'IS_D0_2Senu':mcMatch("[B- -> D(2S)0 e- nu_e~]CC"),	
-		'IS_Dstar0_2460_2enu':mcMatch("[B- -> D*_2(2460)0 e- nu_e~]CC"),	
-		'IS_D0_2460_1enu':mcMatch("[B- -> D_1(2420)0 e- nu_e~]CC"),	
-		'IS_D0_H_1taunu':mcMatch("[B- -> D_1(H)0 tau- nu_tau~]CC"),	
-		'IS_D0_2420_1taunu':mcMatch("[B- -> D_1(2420)0 tau- nu_tau~]CC"),	
-		'IS_Dstar0_2460_2taunu':mcMatch("[B- -> D*_2(2460)0 tau- nu_tau~]CC"),	
-		})
-	return(variables)
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data/Spruce.py b/SL_l_nu_D0toKpi_Run3_MC_data/Spruce.py
deleted file mode 100644
index 964714aba8..0000000000
--- a/SL_l_nu_D0toKpi_Run3_MC_data/Spruce.py
+++ /dev/null
@@ -1,58 +0,0 @@
-###############################################################################
-# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
-#                                                                             #
-# This software is distributed under the terms of the GNU General Public      #
-# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
-#                                                                             #
-# In applying this licence, CERN does not waive the privileges and immunities #
-# granted to it by virtue of its status as an Intergovernmental Organization  #
-# or submit itself to any jurisdiction.                                       #
-###############################################################################
-#Example follows from hlt2_with_hlt1_decision.py
-from Moore import Options,options, run_moore, config
-from Hlt2Conf.lines.semileptonic.builders import sl_line_prefilter
-from Moore.config import SpruceLine,register_line_builder
-from .Hlt2 import make_b
-from Moore.streams import DETECTORS, Stream, Streams
-from PyConf.application import configure_input, configure, default_raw_event
-from RecoConf.global_tools import stateProvider_with_simplified_geom
-from RecoConf.reconstruction_objects import reconstruction
-from PyConf.reading import reconstruction as reco_spruce, upfront_reconstruction as upfront_spruce
-from RecoConf.decoders import default_ft_decoding_version
-from Hlt2Conf.lines.semileptonic.spruce_semileptonic import spruce_butod0munu_d0tokpi_line,spruce_butod0taunu_d0tokpi_tautomununu_line
-from Hlt2Conf.lines.semileptonic.HbToHcTauNu_TauToLNuNu import make_butod0taunu_d0tokpi_tautolnunu
-from Hlt2Conf.lines.semileptonic.HbToHcLNu import make_butod0lnu_d0tokpi
-from Moore.persistence.hlt2_tistos import list_of_full_stream_lines
-from Hlt2Conf.lines.semileptonic import all_lines as slb_lines
-from Hlt2Conf.lines.topological_b import all_lines as topo_lines
-from Hlt2Conf.lines.semileptonic import sprucing_lines as slb_sprucing_lines
-def lines_for_tistos():
-    """
-    Nikole Comment : 
-    This TISTOS part is only needed for exclusive Sprucing 
-    and it saves the candidates of the FULL HLT2 lines that fired for each event. 
-    You need to make sure its only FULL HLT2 lines in the lines_for_tistos 
-    and they are the ones you care about ie. RD inclusive lines
-    """
-    return [linename for line_dict in [slb_lines,topo_lines] for linename in line_dict.keys()]
-
-@register_line_builder(slb_sprucing_lines)
-def spruce_mybutod0enu_d0tokpi_line(name='SpruceSLB_myBuToD0ENu_D0ToKPi',prescale=1):
-    Bcands = make_b()
-    return SpruceLine(name=name,  hlt2_filter_code=[
-    f"{name.replace('Spruce','Hlt2')}Decision",
-    "Hlt2Topo2BodyDecision", "Hlt2Topo3BodyDecision"]
-    ,prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
-
-def make_full_streams():
-    lines = [builder() for builder in slb_sprucing_lines.values()]
-    streams = [Stream(lines=lines, detectors=[])]
-    return Streams(streams=streams)
-
-def main(options: Options):
-    public_tools = [stateProvider_with_simplified_geom()]
-    with reconstruction.bind(from_file=True, spruce=True),\
-      reco_spruce.bind(simulation=True),\
-      upfront_spruce.bind(simulation=True),\
-      list_of_full_stream_lines.bind(lines=lines_for_tistos()):
-        return run_moore(options, make_full_streams, public_tools=public_tools)
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data/info.yaml b/SL_l_nu_D0toKpi_Run3_MC_data/info.yaml
deleted file mode 100644
index 47634c4fa3..0000000000
--- a/SL_l_nu_D0toKpi_Run3_MC_data/info.yaml
+++ /dev/null
@@ -1,155 +0,0 @@
-defaults:
-  inform:
-    - ching-hua.li@cern.ch
-  wg: SL
-
-{%- set evttype_lines_and_leptons = [
-  ('11584030','SLB_BuToD0ENu_D0ToKPi','b0_dstp_e'),
-  ('11574020','SLB_BuToD0MuNu_D0ToKPi','b0_dstp_muon'),
-  ('11584010','SLB_BuToD0TauNu_D0ToKPi_TauToENuNu','b0_dstp_taue'),
-  ('11574010','SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu','b0_dstp_taumuon'),
-  ('12685400','SLB_BuToDststENu','bp_dstst_e'),
-  ('12883000','SLB_BuToDststTauNu_TauToENuNu','bp_dstst_taue'),
-  ('11686000','SLB_BdToDststENu','b0_dststp_e'),
-  ('11883000','SLB_BdToDststTauNu_TauToENuNu','b0_dststp_taue'),
-] %}
-
-{%- set polarity_variables = [
-  ('MagDown','sim-20231017-vc-md100'),
-  ('MagUp','sim-20231017-vc-mu100'),
-]%}
-{%- for polarity, cond_tag in polarity_variables %}
-  {%- for evttype, line, dk in evttype_lines_and_leptons %}
-HLT1_{{dk}}_{{ polarity }}:
-  application: "Moore/v55r7@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  input:
-    bk_query: "/MC/Dev/Beam6800GeV-expected-2024-{{polarity}}-Nu7.6-25ns-Pythia8/Sim10c/{{evttype}}/DIGI"
-    dq_flags:
-      - OK
-    n_test_lfns: 1
-  output: hlt1.dst
-  options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data.Hlt1:main
-    extra_options:
-      input_raw_format: 0.3
-      conddb_tag: {{cond_tag}}
-      dddb_tag: dddb-20231017
-      input_type: ROOT
-      output_type: ROOT
-      simulation: True
-      data_type: "Upgrade"
-      scheduler_legacy_mode: False
-      compression:
-        algorithm: ZSTD
-        level: 1
-        max_buffer_size: 1048576
-      #evt_max: 1000 
-
-HLT2_{{dk}}_{{ polarity }}:
-  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  input:
-    job_name: HLT1_{{dk}}_{{ polarity }}
-  output: hlt2.dst
-  options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data.Hlt2:main
-    extra_options:
-      input_raw_format: 0.5
-      conddb_tag: {{cond_tag}}
-      dddb_tag: dddb-20231017
-      input_type: ROOT
-      output_type: ROOT
-      simulation: True
-      data_type: "Upgrade"
-      scheduler_legacy_mode: False
-      output_manifest_file: "HLT2.tck.json" 
-      compression:
-        algorithm: ZSTD
-        level: 1
-        max_buffer_size: 1048576
-      #evt_max: 1000
-SPRUCE_{{dk}}_{{ polarity }}:
-  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  input:
-    job_name: HLT2_{{dk}}_{{ polarity }}
-  output: spruce.dst
-  options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data.Spruce:main
-    extra_options:
-      input_raw_format: 0.5
-      conddb_tag: {{cond_tag}}
-      dddb_tag: dddb-20231017
-      input_type: ROOT
-      output_type: ROOT
-      simulation: True
-      data_type: "Upgrade"
-      scheduler_legacy_mode: False
-      input_process: "Hlt2"
-      input_manifest_file: "HLT2.tck.json"
-      output_manifest_file: "SPRUCE.tck.json" 
-      compression:
-        algorithm: ZSTD
-        level: 1
-        max_buffer_size: 1048576
-      #evt_max: 1000
-DV_{{dk}}_{{ polarity }}:
-  application: "DaVinci/v64r5@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  input:
-    job_name: SPRUCE_{{dk}}_{{ polarity }}
-  output: NTuple.root
-  options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data.DV:MC_{{line}}
-    extra_options:
-      input_raw_format: 0.5
-      conddb_tag: {{cond_tag}}
-      dddb_tag: dddb-20231017
-      input_type: ROOT
-      simulation: True
-      data_type: "Upgrade"
-      #geometry_version: run3/2024.Q1.2-v00.00
-      input_process: "Spruce"
-      input_manifest_file: "SPRUCE.tck.json"
-      #evt_max: 1000
-
-  {%- endfor %}
-{%- endfor %}
-
-
-{%- set lines_and_decays = [
-  ('SLB_BuToD0ENu_D0ToKPi','b0_dstp_e'),
-  ('SLB_BuToD0MuNu_D0ToKPi','b0_dstp_muon'),
-  ('SLB_BuToD0TauNu_D0ToKPi_TauToENuNu','b0_dstp_taue'),
-  ('SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu','b0_dstp_taumuon'),
-  ('SLB_BuToD0ENu_D0ToKPi_FakeElectron','b0_dstp_e_fake'),
-  ('SLB_BuToD0MuNu_D0ToKPi_FakeMuon','b0_dstp_muon_fake'),
-  ('SLB_BuToD0TauNu_D0ToKPi_FakeElectron','b0_dstp_taue_fake'),
-  ('SLB_BuToD0TauNu_D0ToKPi_FakeMuon','b0_dstp_taumuon_fake'),
-] %}
-
-{%- for spruce_line, decay in lines_and_decays %}
-data_{{decay}}:
-  application: "DaVinci/v64r5"
-  input:
-    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-MagDown-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
-    dq_flags:
-      - UNCHECKED
-      - OK
-    keep_running: true
-    n_test_lfns: 1 
-  output: DATA.ROOT
-  options:
-    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data.DV:Data_{{spruce_line}}
-    extra_options:
-      input_raw_format: 0.5
-      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
-      simulation: False
-      #data_type: "Upgrade"
-      geometry_version: run3/2024.Q1.2-v00.00
-      conditions_version: master
-      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
-      input_stream: "sl" # for streamed data
-      #evt_max: 1000
-{%- endfor %}
-
diff --git a/lb_lc_mu_2024data/DV.py b/lb_lc_mu_2024data/DV.py
new file mode 100644
index 0000000000..84cf179833
--- /dev/null
+++ b/lb_lc_mu_2024data/DV.py
@@ -0,0 +1,299 @@
+###############################################################################
+# (c) Copyright 2024 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+import sys
+from DaVinci import Options,make_config
+from PyConf.reading import get_pvs, get_rec_summary, get_particles
+from PyConf.Algorithms import ThOrParticleSelection
+import Functors as F
+from FunTuple import FunctorCollection
+from FunTuple import FunTuple_Particles as Funtuple
+from DaVinci.algorithms import create_lines_filter
+import FunTuple.functorcollections as FC
+from DaVinciMCTools import MCTruthAndBkgCat
+from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
+from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Functors.grammar import Functor
+from Hlt2Conf.lines.semileptonic.isolationMVA import mva_functor_e_inclusive,mva_functor_mu_inclusive
+
+_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
+_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
+_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
+#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
+#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
+ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
+
+TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
+
+def make_Bst(B, pions):
+
+
+    hadron_cut = F.IS_ABS_ID('Lambda_c+')  # Getting the hadron candidates
+
+    code_hadron = F.FILTER(hadron_cut) @ F.GET_CHILDREN()
+    hadron_TES = ThOrParticleSelection(
+        name="hadron_iso",
+        InputParticles=B,
+        Functor=code_hadron).OutputSelection
+
+    lepton_cut = F.IS_ABS_ID('mu-')
+    code_lepton = F.FILTER(lepton_cut) @ F.GET_CHILDREN()
+    lepton_TES = ThOrParticleSelection(
+        name="lepton_iso",
+        InputParticles=B,
+        Functor=code_lepton).OutputSelection
+
+
+    #combine to make [B*- -> Lambda_c+ mu-]cc
+    Bstm = ParticleCombiner(
+        Inputs=[hadron_TES, lepton_TES],
+        name=f'Bstm_mu',
+        DecayDescriptor='[B*- -> Lambda_c+ mu-]cc',
+        CombinationCut=F.ALL,
+        CompositeCut=F.ALL,
+        ParticleCombiner="ParticleVertexFitter",
+    )
+
+    cut_combination = F.require_all(F.MAXDOCA < 8.0, F.MAXDOCACHI2 < 20)
+
+    #combine to make [B*0 -> B*- pi+]cc
+    Bst_1 = ParticleCombiner(
+        Inputs=[Bstm, pions],
+        name='Bst_1',
+        DecayDescriptor='[B*0 -> B*- pi+]cc',
+        CombinationCut=cut_combination,
+        CompositeCut=F.ALL,
+        ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
+        #OutputLevel=1
+    )
+    #combine to make [B*0 -> B*- pi-]cc
+    Bst_2 = ParticleCombiner(
+        Inputs=[Bstm, pions],
+        name='Bst_2',
+        DecayDescriptor='[B*0 -> B*- pi-]cc',
+        CombinationCut=cut_combination,
+        CompositeCut=F.ALL,
+        ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
+        #OutputLevel=1
+    )
+    #merge the two Bst candidates
+    Bst = ParticleContainersMerger([Bst_1, Bst_2], name = 'Bst_combiner')
+    return Bst
+
+def get_functors(v2_pvs, rec_summary):
+    #define common variables for all fields (composite and basic)
+    vars_common  = FunctorCollection()
+    #all pvs: ip, ipchi2. The PV positions are stored in event variables
+    vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
+    vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
+    #best pv: x, y, z, ip, ipchi2
+    vars_common['BPV_X']          = F.BPVX(v2_pvs)
+    vars_common['BPV_Y']          = F.BPVY(v2_pvs)
+    vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
+    vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
+    vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
+    vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
+    vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
+    #particle id, key, truekey. The trueid is stored in MCHierarchy
+    vars_common['ID']            = F.PARTICLE_ID
+    vars_common['KEY']           = F.OBJECT_KEY
+    #get charge, min ip and min ipchi2
+    vars_common['CHARGE']        = F.CHARGE
+    vars_common['MINIP']         = F.MINIP(v2_pvs)
+    vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
+    #reco kinematics
+    vars_common += FC.Kinematics()
+    vars_common['ETA']           = F.ETA
+    vars_common['PHI']           = F.PHI
+
+    #variables for composite particles
+    vars_composite  = FunctorCollection()
+    #end vertex position and end vertex chi2
+    vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
+    vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
+    vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
+    #all pvs: dira, fd, fdchi2
+    vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
+    vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
+    vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
+    vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
+    vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
+    vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
+    vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
+    vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
+    #best pv: dira, fd, fdchi2, corrm, ltime, dls
+    vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
+    vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
+    vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
+    vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
+    vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
+    vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
+    #Compute maximum DOCA and maximum DOCACHI2. Since there are 
+    # only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
+    # the DOCA/DOCACHI2 see below.
+    vars_composite['MAX_DOCA'] = F.MAXDOCA
+    vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
+    vars_composite['MAX_SDOCA'] = F.MAXSDOCA
+    vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
+
+    #variables for Lb field
+    var_B  = FunctorCollection()
+
+    #variables for basics
+    vars_basic  = FunctorCollection()
+    vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
+    vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
+    vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
+    vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
+    vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
+    vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
+    vars_basic['GHOSTPROB'] = F.GHOSTPROB
+    vars_basic['PIDpi'] = F.PID_PI
+    vars_basic['PIDk']  = F.PID_K
+    vars_basic['PIDp']  = F.PID_P
+    vars_basic['PIDe']  = F.PID_E
+    vars_basic['PIDmu'] = F.PID_MU
+
+    #variables for event
+    evt_vars = FunctorCollection()
+    #evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
+    #evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
+    #evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
+    #evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
+    #evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
+    evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
+    evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
+    evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
+    evt_vars['nFTClusters'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nFTClusters")
+
+    #return all functors
+    functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars)
+    return functors
+
+def tuple_Bst(Bst, v2_pvs, rec_summary):
+    #get functors
+    functors = get_functors(v2_pvs, rec_summary)
+    vars_common = functors[0]
+    vars_composite = functors[1]
+    var_B = functors[2]
+    vars_basic = functors[3]
+    evt_vars = functors[4]
+
+    #variables for Sb field
+    vars_Bst  = FunctorCollection()
+    B_child   = F.CHILD(1, F.FORWARDARG0)
+    Epi_child = F.CHILD(2, F.FORWARDARG0)
+    bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+    #diff in vtx chi2 with and without extra particle
+    vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
+    #IP and IPChi2 of extra particle wrt to Sb end vertex
+    vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+    #IP and IPChi2 of extra particle wrt to Lb end vertex
+    vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+    #angle between extra particle and Lb
+    vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+    #diff in fd chi2 with and without extra particle
+    vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
+    vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+    #IP chi2 of extra particle wrt PV and SV of Sb
+    vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+    #IP chi2 of extra particle wrt PV and SV of Bb
+    vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+    #DOCA and DOCACHI2 b/w Lb and extra particle
+    vars_Bst['DOCA12']       = F.DOCA(1, 2)
+    vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+    #vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
+    #vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
+    #DOCACHI2 of extra particle wrt to mother i.e. Sb
+    vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
+    vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+    vars_Bst['iso_mva'] = mva_functor_mu_inclusive(v2_pvs)[0]
+
+    #define fields
+    fields_mu = {}
+    fields_mu['Sb']    = '[B*0 ->  (B*- ->  Lambda_c+  mu-)  [pi+]CC]CC'
+    fields_mu['Lb']    = '[B*0 -> ^(B*- ->  Lambda_c+  mu-)  [pi+]CC]CC'
+    fields_mu['Lc']    = '[B*0 ->  (B*- -> ^Lambda_c+  mu-)  [pi+]CC]CC'
+    fields_mu['Lep']   = '[B*0 ->  (B*- ->  Lambda_c+ ^mu-)  [pi+]CC]CC'
+    fields_mu['Epi']   = '[B*0 ->  (B*- ->  Lambda_c+  mu-) ^[pi+]CC]CC'
+    fields_mu['p']    = '[B*0 ->  (B*- -> (Lambda_c+ -> ^p+ K- pi+)  mu-)  [pi+]CC]CC'
+    fields_mu['Km']   = '[B*0 ->  (B*- -> (Lambda_c+ -> p+ ^K- pi+)  mu-)  [pi+]CC]CC'
+    fields_mu['pip']  = '[B*0 ->  (B*- -> (Lambda_c+ -> p+ K- ^pi+)  mu-)  [pi+]CC]CC'
+
+    #add variables
+    variables = {}
+    variables["ALL"] = vars_common
+    variables["Sb"]  = vars_composite + vars_Bst
+    variables["Lb"]  = vars_composite + var_B
+    variables["Lc"]  = vars_composite
+    variables["Lep"] = vars_basic
+    variables["Epi"] = vars_basic
+    variables["p"]  = vars_basic
+    variables["Km"] = vars_basic
+    variables["pip"]= vars_basic
+
+    #define tuple
+    my_tuple = Funtuple(
+        name="Tuple",
+        tuple_name="DecayTree",
+        fields=fields_mu,
+        variables=variables,
+        event_variables=evt_vars,
+        inputs=Bst)
+
+    return my_tuple
+
+def get_extra_pions():
+	"""
+	Note this function in DaVinci requires:
+	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
+	and it's related LHCb, DaVinci and Rec MRs
+	"""
+	long_pions = make_has_rich_long_pions()
+	up_pions = make_has_rich_up_pions()
+	down_pions = make_has_rich_down_pions()
+	return ParticleContainersMerger([long_pions, up_pions, down_pions],
+									name='Pions_combiner')
+
+def main(options: Options):
+
+    #define filer
+    my_filter = create_lines_filter(name="Filter", lines=['SpruceSLB_LbToLcMuNu_LcToPKPi'])
+
+    #get data and extra particles
+    lb = get_particles("/Event/Spruce/SpruceSLB_LbToLcMuNu_LcToPKPi/Particles")
+    extra_particles = get_extra_pions()
+
+    #get v2_pvs and rec_summary
+    v2_pvs  = get_pvs()
+    rec_summary = get_rec_summary()
+
+    #make sb candidate
+    Bst = make_Bst(lb, extra_particles)
+    #MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+
+    tuple_file = tuple_Bst(Bst, v2_pvs, rec_summary)
+
+    #define algorithms
+    user_algorithms = {}
+    user_algorithms['Alg'] = [my_filter, tuple_file]
+
+    return make_config(options, user_algorithms)
diff --git a/lb_lc_mu_2024data/info.yaml b/lb_lc_mu_2024data/info.yaml
new file mode 100644
index 0000000000..903d0f8a86
--- /dev/null
+++ b/lb_lc_mu_2024data/info.yaml
@@ -0,0 +1,28 @@
+defaults:
+  inform:
+    - ching-hua.li@cern.ch
+  wg: SL
+
+data_lb_lc_mu:
+  application: "DaVinci/v64r5"
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-MagDown-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    keep_running: true
+    n_test_lfns: 1 
+  output: DATA.ROOT
+  options:
+    entrypoint: lb_lc_mu_2024data.DV:main
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
+      simulation: False
+      #data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "sl" # for streamed data
+      #evt_max: 1000
+
-- 
GitLab


From 33c51739f61a4362ff92682a5b391022dc228ea3 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Wed, 10 Jul 2024 21:48:08 +0200
Subject: [PATCH 45/57] Fix info.yaml

---
 lb_lc_mu_2024data/info.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lb_lc_mu_2024data/info.yaml b/lb_lc_mu_2024data/info.yaml
index 903d0f8a86..e3ab539a95 100644
--- a/lb_lc_mu_2024data/info.yaml
+++ b/lb_lc_mu_2024data/info.yaml
@@ -20,7 +20,7 @@ data_lb_lc_mu:
       input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
       simulation: False
       #data_type: "Upgrade"
-      geometry_version: run3/2024.Q1.2-v00.00
+      geometry_version: run3/trunk
       conditions_version: master
       input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
       input_stream: "sl" # for streamed data
-- 
GitLab


From 201c10b2729da34f514435abe0d200e26c296a7c Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Thu, 18 Jul 2024 14:28:09 +0200
Subject: [PATCH 46/57] Reconstruct two extra pion

---
 lb_lc_mu_2024data/DV.py           |  66 +++++++++-----
 lb_lc_mu_2024data/isolationMVA.py | 139 ++++++++++++++++++++++++++++++
 2 files changed, 182 insertions(+), 23 deletions(-)
 create mode 100644 lb_lc_mu_2024data/isolationMVA.py

diff --git a/lb_lc_mu_2024data/DV.py b/lb_lc_mu_2024data/DV.py
index 84cf179833..b940627275 100644
--- a/lb_lc_mu_2024data/DV.py
+++ b/lb_lc_mu_2024data/DV.py
@@ -23,6 +23,8 @@ from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
 from Hlt2Conf.algorithms_thor import ParticleContainersMerger
 from Functors.grammar import Functor
 from Hlt2Conf.lines.semileptonic.isolationMVA import mva_functor_e_inclusive,mva_functor_mu_inclusive
+from .isolationMVA import mva_transform_output,mva_functor_mu_inclusive
+
 
 _BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
 _allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
@@ -39,7 +41,7 @@ ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_F
 
 TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
 
-def make_Bst(B, pions):
+def make_Bst(B, pions,v2_pvs):
 
 
     hadron_cut = F.IS_ABS_ID('Lambda_c+')  # Getting the hadron candidates
@@ -68,25 +70,28 @@ def make_Bst(B, pions):
         ParticleCombiner="ParticleVertexFitter",
     )
 
-    cut_combination = F.require_all(F.MAXDOCA < 8.0, F.MAXDOCACHI2 < 20)
+    #cut_combination = F.require_all(F.MAXDOCA < 8.0, F.MAXDOCACHI2 < 20)
+
+    MVA_cut = mva_transform_output(0.05)
+    cut_composite = F.require_all(mva_functor_mu_inclusive(v2_pvs,2) > MVA_cut,mva_functor_mu_inclusive(v2_pvs,3) > MVA_cut)
 
-    #combine to make [B*0 -> B*- pi+]cc
+    #combine to make [B*0 -> B*- pi+ pi-]cc
     Bst_1 = ParticleCombiner(
-        Inputs=[Bstm, pions],
+        Inputs=[Bstm, pions,pions],
         name='Bst_1',
-        DecayDescriptor='[B*0 -> B*- pi+]cc',
-        CombinationCut=cut_combination,
-        CompositeCut=F.ALL,
+        DecayDescriptor='[B*0 -> B*- pi+ pi-]cc',
+        CombinationCut=F.ALL,
+        CompositeCut=cut_composite,
         ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
         #OutputLevel=1
     )
-    #combine to make [B*0 -> B*- pi-]cc
+    #combine to make [B*0 -> B*- pi- pi-]cc
     Bst_2 = ParticleCombiner(
-        Inputs=[Bstm, pions],
+        Inputs=[Bstm, pions,pions],
         name='Bst_2',
-        DecayDescriptor='[B*0 -> B*- pi-]cc',
-        CombinationCut=cut_combination,
-        CompositeCut=F.ALL,
+        DecayDescriptor='[B*0 -> B*- pi- pi-]cc',
+        CombinationCut=F.ALL,
+        CompositeCut=cut_composite,
         ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
         #OutputLevel=1
     )
@@ -225,18 +230,32 @@ def tuple_Bst(Bst, v2_pvs, rec_summary):
     #DOCACHI2 of extra particle wrt to mother i.e. Sb
     vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
     vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
-    vars_Bst['iso_mva'] = mva_functor_mu_inclusive(v2_pvs)[0]
 
+    #Get mva output for 1st and 2nd pion
+    #mva_first_pion = mva_functor_mu_inclusive(v2_pvs,2)[0]
+    vars_Bst['iso_mva_1'] = mva_functor_mu_inclusive(v2_pvs,2)    
+
+    #mva_second_pion = mva_functor_mu_inclusive(v2_pvs,3)[0]
+    vars_Bst['iso_mva_2'] = mva_functor_mu_inclusive(v2_pvs,3)    
+    '''
+    MVA_cut = mva_transform_output(0.05)
+    #MVA_cut_functor = (mva_functor_mu_inclusive(v2_pvs,2) > MVA_cut & mva_functor_mu_inclusive(v2_pvs,3) > MVA_cut) 
+    MVA_cut_functor = F.require_all(mva_functor_mu_inclusive(v2_pvs,2) > MVA_cut,mva_functor_mu_inclusive(v2_pvs,3) > MVA_cut)
+    Bst_mva_cut = ParticleFilter(
+        Bst, F.FILTER(MVA_cut_functor), name="filter_isoPions"
+    )  # B + extra track combos passing the MVA cuts
+    '''
     #define fields
     fields_mu = {}
-    fields_mu['Sb']    = '[B*0 ->  (B*- ->  Lambda_c+  mu-)  [pi+]CC]CC'
-    fields_mu['Lb']    = '[B*0 -> ^(B*- ->  Lambda_c+  mu-)  [pi+]CC]CC'
-    fields_mu['Lc']    = '[B*0 ->  (B*- -> ^Lambda_c+  mu-)  [pi+]CC]CC'
-    fields_mu['Lep']   = '[B*0 ->  (B*- ->  Lambda_c+ ^mu-)  [pi+]CC]CC'
-    fields_mu['Epi']   = '[B*0 ->  (B*- ->  Lambda_c+  mu-) ^[pi+]CC]CC'
-    fields_mu['p']    = '[B*0 ->  (B*- -> (Lambda_c+ -> ^p+ K- pi+)  mu-)  [pi+]CC]CC'
-    fields_mu['Km']   = '[B*0 ->  (B*- -> (Lambda_c+ -> p+ ^K- pi+)  mu-)  [pi+]CC]CC'
-    fields_mu['pip']  = '[B*0 ->  (B*- -> (Lambda_c+ -> p+ K- ^pi+)  mu-)  [pi+]CC]CC'
+    fields_mu['Sb']    = '[B*0 ->  (B*- ->  Lambda_c+  mu-)  [pi+]CC pi-]CC'
+    fields_mu['Lb']    = '[B*0 -> ^(B*- ->  Lambda_c+  mu-)  [pi+]CC pi-]CC'
+    fields_mu['Lc']    = '[B*0 ->  (B*- -> ^Lambda_c+  mu-)  [pi+]CC pi-]CC'
+    fields_mu['Lep']   = '[B*0 ->  (B*- ->  Lambda_c+ ^mu-)  [pi+]CC pi-]CC'
+    fields_mu['Epi1']   = '[B*0 ->  (B*- ->  Lambda_c+  mu-) ^[pi+]CC pi-]CC'
+    fields_mu['Epi2']   = '[B*0 ->  (B*- ->  Lambda_c+  mu-) [pi+]CC ^pi-]CC'
+    fields_mu['p']    = '[B*0 ->  (B*- -> (Lambda_c+ -> ^p+ K- pi+)  mu-)  [pi+]CC pi-]CC'
+    fields_mu['Km']   = '[B*0 ->  (B*- -> (Lambda_c+ -> p+ ^K- pi+)  mu-)  [pi+]CC pi-]CC'
+    fields_mu['pip']  = '[B*0 ->  (B*- -> (Lambda_c+ -> p+ K- ^pi+)  mu-)  [pi+]CC pi-]CC'
 
     #add variables
     variables = {}
@@ -245,7 +264,8 @@ def tuple_Bst(Bst, v2_pvs, rec_summary):
     variables["Lb"]  = vars_composite + var_B
     variables["Lc"]  = vars_composite
     variables["Lep"] = vars_basic
-    variables["Epi"] = vars_basic
+    variables["Epi1"] = vars_basic
+    variables["Epi2"] = vars_basic
     variables["p"]  = vars_basic
     variables["Km"] = vars_basic
     variables["pip"]= vars_basic
@@ -287,7 +307,7 @@ def main(options: Options):
     rec_summary = get_rec_summary()
 
     #make sb candidate
-    Bst = make_Bst(lb, extra_particles)
+    Bst = make_Bst(lb, extra_particles,v2_pvs)
     #MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
 
     tuple_file = tuple_Bst(Bst, v2_pvs, rec_summary)
diff --git a/lb_lc_mu_2024data/isolationMVA.py b/lb_lc_mu_2024data/isolationMVA.py
new file mode 100644
index 0000000000..92f9ae0700
--- /dev/null
+++ b/lb_lc_mu_2024data/isolationMVA.py
@@ -0,0 +1,139 @@
+###############################################################################
+# (c) Copyright 2024 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+import Functors as F
+from Hlt2Conf.algorithms_thor import ParticleCombiner
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Hlt2Conf.algorithms_thor import ParticleFilter
+from RecoConf.reconstruction_objects import make_pvs
+import Functors.math as fmath
+import math
+import re
+from dataclasses import dataclass
+from PyConf.Algorithms import ThOrParticleSelection
+
+#Multiplying by this number will convert log_e to log_10
+#we multiply by log10(e) rather than dividing by ln(10)
+#since multiplication is faster
+LOG10_E = math.log10(math.e)
+#toggle for printing debug messages
+#set to False for proper productions
+DEBUG = False
+
+
+@dataclass
+class MVAinput:
+    """Struct for storing MVA input variables"""
+    name: str  # The name of the var (as per the model)
+    number: int  # The number of the var
+    functor: F.grammar.FunctorBase  # The functor to calculate that variable
+    x_range: (float, float)  # axis range for input var monitoring histos
+
+
+def mva_functor_mu_inclusive(v2_pvs,
+                             index_pion,
+                             useNumbers: bool = False):
+    """
+    Compute the output of the MVA classifier (xGBoost) for charged track isolation.
+    Higher values of MVA classifier output indicate that the charged track is less isolated
+    and is more likely to be associated to be coming from the same decay vertex as the B0.
+    For more details: Checkout the presentation https://indico.cern.ch/event/1234758/#sc-1-4-ml-based-charged-isolat
+
+    Args:
+        v2_pvs (list): TES location of v2 PVs
+        useNumbers (bool): decision of whether to use the numbers or names of vars in the MVA functor
+    """
+    #get the children of the two-body combination (B0-extraparticle)
+    Bstar_p_child = F.CHILD(1, F.FORWARDARGS)
+    ExtraParticle_child = F.CHILD(index_pion, F.FORWARDARGS)
+
+    #define the input variables for mva
+    mva_input_vars = []  #FunctorCollection()
+    #define Impact parameter chi2 of the extra particle wrt to the BPV associated to the two-body combination (B0-extraparticle)
+    mva_input_vars.append(
+        MVAinput("Epi_BPV_IPCHI2", 0,
+                 F.BPVIPCHI2(v2_pvs).bind(ExtraParticle_child), (0, 20)))  # PV
+    #define PT of two body combination (B0-extraparticle). Here is transformed to be less peaky
+    mva_input_vars.append(
+        MVAinput("Epi_PT", 1,
+                 fmath.log(F.PT.bind(ExtraParticle_child)) * LOG10_E, (1, 5)))
+    #define opening angle between B0 and extra particle. Here is transformed to be less peaky
+    cos_angle = F.COSANGLE.bind(F.THREEMOMENTUM @ Bstar_p_child,
+                                F.THREEMOMENTUM @ ExtraParticle_child)
+    mva_input_vars.append(
+        MVAinput("Sb_Epi_COSANGLE_Lb", 2, 1. - fmath.pow(1. - cos_angle, 0.2),
+                 (0, 1)))
+    #define DIRA of the two body combination (B0-extraparticle)
+    mva_input_vars.append(
+        MVAinput("Sb_BPV_DIRA_TF", 8, fmath.pow(1. - F.BPVDIRA(v2_pvs), 0.2),
+                 (0, 1.2)))
+    #define magnitude of PV distance i.e. distance between PV and vertex of two-body combination (B0-extraparticle)
+    # NB: the sign of the magnitude deterimined by the by the difference in z-coordinate of PV and vertex of two-body combination
+    mva_input_vars.append(
+        MVAinput("PVdis", 3,
+                 (F.MAGNITUDE @ (F.ENDVERTEX_POS - F.BPV_POS(v2_pvs))) *
+                 fmath.sign(F.END_VZ - F.BPVZ(v2_pvs)), (-50, 100)))
+    #* F.MAGNITUDE @ (F.ENDVERTEX_POS - F.BPV_POS(v2_pvs))
+    #define magnitude of SV distance i.e. distance between two-body combination (B0-extraparticle) vertex and the vertex
+    # without the extra particle included. The sign of the magnitude is determined by the difference in z-coordinate of both vertices
+    mva_input_vars.append(
+        MVAinput("SVdis", 4,
+                 (F.MAGNITUDE
+                  @ (F.ENDVERTEX_POS.bind(Bstar_p_child) - F.ENDVERTEX_POS)) *
+                 fmath.sign(F.END_VZ - F.END_VZ.bind(Bstar_p_child)),
+                 (-50, 50)))
+    #define DeltaR i.e. the difference in radius of B0 and extra particle in the rapidity-azimuth plane
+    delta_eta = F.ETA.bind(Bstar_p_child) - F.ETA.bind(ExtraParticle_child)
+    delta_phi = F.PHI.bind(Bstar_p_child) - F.PHI.bind(ExtraParticle_child)
+    delta_phi = fmath.where(delta_phi > math.pi, delta_phi - math.pi,
+                            delta_phi)
+    delta_phi = fmath.where(delta_phi < -math.pi, delta_phi + math.pi,
+                            delta_phi)
+    mva_input_vars.append(
+        MVAinput(
+            "DeltaREpi", 5,
+            fmath.pow(
+                fmath.sqrt(
+                    fmath.pow(delta_eta, 2.) + fmath.pow(delta_phi, 2.)), 0.2),
+            (0, 1.5)))
+
+    mva_input_vars.append(
+        MVAinput("Sb_MAX_DOCACHI2", 6,
+                 fmath.log(F.SDOCACHI2(1, index_pion)) * LOG10_E, (-2.6, 7.5)))
+    mva_input_vars.append(
+        MVAinput(
+            "Sb_Epi_IPCHI2_WRT_LbENDVERTEX", 7,
+            fmath.log(
+                F.IPCHI2.bind(F.ENDVERTEX @ Bstar_p_child,
+                              ExtraParticle_child)) * LOG10_E, (-2, 6)))  # SV
+
+    #define the mva classifier
+    mva = F.MVA(
+        MVAType='TMVA',
+        Config={
+            'XMLFile': 'paramfile://data/xgboost_model_cocktail_inclusive.xml',
+            'Name': 'BDT',
+        },
+        Inputs={(f"f[{var.number}]" if useNumbers else var.name): var.functor
+                for var in mva_input_vars})
+    return mva
+
+def mva_transform_output(xgboost_style_input: float) -> float:
+    """
+    We've converted our input from xgboost-style to TMVA-style but this gives a transformation on the cut variables
+    This function converts from an xgboost-style cut to the corresponding TMVA-style
+    taken from: https://github.com/jpata/mlglue/blob/master/mlglue/tree.py#L400-L409
+    This takes the domain from [0,1] and transforms it from [-1,1] in a strange (nonlinear) way
+    """
+    TMVA_style_output = -math.log(1. / xgboost_style_input - 1.)
+    TMVA_style_output = 2. / (1. + math.exp(-2. * TMVA_style_output)) - 1.
+
+    return TMVA_style_output
+
-- 
GitLab


From ab5560ed21f3e6630c4bead1f6f82a4c8cd6b7b1 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Sat, 20 Jul 2024 22:57:34 +0200
Subject: [PATCH 47/57] Add MC

---
 lb_lc_mu_2024data/DV.py     | 181 +++++++++++++++++++++++++++---------
 lb_lc_mu_2024data/Hlt1.py   |  18 ++++
 lb_lc_mu_2024data/Hlt2.py   |  55 +++++++++++
 lb_lc_mu_2024data/Spruce.py |  29 ++++++
 lb_lc_mu_2024data/info.yaml | 110 +++++++++++++++++++++-
 5 files changed, 349 insertions(+), 44 deletions(-)
 create mode 100644 lb_lc_mu_2024data/Hlt1.py
 create mode 100644 lb_lc_mu_2024data/Hlt2.py
 create mode 100644 lb_lc_mu_2024data/Spruce.py

diff --git a/lb_lc_mu_2024data/DV.py b/lb_lc_mu_2024data/DV.py
index b940627275..ce3f7eef71 100644
--- a/lb_lc_mu_2024data/DV.py
+++ b/lb_lc_mu_2024data/DV.py
@@ -22,8 +22,8 @@ from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_u
 from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
 from Hlt2Conf.algorithms_thor import ParticleContainersMerger
 from Functors.grammar import Functor
-from Hlt2Conf.lines.semileptonic.isolationMVA import mva_functor_e_inclusive,mva_functor_mu_inclusive
-from .isolationMVA import mva_transform_output,mva_functor_mu_inclusive
+from Hlt2Conf.lines.semileptonic.isolationMVA import mva_functor_mu_inclusive,mva_transform_output
+from .isolationMVA import mva_functor_mu_inclusive as mva_functor_inclusive
 
 
 _BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
@@ -41,8 +41,7 @@ ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_F
 
 TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
 
-def make_Bst(B, pions,v2_pvs):
-
+def make_Bst_2pi(B, pions,v2_pvs,prepare_pion):
 
     hadron_cut = F.IS_ABS_ID('Lambda_c+')  # Getting the hadron candidates
 
@@ -72,34 +71,82 @@ def make_Bst(B, pions,v2_pvs):
 
     #cut_combination = F.require_all(F.MAXDOCA < 8.0, F.MAXDOCACHI2 < 20)
 
-    MVA_cut = mva_transform_output(0.05)
-    cut_composite = F.require_all(mva_functor_mu_inclusive(v2_pvs,2) > MVA_cut,mva_functor_mu_inclusive(v2_pvs,3) > MVA_cut)
-
-    #combine to make [B*0 -> B*- pi+ pi-]cc
-    Bst_1 = ParticleCombiner(
-        Inputs=[Bstm, pions,pions],
-        name='Bst_1',
+    if prepare_pion=='True':
+        MVA_cut = mva_transform_output(0.05)
+        cut_composite = F.require_all(mva_functor_mu_inclusive(v2_pvs)[0] > MVA_cut)
+
+        #first make [B*0 -> B*- pi+]cc
+        Bst_1 = ParticleCombiner(
+            Inputs=[Bstm, pions],
+            name='Bst_1',
+            DecayDescriptor='[B*0 -> B*- pi+]cc',
+            CombinationCut=F.ALL,
+            CompositeCut=cut_composite,
+            ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
+            #OutputLevel=1
+        )
+        Bst_2 = ParticleCombiner(
+            Inputs=[Bstm, pions],
+            name='Bst_2',
+            DecayDescriptor='[B*0 -> B*- pi-]cc',
+            CombinationCut=F.ALL,
+            CompositeCut=cut_composite,
+            ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
+            #OutputLevel=1
+        )
+        #merge the two Bst candidates
+        Bst = ParticleContainersMerger([Bst_1, Bst_2], name = 'Bst_combiner')
+
+        #prepare filtered pion
+        pion_cut = F.IS_ABS_ID('pi+')  # Getting the filtered pion candidates
+
+        code_pion = F.FILTER(pion_cut) @ F.GET_CHILDREN()
+        pion_TES = ThOrParticleSelection(
+            name="pion_iso",
+            InputParticles=Bst,
+            Functor=code_pion).OutputSelection
+        '''
+        #prepare filtered Bstm
+        Bstm_cut = F.IS_ABS_ID('B*+')  # Getting the filtered B*+ candidates
+
+        code_Bstm = F.FILTER(Bstm_cut) @ F.GET_CHILDREN()
+        Bstm_TES = ThOrParticleSelection(
+            name="Bstm_iso",
+            InputParticles=Bst,
+            Functor=code_Bstm).OutputSelection
+        '''
+    else : pion_TES = pions
+
+    #make Lc mu pi pi 
+    Bst_2pi_1 = ParticleCombiner(
+        Inputs=[Bstm, pion_TES, pion_TES],
+        name='Bst_2pi_1',
         DecayDescriptor='[B*0 -> B*- pi+ pi-]cc',
         CombinationCut=F.ALL,
-        CompositeCut=cut_composite,
+        CompositeCut=F.ALL,
         ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
         #OutputLevel=1
     )
-    #combine to make [B*0 -> B*- pi- pi-]cc
-    Bst_2 = ParticleCombiner(
-        Inputs=[Bstm, pions,pions],
-        name='Bst_2',
+    Bst_2pi_2 = ParticleCombiner(
+        Inputs=[Bstm, pion_TES, pion_TES],
+        name='Bst_2pi_2',
         DecayDescriptor='[B*0 -> B*- pi- pi-]cc',
         CombinationCut=F.ALL,
-        CompositeCut=cut_composite,
+        CompositeCut=F.ALL,
         ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
         #OutputLevel=1
     )
     #merge the two Bst candidates
-    Bst = ParticleContainersMerger([Bst_1, Bst_2], name = 'Bst_combiner')
-    return Bst
+    Bst_2pi = ParticleContainersMerger([Bst_2pi_1, Bst_2pi_2], name = 'Bst_2pi_combiner')
+
+
+    return Bst_2pi
 
-def get_functors(v2_pvs, rec_summary):
+
+
+
+
+def get_functors(MCTRUTH, v2_pvs, rec_summary):
     #define common variables for all fields (composite and basic)
     vars_common  = FunctorCollection()
     #all pvs: ip, ipchi2. The PV positions are stored in event variables
@@ -124,6 +171,25 @@ def get_functors(v2_pvs, rec_summary):
     vars_common += FC.Kinematics()
     vars_common['ETA']           = F.ETA
     vars_common['PHI']           = F.PHI
+    if MCTRUTH != 'None':
+        #mc vars
+        vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
+        vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
+        vars_common['TRUEETA'] = MCTRUTH(F.ETA)
+        vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
+        #type of the origin vertex
+        vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
+        #make some helper functions
+        MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
+        MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
+        vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
+        vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
+        vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
+        vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
+        for i in range(2,14):
+          prefix = "MC_GD_MOTHER_{}".format(i)
+          vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
+          vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
 
     #variables for composite particles
     vars_composite  = FunctorCollection()
@@ -189,9 +255,9 @@ def get_functors(v2_pvs, rec_summary):
     functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars)
     return functors
 
-def tuple_Bst(Bst, v2_pvs, rec_summary):
+def tuple_Bst(Bst, MCTRUTH,v2_pvs, rec_summary):
     #get functors
-    functors = get_functors(v2_pvs, rec_summary)
+    functors = get_functors(MCTRUTH,v2_pvs, rec_summary)
     vars_common = functors[0]
     vars_composite = functors[1]
     var_B = functors[2]
@@ -201,42 +267,59 @@ def tuple_Bst(Bst, v2_pvs, rec_summary):
     #variables for Sb field
     vars_Bst  = FunctorCollection()
     B_child   = F.CHILD(1, F.FORWARDARG0)
-    Epi_child = F.CHILD(2, F.FORWARDARG0)
-    bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+    Epi_child1 = F.CHILD(2, F.FORWARDARG0)
+    Epi_child2 = F.CHILD(3, F.FORWARDARG0)
+    bpv_pi1    = F.BPV(v2_pvs).bind(Epi_child1)
+    bpv_pi2    = F.BPV(v2_pvs).bind(Epi_child2)
     #diff in vtx chi2 with and without extra particle
     vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
     #IP and IPChi2 of extra particle wrt to Sb end vertex
-    vars_Bst['Epi_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
-    vars_Bst['Epi_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+    vars_Bst['Epi1_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child1)
+    vars_Bst['Epi1_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child1)
+    vars_Bst['Epi2_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child1)
+    vars_Bst['Epi2_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child1)
     #IP and IPChi2 of extra particle wrt to Lb end vertex
-    vars_Bst['Epi_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
-    vars_Bst['Epi_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+    vars_Bst['Epi1_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child1)
+    vars_Bst['Epi1_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child1)
+    vars_Bst['Epi2_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child2)
+    vars_Bst['Epi2_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child2)
     #angle between extra particle and Lb
-    vars_Bst['Epi_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+    vars_Bst['Epi1_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child1)
+    vars_Bst['Epi2_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child2)
     #diff in fd chi2 with and without extra particle
-    vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
-    vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+    vars_Bst['Delta_BPV_of_Epi1_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi1, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi1, B_child)
+    vars_Bst['Delta_BPV_of_Epi2_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi2, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi1, B_child)
+    vars_Bst['BPV_of_Epi1_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi1, F.FORWARDARGS)
+    vars_Bst['BPV_of_Epi2_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi2, F.FORWARDARGS)
     #IP chi2 of extra particle wrt PV and SV of Sb
-    vars_Bst['Epi_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
-    vars_Bst['Epi_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+    vars_Bst['Epi1_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child1)
+    vars_Bst['Epi1_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child1)
+    vars_Bst['Epi2_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child2)
+    vars_Bst['Epi2_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child2)
     #IP chi2 of extra particle wrt PV and SV of Bb
-    vars_Bst['Epi_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
-    vars_Bst['Epi_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+    vars_Bst['Epi1_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child1)
+    vars_Bst['Epi1_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child1)
+    vars_Bst['Epi2_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child2)
+    vars_Bst['Epi2_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child2)
     #DOCA and DOCACHI2 b/w Lb and extra particle
     vars_Bst['DOCA12']       = F.DOCA(1, 2)
     vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+    vars_Bst['DOCA13']       = F.DOCA(1, 3)
+    vars_Bst['DOCA12_CHI2_13']  = F.DOCACHI2(1, 3)
     #vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
     #vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
     #DOCACHI2 of extra particle wrt to mother i.e. Sb
     vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
     vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+    vars_Bst['MTDOCACHI2_3'] = F.MTDOCACHI2(3, v2_pvs)
 
     #Get mva output for 1st and 2nd pion
     #mva_first_pion = mva_functor_mu_inclusive(v2_pvs,2)[0]
-    vars_Bst['iso_mva_1'] = mva_functor_mu_inclusive(v2_pvs,2)    
+    vars_Bst['iso_mva_1'] = mva_functor_inclusive(v2_pvs,2)    
 
     #mva_second_pion = mva_functor_mu_inclusive(v2_pvs,3)[0]
-    vars_Bst['iso_mva_2'] = mva_functor_mu_inclusive(v2_pvs,3)    
+    vars_Bst['iso_mva_2'] = mva_functor_inclusive(v2_pvs,3)    
+    
     '''
     MVA_cut = mva_transform_output(0.05)
     #MVA_cut_functor = (mva_functor_mu_inclusive(v2_pvs,2) > MVA_cut & mva_functor_mu_inclusive(v2_pvs,3) > MVA_cut) 
@@ -293,27 +376,39 @@ def get_extra_pions():
 	return ParticleContainersMerger([long_pions, up_pions, down_pions],
 									name='Pions_combiner')
 
-def main(options: Options):
+def main(options: Options,data_or_mc='mc'):
 
     #define filer
     my_filter = create_lines_filter(name="Filter", lines=['SpruceSLB_LbToLcMuNu_LcToPKPi'])
 
     #get data and extra particles
     lb = get_particles("/Event/Spruce/SpruceSLB_LbToLcMuNu_LcToPKPi/Particles")
-    extra_particles = get_extra_pions()
 
     #get v2_pvs and rec_summary
     v2_pvs  = get_pvs()
     rec_summary = get_rec_summary()
 
-    #make sb candidate
-    Bst = make_Bst(lb, extra_particles,v2_pvs)
-    #MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+    if data_or_mc == 'mc':
+        extra_particles = get_particles("/Event/Spruce/SpruceSLB_LbToLcMuNu_LcToPKPi/SpruceSLB_LbToLcMuNu_LcToPKPi_extra_tracks")
+        #make sb candidate
+        Bst = make_Bst_2pi(lb, extra_particles,v2_pvs,'False')
+        MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+        tuple_file = tuple_Bst(Bst,MCTRUTH_Bst, v2_pvs, rec_summary)
 
-    tuple_file = tuple_Bst(Bst, v2_pvs, rec_summary)
+    elif data_or_mc == 'data':
+        extra_particles = get_extra_pions()
+        #make sb candidate
+        Bst = make_Bst_2pi(lb, extra_particles,v2_pvs,'True')
+        tuple_file = tuple_Bst(Bst,'None', v2_pvs, rec_summary)
 
     #define algorithms
     user_algorithms = {}
     user_algorithms['Alg'] = [my_filter, tuple_file]
 
     return make_config(options, user_algorithms)
+
+def MC_SLB_LbToLcMuNu_LcToPKPi(options: Options):
+	return main(options=options,data_or_mc='mc')
+
+def Data_SLB_LbToLcMuNu_LcToPKPi(options: Options):
+	return main(options=options,data_or_mc='data')
diff --git a/lb_lc_mu_2024data/Hlt1.py b/lb_lc_mu_2024data/Hlt1.py
new file mode 100644
index 0000000000..eeabcc4913
--- /dev/null
+++ b/lb_lc_mu_2024data/Hlt1.py
@@ -0,0 +1,18 @@
+###############################################################################
+# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+from Moore import Options
+from Moore.config import run_allen
+from RecoConf.hlt1_allen import allen_gaudi_config as allen_sequence
+
+def main(options: Options):
+    with allen_sequence.bind(sequence="hlt1_pp_matching_no_ut_1000KHz"):
+        return run_allen(options)
+
diff --git a/lb_lc_mu_2024data/Hlt2.py b/lb_lc_mu_2024data/Hlt2.py
new file mode 100644
index 0000000000..c9da3abacc
--- /dev/null
+++ b/lb_lc_mu_2024data/Hlt2.py
@@ -0,0 +1,55 @@
+###############################################################################
+# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+"""
+Stolen and adapted from Hlt/Hlt2Conf/options/hlt2_pp_expected_24_without_UT.py from v55r7.
+"""
+from Moore import Options,options, run_moore, config
+from Hlt2Conf.settings.defaults import get_default_hlt1_filter_code_for_hlt2
+from Hlt2Conf.lines.semileptonic.hlt2_semileptonic import hlt2_lbtolcmunu_lctopkpi_line
+from Moore.config import Hlt2Line,register_line_builder
+from Moore.streams import Stream, Streams, DETECTORS
+from RecoConf.event_filters import require_gec
+from RecoConf.global_tools import stateProvider_with_simplified_geom, trackMasterExtrapolator_with_simplified_geom
+from RecoConf.hlt2_global_reco import reconstruction as hlt2_reconstruction, make_light_reco_pr_kf_without_UT
+from RecoConf.reconstruction_objects import reconstruction,make_pvs
+from RecoConf.decoders import default_ft_decoding_version,default_VeloCluster_source
+from RecoConf.hlt2_tracking import (
+    make_TrackBestTrackCreator_tracks,
+    make_PrKalmanFilter_noUT_tracks,
+    make_PrKalmanFilter_Velo_tracks,
+    make_PrKalmanFilter_Seed_tracks,
+)
+import Functors as F
+from Functors.math import in_range
+import sys
+
+def make_lines():
+    lines = [hlt2_lbtolcmunu_lctopkpi_line()]
+    return lines
+
+public_tools = [
+    trackMasterExtrapolator_with_simplified_geom(),
+    stateProvider_with_simplified_geom(),
+]
+
+def main(options: Options):
+    # NOTE: the TBTC does not apply a chi2 cut because it is applied by the PrKF
+    with reconstruction.bind(from_file=False),\
+         hlt2_reconstruction.bind(make_reconstruction=make_light_reco_pr_kf_without_UT),\
+         require_gec.bind(skipUT=True),\
+         default_VeloCluster_source.bind(bank_type="VPRetinaCluster"),\
+         make_TrackBestTrackCreator_tracks.bind(max_ghost_prob=0.7, max_chi2ndof=sys.float_info.max),\
+         make_PrKalmanFilter_Velo_tracks.bind(max_chi2ndof=5.),\
+         make_PrKalmanFilter_noUT_tracks.bind(max_chi2ndof=4.),\
+         make_PrKalmanFilter_Seed_tracks.bind(max_chi2ndof=6.),\
+         get_default_hlt1_filter_code_for_hlt2.bind(code=r"Hlt1(?!PassthroughLargeEvent).*Decision"):
+        return run_moore(options, make_lines, public_tools)
+
diff --git a/lb_lc_mu_2024data/Spruce.py b/lb_lc_mu_2024data/Spruce.py
new file mode 100644
index 0000000000..0905170094
--- /dev/null
+++ b/lb_lc_mu_2024data/Spruce.py
@@ -0,0 +1,29 @@
+###############################################################################
+# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+#Example follows from hlt2_with_hlt1_decision.py
+from Moore import Options,options, run_moore, config
+from Hlt2Conf.lines.semileptonic.spruce_semileptonic import spruce_lbtolcmunu_lctopkpi_line
+from PyConf.application import configure_input, configure, default_raw_event
+from RecoConf.global_tools import stateProvider_with_simplified_geom
+from RecoConf.reconstruction_objects import reconstruction
+from PyConf.reading import reconstruction as reco_spruce, upfront_reconstruction as upfront_spruce
+from RecoConf.decoders import default_ft_decoding_version
+
+def make_lines():
+    lines = [spruce_lbtolcmunu_lctopkpi_line()]
+    return lines
+
+def main(options: Options):
+    public_tools = [stateProvider_with_simplified_geom()]
+    with reconstruction.bind(from_file=True, spruce=True),\
+      reco_spruce.bind(simulation=True),\
+      upfront_spruce.bind(simulation=True),\
+        return run_moore(options, make_lines, public_tools=public_tools)
diff --git a/lb_lc_mu_2024data/info.yaml b/lb_lc_mu_2024data/info.yaml
index e3ab539a95..b6c0066ad2 100644
--- a/lb_lc_mu_2024data/info.yaml
+++ b/lb_lc_mu_2024data/info.yaml
@@ -2,6 +2,114 @@ defaults:
   inform:
     - ching-hua.li@cern.ch
   wg: SL
+{%- set datasets = [
+  ('15576010','lb_lc2593_mu'),
+  ('15576011','lb_lc2625_mu'),
+  ('15876031','lb_lc2880_mu'),
+] %}
+
+{%- set polarity_variables = [
+  ('MagDown','sim-20231017-vc-md100'),
+  ('MagUp','sim-20231017-vc-mu100'),
+]%}
+
+{%- for polarity, cond_tag in polarity_variables %}
+  {%- for evttype, dk in datasets %}
+HLT1_{{dk}}_{{ polarity }}:
+  #application: "Moore/v55r7@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  input:
+    bk_query: "/MC/Dev/Beam6800GeV-expected-2024-{{polarity}}-Nu7.6-25ns-Pythia8/Sim10c/{{evttype}}/DIGI"
+    dq_flags:
+      - OK
+    n_test_lfns: 1
+  output: hlt1.dst
+  options:
+    entrypoint: lb_lc_mu_2024data.Hlt1:main
+    extra_options:
+      input_raw_format: 0.3
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      output_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      scheduler_legacy_mode: False
+      compression:
+        algorithm: ZSTD
+        level: 1
+        max_buffer_size: 1048576
+      #evt_max: 1000 
+
+HLT2_{{dk}}_{{ polarity }}:
+  #application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  input:
+    job_name: HLT1_{{dk}}_{{ polarity }}
+  output: hlt2.dst
+  options:
+    entrypoint: lb_lc_mu_2024data.Hlt2:main
+    extra_options:
+      input_raw_format: 0.5
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      output_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      scheduler_legacy_mode: False
+      output_manifest_file: "HLT2.tck.json" 
+      compression:
+        algorithm: ZSTD
+        level: 1
+        max_buffer_size: 1048576
+      #evt_max: 1000
+SPRUCE_{{dk}}_{{ polarity }}:
+  #application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  input:
+    job_name: HLT2_{{dk}}_{{ polarity }}
+  output: spruce.dst
+  options:
+    entrypoint: lb_lc_mu_2024data.Spruce:main
+    extra_options:
+      input_raw_format: 0.5
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      output_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      scheduler_legacy_mode: False
+      input_process: "Hlt2"
+      input_manifest_file: "HLT2.tck.json"
+      output_manifest_file: "SPRUCE.tck.json" 
+      compression:
+        algorithm: ZSTD
+        level: 1
+        max_buffer_size: 1048576
+      #evt_max: 1000
+DV_{{dk}}_{{ polarity }}:
+  application: "DaVinci/v64r5@x86_64_v2-el9-clang16-opt"
+  input:
+    job_name: SPRUCE_{{dk}}_{{ polarity }}
+  output: NTuple.root
+  options:
+    entrypoint: lb_lc_mu_2024data.DV:MC_SLB_LbToLcMuNu_LcToPKPi
+    extra_options:
+      input_raw_format: 0.5
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      #geometry_version: run3/2024.Q1.2-v00.00
+      input_process: "Spruce"
+      input_manifest_file: "SPRUCE.tck.json"
+      #evt_max: 1000
+
+  {%- endfor %}
+{%- endfor %}
 
 data_lb_lc_mu:
   application: "DaVinci/v64r5"
@@ -14,7 +122,7 @@ data_lb_lc_mu:
     n_test_lfns: 1 
   output: DATA.ROOT
   options:
-    entrypoint: lb_lc_mu_2024data.DV:main
+    entrypoint: lb_lc_mu_2024data.DV:Data_SLB_LbToLcMuNu_LcToPKPi
     extra_options:
       input_raw_format: 0.5
       input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
-- 
GitLab


From 811e6c43d450e83e5f17cdff82334a4b589630a3 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Sat, 20 Jul 2024 23:59:51 +0200
Subject: [PATCH 48/57] Fix bug

---
 lb_lc_mu_2024data/Spruce.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lb_lc_mu_2024data/Spruce.py b/lb_lc_mu_2024data/Spruce.py
index 0905170094..b864401501 100644
--- a/lb_lc_mu_2024data/Spruce.py
+++ b/lb_lc_mu_2024data/Spruce.py
@@ -25,5 +25,5 @@ def main(options: Options):
     public_tools = [stateProvider_with_simplified_geom()]
     with reconstruction.bind(from_file=True, spruce=True),\
       reco_spruce.bind(simulation=True),\
-      upfront_spruce.bind(simulation=True),\
+      upfront_spruce.bind(simulation=True):
         return run_moore(options, make_lines, public_tools=public_tools)
-- 
GitLab


From 281be48d9fb292cc224dc0541c9cd29a8f7ef9e9 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Tue, 30 Jul 2024 08:51:20 +0200
Subject: [PATCH 49/57] Change DV version

---
 lb_lc_mu_2024data/info.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lb_lc_mu_2024data/info.yaml b/lb_lc_mu_2024data/info.yaml
index b6c0066ad2..94531e876e 100644
--- a/lb_lc_mu_2024data/info.yaml
+++ b/lb_lc_mu_2024data/info.yaml
@@ -90,7 +90,7 @@ SPRUCE_{{dk}}_{{ polarity }}:
         max_buffer_size: 1048576
       #evt_max: 1000
 DV_{{dk}}_{{ polarity }}:
-  application: "DaVinci/v64r5@x86_64_v2-el9-clang16-opt"
+  application: "DaVinci/v64r7@x86_64_v2-el9-clang16-opt"
   input:
     job_name: SPRUCE_{{dk}}_{{ polarity }}
   output: NTuple.root
@@ -112,7 +112,7 @@ DV_{{dk}}_{{ polarity }}:
 {%- endfor %}
 
 data_lb_lc_mu:
-  application: "DaVinci/v64r5"
+  application: "DaVinci/v64r7@x86_64_v2-el9-clang16-opt"
   input:
     bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-MagDown-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
     dq_flags:
-- 
GitLab


From b32e3e2269c50268802f68a1299b449ee59f2fe8 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Wed, 14 Aug 2024 10:36:22 +0200
Subject: [PATCH 50/57] add everything

---
 lb_lc_mu_2024data/DV.py           | 414 ------------------------------
 lb_lc_mu_2024data/Hlt1.py         |  18 --
 lb_lc_mu_2024data/Hlt2.py         |  55 ----
 lb_lc_mu_2024data/Spruce.py       |  29 ---
 lb_lc_mu_2024data/info.yaml       | 136 ----------
 lb_lc_mu_2024data/isolationMVA.py | 139 ----------
 6 files changed, 791 deletions(-)
 delete mode 100644 lb_lc_mu_2024data/DV.py
 delete mode 100644 lb_lc_mu_2024data/Hlt1.py
 delete mode 100644 lb_lc_mu_2024data/Hlt2.py
 delete mode 100644 lb_lc_mu_2024data/Spruce.py
 delete mode 100644 lb_lc_mu_2024data/info.yaml
 delete mode 100644 lb_lc_mu_2024data/isolationMVA.py

diff --git a/lb_lc_mu_2024data/DV.py b/lb_lc_mu_2024data/DV.py
deleted file mode 100644
index ce3f7eef71..0000000000
--- a/lb_lc_mu_2024data/DV.py
+++ /dev/null
@@ -1,414 +0,0 @@
-###############################################################################
-# (c) Copyright 2024 CERN for the benefit of the LHCb Collaboration           #
-#                                                                             #
-# This software is distributed under the terms of the GNU General Public      #
-# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
-#                                                                             #
-# In applying this licence, CERN does not waive the privileges and immunities #
-# granted to it by virtue of its status as an Intergovernmental Organization  #
-# or submit itself to any jurisdiction.                                       #
-###############################################################################
-import sys
-from DaVinci import Options,make_config
-from PyConf.reading import get_pvs, get_rec_summary, get_particles
-from PyConf.Algorithms import ThOrParticleSelection
-import Functors as F
-from FunTuple import FunctorCollection
-from FunTuple import FunTuple_Particles as Funtuple
-from DaVinci.algorithms import create_lines_filter
-import FunTuple.functorcollections as FC
-from DaVinciMCTools import MCTruthAndBkgCat
-from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
-from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
-from Hlt2Conf.algorithms_thor import ParticleContainersMerger
-from Functors.grammar import Functor
-from Hlt2Conf.lines.semileptonic.isolationMVA import mva_functor_mu_inclusive,mva_transform_output
-from .isolationMVA import mva_functor_mu_inclusive as mva_functor_inclusive
-
-
-_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
-_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
-_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
-#ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
-#ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
-ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
-ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
-
-TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
-
-def make_Bst_2pi(B, pions,v2_pvs,prepare_pion):
-
-    hadron_cut = F.IS_ABS_ID('Lambda_c+')  # Getting the hadron candidates
-
-    code_hadron = F.FILTER(hadron_cut) @ F.GET_CHILDREN()
-    hadron_TES = ThOrParticleSelection(
-        name="hadron_iso",
-        InputParticles=B,
-        Functor=code_hadron).OutputSelection
-
-    lepton_cut = F.IS_ABS_ID('mu-')
-    code_lepton = F.FILTER(lepton_cut) @ F.GET_CHILDREN()
-    lepton_TES = ThOrParticleSelection(
-        name="lepton_iso",
-        InputParticles=B,
-        Functor=code_lepton).OutputSelection
-
-
-    #combine to make [B*- -> Lambda_c+ mu-]cc
-    Bstm = ParticleCombiner(
-        Inputs=[hadron_TES, lepton_TES],
-        name=f'Bstm_mu',
-        DecayDescriptor='[B*- -> Lambda_c+ mu-]cc',
-        CombinationCut=F.ALL,
-        CompositeCut=F.ALL,
-        ParticleCombiner="ParticleVertexFitter",
-    )
-
-    #cut_combination = F.require_all(F.MAXDOCA < 8.0, F.MAXDOCACHI2 < 20)
-
-    if prepare_pion=='True':
-        MVA_cut = mva_transform_output(0.05)
-        cut_composite = F.require_all(mva_functor_mu_inclusive(v2_pvs)[0] > MVA_cut)
-
-        #first make [B*0 -> B*- pi+]cc
-        Bst_1 = ParticleCombiner(
-            Inputs=[Bstm, pions],
-            name='Bst_1',
-            DecayDescriptor='[B*0 -> B*- pi+]cc',
-            CombinationCut=F.ALL,
-            CompositeCut=cut_composite,
-            ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
-            #OutputLevel=1
-        )
-        Bst_2 = ParticleCombiner(
-            Inputs=[Bstm, pions],
-            name='Bst_2',
-            DecayDescriptor='[B*0 -> B*- pi-]cc',
-            CombinationCut=F.ALL,
-            CompositeCut=cut_composite,
-            ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
-            #OutputLevel=1
-        )
-        #merge the two Bst candidates
-        Bst = ParticleContainersMerger([Bst_1, Bst_2], name = 'Bst_combiner')
-
-        #prepare filtered pion
-        pion_cut = F.IS_ABS_ID('pi+')  # Getting the filtered pion candidates
-
-        code_pion = F.FILTER(pion_cut) @ F.GET_CHILDREN()
-        pion_TES = ThOrParticleSelection(
-            name="pion_iso",
-            InputParticles=Bst,
-            Functor=code_pion).OutputSelection
-        '''
-        #prepare filtered Bstm
-        Bstm_cut = F.IS_ABS_ID('B*+')  # Getting the filtered B*+ candidates
-
-        code_Bstm = F.FILTER(Bstm_cut) @ F.GET_CHILDREN()
-        Bstm_TES = ThOrParticleSelection(
-            name="Bstm_iso",
-            InputParticles=Bst,
-            Functor=code_Bstm).OutputSelection
-        '''
-    else : pion_TES = pions
-
-    #make Lc mu pi pi 
-    Bst_2pi_1 = ParticleCombiner(
-        Inputs=[Bstm, pion_TES, pion_TES],
-        name='Bst_2pi_1',
-        DecayDescriptor='[B*0 -> B*- pi+ pi-]cc',
-        CombinationCut=F.ALL,
-        CompositeCut=F.ALL,
-        ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
-        #OutputLevel=1
-    )
-    Bst_2pi_2 = ParticleCombiner(
-        Inputs=[Bstm, pion_TES, pion_TES],
-        name='Bst_2pi_2',
-        DecayDescriptor='[B*0 -> B*- pi- pi-]cc',
-        CombinationCut=F.ALL,
-        CompositeCut=F.ALL,
-        ParticleCombiner="ParticleVertexFitter",  #for neutrals need to use different combiner e.g. ParticleAdder
-        #OutputLevel=1
-    )
-    #merge the two Bst candidates
-    Bst_2pi = ParticleContainersMerger([Bst_2pi_1, Bst_2pi_2], name = 'Bst_2pi_combiner')
-
-
-    return Bst_2pi
-
-
-
-
-
-def get_functors(MCTRUTH, v2_pvs, rec_summary):
-    #define common variables for all fields (composite and basic)
-    vars_common  = FunctorCollection()
-    #all pvs: ip, ipchi2. The PV positions are stored in event variables
-    vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
-    vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
-    #best pv: x, y, z, ip, ipchi2
-    vars_common['BPV_X']          = F.BPVX(v2_pvs)
-    vars_common['BPV_Y']          = F.BPVY(v2_pvs)
-    vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
-    vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
-    vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
-    vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
-    vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
-    #particle id, key, truekey. The trueid is stored in MCHierarchy
-    vars_common['ID']            = F.PARTICLE_ID
-    vars_common['KEY']           = F.OBJECT_KEY
-    #get charge, min ip and min ipchi2
-    vars_common['CHARGE']        = F.CHARGE
-    vars_common['MINIP']         = F.MINIP(v2_pvs)
-    vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
-    #reco kinematics
-    vars_common += FC.Kinematics()
-    vars_common['ETA']           = F.ETA
-    vars_common['PHI']           = F.PHI
-    if MCTRUTH != 'None':
-        #mc vars
-        vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
-        vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
-        vars_common['TRUEETA'] = MCTRUTH(F.ETA)
-        vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
-        #type of the origin vertex
-        vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
-        #make some helper functions
-        MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
-        MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
-        vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
-        vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
-        vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
-        vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
-        for i in range(2,14):
-          prefix = "MC_GD_MOTHER_{}".format(i)
-          vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
-          vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
-
-    #variables for composite particles
-    vars_composite  = FunctorCollection()
-    #end vertex position and end vertex chi2
-    vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
-    vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
-    vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
-    #all pvs: dira, fd, fdchi2
-    vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
-    vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
-    vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
-    vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
-    vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
-    vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
-    vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
-    vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
-    #best pv: dira, fd, fdchi2, corrm, ltime, dls
-    vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
-    vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
-    vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
-    vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
-    vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
-    vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
-    #Compute maximum DOCA and maximum DOCACHI2. Since there are 
-    # only two daughters of Sb particles, the maximum DOCA/DOCACHI2 is 
-    # the DOCA/DOCACHI2 see below.
-    vars_composite['MAX_DOCA'] = F.MAXDOCA
-    vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
-    vars_composite['MAX_SDOCA'] = F.MAXSDOCA
-    vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
-
-    #variables for Lb field
-    var_B  = FunctorCollection()
-
-    #variables for basics
-    vars_basic  = FunctorCollection()
-    vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
-    vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
-    vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
-    vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
-    vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
-    vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
-    vars_basic['GHOSTPROB'] = F.GHOSTPROB
-    vars_basic['PIDpi'] = F.PID_PI
-    vars_basic['PIDk']  = F.PID_K
-    vars_basic['PIDp']  = F.PID_P
-    vars_basic['PIDe']  = F.PID_E
-    vars_basic['PIDmu'] = F.PID_MU
-
-    #variables for event
-    evt_vars = FunctorCollection()
-    #evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
-    #evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
-    #evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
-    #evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
-    #evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
-    evt_vars['nTracks']     = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nTracks")
-    evt_vars['nLongTracks'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks")
-    evt_vars['nPVs']        = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs")
-    evt_vars['nFTClusters'] = F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nFTClusters")
-
-    #return all functors
-    functors = (vars_common, vars_composite, var_B, vars_basic, evt_vars)
-    return functors
-
-def tuple_Bst(Bst, MCTRUTH,v2_pvs, rec_summary):
-    #get functors
-    functors = get_functors(MCTRUTH,v2_pvs, rec_summary)
-    vars_common = functors[0]
-    vars_composite = functors[1]
-    var_B = functors[2]
-    vars_basic = functors[3]
-    evt_vars = functors[4]
-
-    #variables for Sb field
-    vars_Bst  = FunctorCollection()
-    B_child   = F.CHILD(1, F.FORWARDARG0)
-    Epi_child1 = F.CHILD(2, F.FORWARDARG0)
-    Epi_child2 = F.CHILD(3, F.FORWARDARG0)
-    bpv_pi1    = F.BPV(v2_pvs).bind(Epi_child1)
-    bpv_pi2    = F.BPV(v2_pvs).bind(Epi_child2)
-    #diff in vtx chi2 with and without extra particle
-    vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
-    #IP and IPChi2 of extra particle wrt to Sb end vertex
-    vars_Bst['Epi1_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child1)
-    vars_Bst['Epi1_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child1)
-    vars_Bst['Epi2_IP_WRT_SbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child1)
-    vars_Bst['Epi2_IPCHI2_WRT_SbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child1)
-    #IP and IPChi2 of extra particle wrt to Lb end vertex
-    vars_Bst['Epi1_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child1)
-    vars_Bst['Epi1_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child1)
-    vars_Bst['Epi2_IP_WRT_LbENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child2)
-    vars_Bst['Epi2_IPCHI2_WRT_LbENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child2)
-    #angle between extra particle and Lb
-    vars_Bst['Epi1_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child1)
-    vars_Bst['Epi2_COSANGLE_Lb']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child2)
-    #diff in fd chi2 with and without extra particle
-    vars_Bst['Delta_BPV_of_Epi1_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi1, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi1, B_child)
-    vars_Bst['Delta_BPV_of_Epi2_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi2, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi1, B_child)
-    vars_Bst['BPV_of_Epi1_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi1, F.FORWARDARGS)
-    vars_Bst['BPV_of_Epi2_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi2, F.FORWARDARGS)
-    #IP chi2 of extra particle wrt PV and SV of Sb
-    vars_Bst['Epi1_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child1)
-    vars_Bst['Epi1_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child1)
-    vars_Bst['Epi2_IP_WRT_SbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child2)
-    vars_Bst['Epi2_IPCHI2_WRT_SbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child2)
-    #IP chi2 of extra particle wrt PV and SV of Bb
-    vars_Bst['Epi1_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child1)
-    vars_Bst['Epi1_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child1)
-    vars_Bst['Epi2_IP_WRT_LbBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child2)
-    vars_Bst['Epi2_IPCHI2_WRT_LbBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child2)
-    #DOCA and DOCACHI2 b/w Lb and extra particle
-    vars_Bst['DOCA12']       = F.DOCA(1, 2)
-    vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
-    vars_Bst['DOCA13']       = F.DOCA(1, 3)
-    vars_Bst['DOCA12_CHI2_13']  = F.DOCACHI2(1, 3)
-    #vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
-    #vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
-    #DOCACHI2 of extra particle wrt to mother i.e. Sb
-    vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
-    vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
-    vars_Bst['MTDOCACHI2_3'] = F.MTDOCACHI2(3, v2_pvs)
-
-    #Get mva output for 1st and 2nd pion
-    #mva_first_pion = mva_functor_mu_inclusive(v2_pvs,2)[0]
-    vars_Bst['iso_mva_1'] = mva_functor_inclusive(v2_pvs,2)    
-
-    #mva_second_pion = mva_functor_mu_inclusive(v2_pvs,3)[0]
-    vars_Bst['iso_mva_2'] = mva_functor_inclusive(v2_pvs,3)    
-    
-    '''
-    MVA_cut = mva_transform_output(0.05)
-    #MVA_cut_functor = (mva_functor_mu_inclusive(v2_pvs,2) > MVA_cut & mva_functor_mu_inclusive(v2_pvs,3) > MVA_cut) 
-    MVA_cut_functor = F.require_all(mva_functor_mu_inclusive(v2_pvs,2) > MVA_cut,mva_functor_mu_inclusive(v2_pvs,3) > MVA_cut)
-    Bst_mva_cut = ParticleFilter(
-        Bst, F.FILTER(MVA_cut_functor), name="filter_isoPions"
-    )  # B + extra track combos passing the MVA cuts
-    '''
-    #define fields
-    fields_mu = {}
-    fields_mu['Sb']    = '[B*0 ->  (B*- ->  Lambda_c+  mu-)  [pi+]CC pi-]CC'
-    fields_mu['Lb']    = '[B*0 -> ^(B*- ->  Lambda_c+  mu-)  [pi+]CC pi-]CC'
-    fields_mu['Lc']    = '[B*0 ->  (B*- -> ^Lambda_c+  mu-)  [pi+]CC pi-]CC'
-    fields_mu['Lep']   = '[B*0 ->  (B*- ->  Lambda_c+ ^mu-)  [pi+]CC pi-]CC'
-    fields_mu['Epi1']   = '[B*0 ->  (B*- ->  Lambda_c+  mu-) ^[pi+]CC pi-]CC'
-    fields_mu['Epi2']   = '[B*0 ->  (B*- ->  Lambda_c+  mu-) [pi+]CC ^pi-]CC'
-    fields_mu['p']    = '[B*0 ->  (B*- -> (Lambda_c+ -> ^p+ K- pi+)  mu-)  [pi+]CC pi-]CC'
-    fields_mu['Km']   = '[B*0 ->  (B*- -> (Lambda_c+ -> p+ ^K- pi+)  mu-)  [pi+]CC pi-]CC'
-    fields_mu['pip']  = '[B*0 ->  (B*- -> (Lambda_c+ -> p+ K- ^pi+)  mu-)  [pi+]CC pi-]CC'
-
-    #add variables
-    variables = {}
-    variables["ALL"] = vars_common
-    variables["Sb"]  = vars_composite + vars_Bst
-    variables["Lb"]  = vars_composite + var_B
-    variables["Lc"]  = vars_composite
-    variables["Lep"] = vars_basic
-    variables["Epi1"] = vars_basic
-    variables["Epi2"] = vars_basic
-    variables["p"]  = vars_basic
-    variables["Km"] = vars_basic
-    variables["pip"]= vars_basic
-
-    #define tuple
-    my_tuple = Funtuple(
-        name="Tuple",
-        tuple_name="DecayTree",
-        fields=fields_mu,
-        variables=variables,
-        event_variables=evt_vars,
-        inputs=Bst)
-
-    return my_tuple
-
-def get_extra_pions():
-	"""
-	Note this function in DaVinci requires:
-	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
-	and it's related LHCb, DaVinci and Rec MRs
-	"""
-	long_pions = make_has_rich_long_pions()
-	up_pions = make_has_rich_up_pions()
-	down_pions = make_has_rich_down_pions()
-	return ParticleContainersMerger([long_pions, up_pions, down_pions],
-									name='Pions_combiner')
-
-def main(options: Options,data_or_mc='mc'):
-
-    #define filer
-    my_filter = create_lines_filter(name="Filter", lines=['SpruceSLB_LbToLcMuNu_LcToPKPi'])
-
-    #get data and extra particles
-    lb = get_particles("/Event/Spruce/SpruceSLB_LbToLcMuNu_LcToPKPi/Particles")
-
-    #get v2_pvs and rec_summary
-    v2_pvs  = get_pvs()
-    rec_summary = get_rec_summary()
-
-    if data_or_mc == 'mc':
-        extra_particles = get_particles("/Event/Spruce/SpruceSLB_LbToLcMuNu_LcToPKPi/SpruceSLB_LbToLcMuNu_LcToPKPi_extra_tracks")
-        #make sb candidate
-        Bst = make_Bst_2pi(lb, extra_particles,v2_pvs,'False')
-        MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
-        tuple_file = tuple_Bst(Bst,MCTRUTH_Bst, v2_pvs, rec_summary)
-
-    elif data_or_mc == 'data':
-        extra_particles = get_extra_pions()
-        #make sb candidate
-        Bst = make_Bst_2pi(lb, extra_particles,v2_pvs,'True')
-        tuple_file = tuple_Bst(Bst,'None', v2_pvs, rec_summary)
-
-    #define algorithms
-    user_algorithms = {}
-    user_algorithms['Alg'] = [my_filter, tuple_file]
-
-    return make_config(options, user_algorithms)
-
-def MC_SLB_LbToLcMuNu_LcToPKPi(options: Options):
-	return main(options=options,data_or_mc='mc')
-
-def Data_SLB_LbToLcMuNu_LcToPKPi(options: Options):
-	return main(options=options,data_or_mc='data')
diff --git a/lb_lc_mu_2024data/Hlt1.py b/lb_lc_mu_2024data/Hlt1.py
deleted file mode 100644
index eeabcc4913..0000000000
--- a/lb_lc_mu_2024data/Hlt1.py
+++ /dev/null
@@ -1,18 +0,0 @@
-###############################################################################
-# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
-#                                                                             #
-# This software is distributed under the terms of the GNU General Public      #
-# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
-#                                                                             #
-# In applying this licence, CERN does not waive the privileges and immunities #
-# granted to it by virtue of its status as an Intergovernmental Organization  #
-# or submit itself to any jurisdiction.                                       #
-###############################################################################
-from Moore import Options
-from Moore.config import run_allen
-from RecoConf.hlt1_allen import allen_gaudi_config as allen_sequence
-
-def main(options: Options):
-    with allen_sequence.bind(sequence="hlt1_pp_matching_no_ut_1000KHz"):
-        return run_allen(options)
-
diff --git a/lb_lc_mu_2024data/Hlt2.py b/lb_lc_mu_2024data/Hlt2.py
deleted file mode 100644
index c9da3abacc..0000000000
--- a/lb_lc_mu_2024data/Hlt2.py
+++ /dev/null
@@ -1,55 +0,0 @@
-###############################################################################
-# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
-#                                                                             #
-# This software is distributed under the terms of the GNU General Public      #
-# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
-#                                                                             #
-# In applying this licence, CERN does not waive the privileges and immunities #
-# granted to it by virtue of its status as an Intergovernmental Organization  #
-# or submit itself to any jurisdiction.                                       #
-###############################################################################
-"""
-Stolen and adapted from Hlt/Hlt2Conf/options/hlt2_pp_expected_24_without_UT.py from v55r7.
-"""
-from Moore import Options,options, run_moore, config
-from Hlt2Conf.settings.defaults import get_default_hlt1_filter_code_for_hlt2
-from Hlt2Conf.lines.semileptonic.hlt2_semileptonic import hlt2_lbtolcmunu_lctopkpi_line
-from Moore.config import Hlt2Line,register_line_builder
-from Moore.streams import Stream, Streams, DETECTORS
-from RecoConf.event_filters import require_gec
-from RecoConf.global_tools import stateProvider_with_simplified_geom, trackMasterExtrapolator_with_simplified_geom
-from RecoConf.hlt2_global_reco import reconstruction as hlt2_reconstruction, make_light_reco_pr_kf_without_UT
-from RecoConf.reconstruction_objects import reconstruction,make_pvs
-from RecoConf.decoders import default_ft_decoding_version,default_VeloCluster_source
-from RecoConf.hlt2_tracking import (
-    make_TrackBestTrackCreator_tracks,
-    make_PrKalmanFilter_noUT_tracks,
-    make_PrKalmanFilter_Velo_tracks,
-    make_PrKalmanFilter_Seed_tracks,
-)
-import Functors as F
-from Functors.math import in_range
-import sys
-
-def make_lines():
-    lines = [hlt2_lbtolcmunu_lctopkpi_line()]
-    return lines
-
-public_tools = [
-    trackMasterExtrapolator_with_simplified_geom(),
-    stateProvider_with_simplified_geom(),
-]
-
-def main(options: Options):
-    # NOTE: the TBTC does not apply a chi2 cut because it is applied by the PrKF
-    with reconstruction.bind(from_file=False),\
-         hlt2_reconstruction.bind(make_reconstruction=make_light_reco_pr_kf_without_UT),\
-         require_gec.bind(skipUT=True),\
-         default_VeloCluster_source.bind(bank_type="VPRetinaCluster"),\
-         make_TrackBestTrackCreator_tracks.bind(max_ghost_prob=0.7, max_chi2ndof=sys.float_info.max),\
-         make_PrKalmanFilter_Velo_tracks.bind(max_chi2ndof=5.),\
-         make_PrKalmanFilter_noUT_tracks.bind(max_chi2ndof=4.),\
-         make_PrKalmanFilter_Seed_tracks.bind(max_chi2ndof=6.),\
-         get_default_hlt1_filter_code_for_hlt2.bind(code=r"Hlt1(?!PassthroughLargeEvent).*Decision"):
-        return run_moore(options, make_lines, public_tools)
-
diff --git a/lb_lc_mu_2024data/Spruce.py b/lb_lc_mu_2024data/Spruce.py
deleted file mode 100644
index b864401501..0000000000
--- a/lb_lc_mu_2024data/Spruce.py
+++ /dev/null
@@ -1,29 +0,0 @@
-###############################################################################
-# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
-#                                                                             #
-# This software is distributed under the terms of the GNU General Public      #
-# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
-#                                                                             #
-# In applying this licence, CERN does not waive the privileges and immunities #
-# granted to it by virtue of its status as an Intergovernmental Organization  #
-# or submit itself to any jurisdiction.                                       #
-###############################################################################
-#Example follows from hlt2_with_hlt1_decision.py
-from Moore import Options,options, run_moore, config
-from Hlt2Conf.lines.semileptonic.spruce_semileptonic import spruce_lbtolcmunu_lctopkpi_line
-from PyConf.application import configure_input, configure, default_raw_event
-from RecoConf.global_tools import stateProvider_with_simplified_geom
-from RecoConf.reconstruction_objects import reconstruction
-from PyConf.reading import reconstruction as reco_spruce, upfront_reconstruction as upfront_spruce
-from RecoConf.decoders import default_ft_decoding_version
-
-def make_lines():
-    lines = [spruce_lbtolcmunu_lctopkpi_line()]
-    return lines
-
-def main(options: Options):
-    public_tools = [stateProvider_with_simplified_geom()]
-    with reconstruction.bind(from_file=True, spruce=True),\
-      reco_spruce.bind(simulation=True),\
-      upfront_spruce.bind(simulation=True):
-        return run_moore(options, make_lines, public_tools=public_tools)
diff --git a/lb_lc_mu_2024data/info.yaml b/lb_lc_mu_2024data/info.yaml
deleted file mode 100644
index 94531e876e..0000000000
--- a/lb_lc_mu_2024data/info.yaml
+++ /dev/null
@@ -1,136 +0,0 @@
-defaults:
-  inform:
-    - ching-hua.li@cern.ch
-  wg: SL
-{%- set datasets = [
-  ('15576010','lb_lc2593_mu'),
-  ('15576011','lb_lc2625_mu'),
-  ('15876031','lb_lc2880_mu'),
-] %}
-
-{%- set polarity_variables = [
-  ('MagDown','sim-20231017-vc-md100'),
-  ('MagUp','sim-20231017-vc-mu100'),
-]%}
-
-{%- for polarity, cond_tag in polarity_variables %}
-  {%- for evttype, dk in datasets %}
-HLT1_{{dk}}_{{ polarity }}:
-  #application: "Moore/v55r7@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  input:
-    bk_query: "/MC/Dev/Beam6800GeV-expected-2024-{{polarity}}-Nu7.6-25ns-Pythia8/Sim10c/{{evttype}}/DIGI"
-    dq_flags:
-      - OK
-    n_test_lfns: 1
-  output: hlt1.dst
-  options:
-    entrypoint: lb_lc_mu_2024data.Hlt1:main
-    extra_options:
-      input_raw_format: 0.3
-      conddb_tag: {{cond_tag}}
-      dddb_tag: dddb-20231017
-      input_type: ROOT
-      output_type: ROOT
-      simulation: True
-      data_type: "Upgrade"
-      scheduler_legacy_mode: False
-      compression:
-        algorithm: ZSTD
-        level: 1
-        max_buffer_size: 1048576
-      #evt_max: 1000 
-
-HLT2_{{dk}}_{{ polarity }}:
-  #application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  input:
-    job_name: HLT1_{{dk}}_{{ polarity }}
-  output: hlt2.dst
-  options:
-    entrypoint: lb_lc_mu_2024data.Hlt2:main
-    extra_options:
-      input_raw_format: 0.5
-      conddb_tag: {{cond_tag}}
-      dddb_tag: dddb-20231017
-      input_type: ROOT
-      output_type: ROOT
-      simulation: True
-      data_type: "Upgrade"
-      scheduler_legacy_mode: False
-      output_manifest_file: "HLT2.tck.json" 
-      compression:
-        algorithm: ZSTD
-        level: 1
-        max_buffer_size: 1048576
-      #evt_max: 1000
-SPRUCE_{{dk}}_{{ polarity }}:
-  #application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
-  input:
-    job_name: HLT2_{{dk}}_{{ polarity }}
-  output: spruce.dst
-  options:
-    entrypoint: lb_lc_mu_2024data.Spruce:main
-    extra_options:
-      input_raw_format: 0.5
-      conddb_tag: {{cond_tag}}
-      dddb_tag: dddb-20231017
-      input_type: ROOT
-      output_type: ROOT
-      simulation: True
-      data_type: "Upgrade"
-      scheduler_legacy_mode: False
-      input_process: "Hlt2"
-      input_manifest_file: "HLT2.tck.json"
-      output_manifest_file: "SPRUCE.tck.json" 
-      compression:
-        algorithm: ZSTD
-        level: 1
-        max_buffer_size: 1048576
-      #evt_max: 1000
-DV_{{dk}}_{{ polarity }}:
-  application: "DaVinci/v64r7@x86_64_v2-el9-clang16-opt"
-  input:
-    job_name: SPRUCE_{{dk}}_{{ polarity }}
-  output: NTuple.root
-  options:
-    entrypoint: lb_lc_mu_2024data.DV:MC_SLB_LbToLcMuNu_LcToPKPi
-    extra_options:
-      input_raw_format: 0.5
-      conddb_tag: {{cond_tag}}
-      dddb_tag: dddb-20231017
-      input_type: ROOT
-      simulation: True
-      data_type: "Upgrade"
-      #geometry_version: run3/2024.Q1.2-v00.00
-      input_process: "Spruce"
-      input_manifest_file: "SPRUCE.tck.json"
-      #evt_max: 1000
-
-  {%- endfor %}
-{%- endfor %}
-
-data_lb_lc_mu:
-  application: "DaVinci/v64r7@x86_64_v2-el9-clang16-opt"
-  input:
-    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-MagDown-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
-    dq_flags:
-      - UNCHECKED
-      - OK
-    keep_running: true
-    n_test_lfns: 1 
-  output: DATA.ROOT
-  options:
-    entrypoint: lb_lc_mu_2024data.DV:Data_SLB_LbToLcMuNu_LcToPKPi
-    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: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
-      input_stream: "sl" # for streamed data
-      #evt_max: 1000
-
diff --git a/lb_lc_mu_2024data/isolationMVA.py b/lb_lc_mu_2024data/isolationMVA.py
deleted file mode 100644
index 92f9ae0700..0000000000
--- a/lb_lc_mu_2024data/isolationMVA.py
+++ /dev/null
@@ -1,139 +0,0 @@
-###############################################################################
-# (c) Copyright 2024 CERN for the benefit of the LHCb Collaboration           #
-#                                                                             #
-# This software is distributed under the terms of the GNU General Public      #
-# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
-#                                                                             #
-# In applying this licence, CERN does not waive the privileges and immunities #
-# granted to it by virtue of its status as an Intergovernmental Organization  #
-# or submit itself to any jurisdiction.                                       #
-###############################################################################
-import Functors as F
-from Hlt2Conf.algorithms_thor import ParticleCombiner
-from Hlt2Conf.algorithms_thor import ParticleContainersMerger
-from Hlt2Conf.algorithms_thor import ParticleFilter
-from RecoConf.reconstruction_objects import make_pvs
-import Functors.math as fmath
-import math
-import re
-from dataclasses import dataclass
-from PyConf.Algorithms import ThOrParticleSelection
-
-#Multiplying by this number will convert log_e to log_10
-#we multiply by log10(e) rather than dividing by ln(10)
-#since multiplication is faster
-LOG10_E = math.log10(math.e)
-#toggle for printing debug messages
-#set to False for proper productions
-DEBUG = False
-
-
-@dataclass
-class MVAinput:
-    """Struct for storing MVA input variables"""
-    name: str  # The name of the var (as per the model)
-    number: int  # The number of the var
-    functor: F.grammar.FunctorBase  # The functor to calculate that variable
-    x_range: (float, float)  # axis range for input var monitoring histos
-
-
-def mva_functor_mu_inclusive(v2_pvs,
-                             index_pion,
-                             useNumbers: bool = False):
-    """
-    Compute the output of the MVA classifier (xGBoost) for charged track isolation.
-    Higher values of MVA classifier output indicate that the charged track is less isolated
-    and is more likely to be associated to be coming from the same decay vertex as the B0.
-    For more details: Checkout the presentation https://indico.cern.ch/event/1234758/#sc-1-4-ml-based-charged-isolat
-
-    Args:
-        v2_pvs (list): TES location of v2 PVs
-        useNumbers (bool): decision of whether to use the numbers or names of vars in the MVA functor
-    """
-    #get the children of the two-body combination (B0-extraparticle)
-    Bstar_p_child = F.CHILD(1, F.FORWARDARGS)
-    ExtraParticle_child = F.CHILD(index_pion, F.FORWARDARGS)
-
-    #define the input variables for mva
-    mva_input_vars = []  #FunctorCollection()
-    #define Impact parameter chi2 of the extra particle wrt to the BPV associated to the two-body combination (B0-extraparticle)
-    mva_input_vars.append(
-        MVAinput("Epi_BPV_IPCHI2", 0,
-                 F.BPVIPCHI2(v2_pvs).bind(ExtraParticle_child), (0, 20)))  # PV
-    #define PT of two body combination (B0-extraparticle). Here is transformed to be less peaky
-    mva_input_vars.append(
-        MVAinput("Epi_PT", 1,
-                 fmath.log(F.PT.bind(ExtraParticle_child)) * LOG10_E, (1, 5)))
-    #define opening angle between B0 and extra particle. Here is transformed to be less peaky
-    cos_angle = F.COSANGLE.bind(F.THREEMOMENTUM @ Bstar_p_child,
-                                F.THREEMOMENTUM @ ExtraParticle_child)
-    mva_input_vars.append(
-        MVAinput("Sb_Epi_COSANGLE_Lb", 2, 1. - fmath.pow(1. - cos_angle, 0.2),
-                 (0, 1)))
-    #define DIRA of the two body combination (B0-extraparticle)
-    mva_input_vars.append(
-        MVAinput("Sb_BPV_DIRA_TF", 8, fmath.pow(1. - F.BPVDIRA(v2_pvs), 0.2),
-                 (0, 1.2)))
-    #define magnitude of PV distance i.e. distance between PV and vertex of two-body combination (B0-extraparticle)
-    # NB: the sign of the magnitude deterimined by the by the difference in z-coordinate of PV and vertex of two-body combination
-    mva_input_vars.append(
-        MVAinput("PVdis", 3,
-                 (F.MAGNITUDE @ (F.ENDVERTEX_POS - F.BPV_POS(v2_pvs))) *
-                 fmath.sign(F.END_VZ - F.BPVZ(v2_pvs)), (-50, 100)))
-    #* F.MAGNITUDE @ (F.ENDVERTEX_POS - F.BPV_POS(v2_pvs))
-    #define magnitude of SV distance i.e. distance between two-body combination (B0-extraparticle) vertex and the vertex
-    # without the extra particle included. The sign of the magnitude is determined by the difference in z-coordinate of both vertices
-    mva_input_vars.append(
-        MVAinput("SVdis", 4,
-                 (F.MAGNITUDE
-                  @ (F.ENDVERTEX_POS.bind(Bstar_p_child) - F.ENDVERTEX_POS)) *
-                 fmath.sign(F.END_VZ - F.END_VZ.bind(Bstar_p_child)),
-                 (-50, 50)))
-    #define DeltaR i.e. the difference in radius of B0 and extra particle in the rapidity-azimuth plane
-    delta_eta = F.ETA.bind(Bstar_p_child) - F.ETA.bind(ExtraParticle_child)
-    delta_phi = F.PHI.bind(Bstar_p_child) - F.PHI.bind(ExtraParticle_child)
-    delta_phi = fmath.where(delta_phi > math.pi, delta_phi - math.pi,
-                            delta_phi)
-    delta_phi = fmath.where(delta_phi < -math.pi, delta_phi + math.pi,
-                            delta_phi)
-    mva_input_vars.append(
-        MVAinput(
-            "DeltaREpi", 5,
-            fmath.pow(
-                fmath.sqrt(
-                    fmath.pow(delta_eta, 2.) + fmath.pow(delta_phi, 2.)), 0.2),
-            (0, 1.5)))
-
-    mva_input_vars.append(
-        MVAinput("Sb_MAX_DOCACHI2", 6,
-                 fmath.log(F.SDOCACHI2(1, index_pion)) * LOG10_E, (-2.6, 7.5)))
-    mva_input_vars.append(
-        MVAinput(
-            "Sb_Epi_IPCHI2_WRT_LbENDVERTEX", 7,
-            fmath.log(
-                F.IPCHI2.bind(F.ENDVERTEX @ Bstar_p_child,
-                              ExtraParticle_child)) * LOG10_E, (-2, 6)))  # SV
-
-    #define the mva classifier
-    mva = F.MVA(
-        MVAType='TMVA',
-        Config={
-            'XMLFile': 'paramfile://data/xgboost_model_cocktail_inclusive.xml',
-            'Name': 'BDT',
-        },
-        Inputs={(f"f[{var.number}]" if useNumbers else var.name): var.functor
-                for var in mva_input_vars})
-    return mva
-
-def mva_transform_output(xgboost_style_input: float) -> float:
-    """
-    We've converted our input from xgboost-style to TMVA-style but this gives a transformation on the cut variables
-    This function converts from an xgboost-style cut to the corresponding TMVA-style
-    taken from: https://github.com/jpata/mlglue/blob/master/mlglue/tree.py#L400-L409
-    This takes the domain from [0,1] and transforms it from [-1,1] in a strange (nonlinear) way
-    """
-    TMVA_style_output = -math.log(1. / xgboost_style_input - 1.)
-    TMVA_style_output = 2. / (1. + math.exp(-2. * TMVA_style_output)) - 1.
-
-    return TMVA_style_output
-
-- 
GitLab


From afb1c67480f532685529de6fda7712ceabbb6ad4 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Wed, 14 Aug 2024 10:37:57 +0200
Subject: [PATCH 51/57] add SL_l_nu_D0toKpi_Run3_MC_data_v2

---
 SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py         | 503 ++++++++++++++++++
 SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt1.py       |  18 +
 SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py       | 155 ++++++
 SL_l_nu_D0toKpi_Run3_MC_data_v2/MC_Matcher.py |  26 +
 SL_l_nu_D0toKpi_Run3_MC_data_v2/Spruce.py     |  58 ++
 SL_l_nu_D0toKpi_Run3_MC_data_v2/info.yaml     | 156 ++++++
 .../isolationMVA.py                           | 350 ++++++++++++
 7 files changed, 1266 insertions(+)
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt1.py
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC_data_v2/MC_Matcher.py
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC_data_v2/Spruce.py
 create mode 100644 SL_l_nu_D0toKpi_Run3_MC_data_v2/info.yaml
 create mode 100755 SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
new file mode 100644
index 0000000000..116e9fac67
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
@@ -0,0 +1,503 @@
+import sys,os,math
+from PyConf.reading import get_pvs, get_rec_summary, get_particles
+from PyConf.Algorithms import ThOrParticleSelection
+import Functors as F
+from FunTuple import FunctorCollection
+from FunTuple import FunTuple_Particles as Funtuple
+from DaVinci.algorithms import create_lines_filter
+from DaVinci import Options,make_config
+import FunTuple.functorcollections as FC
+from DaVinciMCTools import MCTruthAndBkgCat
+from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Functors.grammar import Functor
+from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
+import numpy as np
+#from Hlt2Conf.lines.semileptonic.isolationMVA import mva_transform_output,mva_functor_mu_inclusive
+from .isolationMVA import mva_functor_inclusive,mva_transform_output
+from .MC_Matcher import trail_seeker
+from DaVinciTools import SubstitutePID
+from Gaudi.Configuration import INFO
+
+_BPVCORRM = Functor('_BPVCORRM', 'Composite::CorrectedMass','Compute the corrected mass')
+_allpv_FDVEC     = (F.ENDVERTEX_POS @ F.FORWARDARG1 - F.TOLINALG @ F.POSITION @ F.FORWARDARG0)
+_allpv_NORMEDDOT = F.NORMEDDOT.bind(F.THREEMOMENTUM @ F.FORWARDARG1, _allpv_FDVEC)
+ALLPV_CHI2      = lambda Vertices: F.MAP(F.CHI2) @ F.TES(Vertices)
+ALLPV_CHI2DOF   = lambda Vertices: F.MAP(F.CHI2DOF) @ F.TES(Vertices)
+ALLPV_IPCHI2    = lambda Vertices: F.MAP(F.IPCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FDCHI2    = lambda Vertices: F.MAP(F.VTX_FDCHI2).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DIRA      = lambda Vertices: F.MAP(_allpv_NORMEDDOT).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_CORRM     = lambda Vertices: F.MAP(_BPVCORRM).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_LTIME     = lambda Vertices: F.MAP(F.VTX_LTIME).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_DLS       = lambda Vertices: F.MAP(F.VTX_DLS).bind(F.TES(Vertices), F.FORWARDARGS)
+ALLPV_FD_COORDINATE   = lambda coordinate, Vertices: F.MAP(coordinate @ _allpv_FDVEC).bind(F.TES(Vertices), F.FORWARDARGS)
+
+TRUE_ID_IS = lambda id, mctruth: (F.VALUE_OR(0) @ mctruth(F.ABS @ F.PARTICLE_ID) == id)
+
+def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = True):
+
+    Bstm = SubstitutePID(
+        name='PIDSubstitute',
+        input_particles=B,
+        substitutions=["B-{{B*-}}","B+{{B*+}}"],
+        output_level=INFO).Particles
+
+    #combine to make [B*0 -> B*- pi+]cc
+    Bst_1 = ParticleCombiner(
+        Inputs=[Bstm, pions],
+        name=f'Bst_1_{lepton}',
+        DecayDescriptor='[B*0 -> B*- pi+]cc',
+        CombinationCut=F.ALL,
+        CompositeCut=F.ALL,
+        ParticleCombiner="ParticleVertexFitter",
+        PrimaryVertices=v2_pvs
+        #OutputLevel=1
+    )
+    #combine to make [B*0 -> B*- pi-]cc
+    Bst_2 = ParticleCombiner(
+        Inputs=[Bstm, pions],
+        name=f'Bst_2_{lepton}',
+        DecayDescriptor='[B*0 -> B*- pi-]cc',
+        CombinationCut=F.ALL,
+        CompositeCut=F.ALL,
+        ParticleCombiner="ParticleVertexFitter",
+        PrimaryVertices=v2_pvs
+        #OutputLevel=1
+    )
+    #merge the two Bst candidates
+    Bst = ParticleContainersMerger([Bst_1, Bst_2], name = f'Bst_combiner_{lepton}')
+    return Bst
+
+def get_functors(MCTRUTH, v2_pvs, rec_summary):
+    #define common variables for all fields (composite and basic)
+    vars_common  = FunctorCollection()
+    #all pvs: ip, ipchi2. The PV positions are stored in event variables
+    vars_common['ALLPV_IP[pv_indx]']     = F.ALLPV_IP(v2_pvs)
+    vars_common['ALLPV_IPCHI2[pv_indx]'] = ALLPV_IPCHI2(v2_pvs)
+    #best pv: x, y, z, ip, ipchi2
+    vars_common['BPV_X']          = F.BPVX(v2_pvs)
+    vars_common['BPV_Y']          = F.BPVY(v2_pvs)
+    vars_common['BPV_Z']          = F.BPVZ(v2_pvs)
+    vars_common['BPV_IP']         = F.BPVIP(v2_pvs)
+    vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
+    vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
+    vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
+    #particle id, key, truekey. The trueid is stored in MCHierarchy
+    vars_common['ID']            = F.PARTICLE_ID
+    vars_common['KEY']           = F.OBJECT_KEY
+
+    #get charge, min ip and min ipchi2
+    vars_common['CHARGE']        = F.CHARGE
+    vars_common['MINIP']         = F.MINIP(v2_pvs)
+    vars_common['MINIPCHI2']     = F.MINIPCHI2(v2_pvs)
+    #reco kinematics
+    vars_common += FC.Kinematics()
+    vars_common['ETA']           = F.ETA
+    vars_common['PHI']           = F.PHI
+    if MCTRUTH != 'None':
+        #mc vars
+        vars_common['TRUEKEY']       = F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY)
+        vars_common += FC.MCKinematics(mctruth_alg = MCTRUTH)
+        vars_common['TRUEETA'] = MCTRUTH(F.ETA)
+        vars_common['TRUEPHI'] = MCTRUTH(F.PHI)
+        #type of the origin vertex
+        vars_common['MC_VTX_TYPE'] = MCTRUTH(F.VALUE_OR(-1) @ F.MC_VTX_TYPE @ F.MC_ORIGINVERTEX)
+        #make some helper functions
+        MCMOTHER_ID  = lambda n: F.VALUE_OR(0)  @ MCTRUTH(F.MC_MOTHER(n, F.PARTICLE_ID))
+        MCMOTHER_KEY = lambda n: F.VALUE_OR(-1) @ MCTRUTH(F.MC_MOTHER(n, F.OBJECT_KEY ))
+        vars_common["TRUEID"] = F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID)
+        vars_common["MCKEY"] = F.VALUE_OR(0) @ MCTRUTH(F.OBJECT_KEY)
+        vars_common["MC_MOTHER_ID"] = MCMOTHER_ID(1)
+        vars_common["MC_MOTHER_KEY"] = MCMOTHER_KEY(1)
+        for i in range(2,14):
+          prefix = "MC_GD_MOTHER_{}".format(i)
+          vars_common[f"{prefix}_ID"]  = MCMOTHER_ID(i)
+          vars_common[f"{prefix}_KEY"] = MCMOTHER_KEY(i)
+
+    #variables for composite particles
+    vars_composite  = FunctorCollection()
+    #end vertex position and end vertex chi2
+    vars_composite['ENDVERTEX_POS_']  = F.ENDVERTEX_POS
+    vars_composite['ENDVERTEX_CHI2']  = F.CHI2 @ F.ENDVERTEX
+    vars_composite['ENDVERTEX_CHI2DOF']  = F.CHI2DOF @ F.ENDVERTEX
+    #all pvs: dira, fd, fdchi2
+    vars_composite['ALLPV_DIRA[pv_indx]']   = ALLPV_DIRA(v2_pvs)
+    vars_composite['ALLPV_FD_X[pv_indx]']   = ALLPV_FD_COORDINATE(F.X_COORDINATE, v2_pvs)
+    vars_composite['ALLPV_FD_Y[pv_indx]']   = ALLPV_FD_COORDINATE(F.Y_COORDINATE, v2_pvs)
+    vars_composite['ALLPV_FD_Z[pv_indx]']   = ALLPV_FD_COORDINATE(F.Z_COORDINATE, v2_pvs)
+    vars_composite['ALLPV_FDCHI2[pv_indx]'] = ALLPV_FDCHI2(v2_pvs)
+    vars_composite['ALLPV_CORRM[pv_indx]']  = ALLPV_CORRM(v2_pvs)
+    vars_composite['ALLPV_LTIME[pv_indx]']  = ALLPV_LTIME(v2_pvs)
+    vars_composite['ALLPV_DLS[pv_indx]']    = ALLPV_DLS(v2_pvs)
+    #best pv: dira, fd, fdchi2, corrm, ltime, dls
+    vars_composite['BPV_DIRA']    = F.BPVDIRA(v2_pvs)
+    vars_composite['BPV_FD_']     = F.BPVFDVEC(v2_pvs)
+    vars_composite['BPV_FDCHI2']  = F.BPVFDCHI2(v2_pvs)
+    vars_composite['BPV_CORRM']   = F.BPVCORRM(v2_pvs)
+    vars_composite['BPV_LTIME']   = F.BPVLTIME(v2_pvs)
+    vars_composite['BPV_DLS']     = F.BPVDLS(v2_pvs)
+
+    #mc composite vertex information
+    if MCTRUTH != 'None': vars_composite += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
+    #Compute maximum DOCA and maximum DOCACHI2. Since there are 
+    # only two daughters of B0 particles, the maximum DOCA/DOCACHI2 is 
+    # the DOCA/DOCACHI2 see below.
+    vars_composite['MAX_DOCA'] = F.MAXDOCA
+    vars_composite['MAX_DOCACHI2'] = F.MAXDOCACHI2
+    vars_composite['MAX_SDOCA'] = F.MAXSDOCA
+    vars_composite['MAX_SDOCACHI2'] = F.MAXSDOCACHI2
+
+    #variables for basics
+    vars_basic  = FunctorCollection()
+    vars_basic['TRACKTYPE']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKTYPE @ F.TRACK
+    vars_basic['TRACKHISTORY'] = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKHISTORY @ F.TRACK
+    vars_basic['TRACKFLAG']    = F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.TRACKFLAG @ F.TRACK
+    vars_basic['TRACKNDOF']    = F.VALUE_OR(-1) @ F.NDOF @ F.TRACK
+    vars_basic['TRACKCHI2']    = F.CHI2 @ F.TRACK
+    vars_basic['TRACKCHI2DOF'] = F.CHI2DOF @ F.TRACK
+    vars_basic['GHOSTPROB'] = F.GHOSTPROB
+    vars_basic['NHITS'] = F.VALUE_OR(-1) @F.NHITS @ F.TRACK
+    vars_basic['NUTHITS'] = F.VALUE_OR(-1) @F.NUTHITS @ F.TRACK
+    vars_basic['NVPHITS'] = F.VALUE_OR(-1) @F.NVPHITS @ F.TRACK
+    vars_basic['NFTHITS'] = F.VALUE_OR(-1) @ F.NFTHITS @ F.TRACK
+    vars_basic['TRACKHASUT'] = F.VALUE_OR(-1) @ F.TRACKHASUT @ F.TRACK
+    vars_basic['TRACKHASVELO'] = F.VALUE_OR(-1) @ F.TRACKHASVELO @ F.TRACK
+    vars_basic['PIDpi'] = F.PID_PI
+    vars_basic['PIDk']  = F.PID_K
+    vars_basic['PIDp']  = F.PID_P
+    vars_basic['PIDe']  = F.PID_E
+    vars_basic['PIDmu'] = F.PID_MU
+    vars_basic['PROBNNe'] = F.PROBNN_E
+    vars_basic['PROBNNpi'] = F.PROBNN_PI
+    vars_basic['PROBNNk'] = F.PROBNN_K
+    vars_basic['PROBNNmu'] = F.PROBNN_MU
+    vars_basic['PROBNNp'] = F.PROBNN_P
+    vars_basic['PROBNNghost'] = F.PROBNN_GHOST
+    if MCTRUTH != 'None': vars_basic += FC.MCVertexInfo(mctruth_alg = MCTRUTH)
+
+    #variables for event
+    #Collection includes tis_tos, nPVs,nHits/clusters,BUNCHCROSSING and GPS var
+    evt_collections = [
+        FC.EventInfo(),
+        FC.RecSummary(),
+    ]
+    evt_vars = FunctorCollection({})
+    evt_vars['ALLPV_X[pv_indx]']      = F.ALLPVX(v2_pvs)
+    evt_vars['ALLPV_Y[pv_indx]']      = F.ALLPVY(v2_pvs)
+    evt_vars['ALLPV_Z[pv_indx]']      = F.ALLPVZ(v2_pvs)
+    evt_vars['ALLPV_CHI2[pv_indx]']   = ALLPV_CHI2(v2_pvs)
+    evt_vars['ALLPV_CHI2DOF[pv_indx]']= ALLPV_CHI2DOF(v2_pvs)
+
+    for coll in evt_collections:evt_vars += coll
+
+    vars_brems = FunctorCollection({})
+    vars_brems.update({"HASBREM": F.HASBREM})
+    #vars_brems.update({"HASBREMADDED": F.HASBREMADDED})
+    vars_brems.update({"BREMENERGY": F.BREMENERGY})
+    vars_brems.update({"BREMBENDCORR": F.BREMBENDCORR})
+    vars_brems.update({"BREMPIDE": F.BREMPIDE})
+    vars_brems.update({"ECALPIDE": F.ECALPIDE})
+    vars_brems.update({"ECALPIDMU": F.ECALPIDMU})
+    vars_brems.update({"HCALPIDE": F.HCALPIDE})
+    vars_brems.update({"HCALPIDMU": F.HCALPIDMU})
+    vars_brems.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP})
+    vars_brems.update({"ELECTRONSHOWERDLL": F.ELECTRONSHOWERDLL})
+    vars_brems.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2})
+    vars_brems.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2})
+    vars_brems.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2})
+    vars_brems.update({"ELECTRONENERGY": F.ELECTRONENERGY})
+    vars_brems.update({"BREMHYPOENERGY": F.BREMHYPOENERGY})
+    vars_brems.update({"BREMHYPODELTAX": F.BREMHYPODELTAX})
+    #vars_brems.update({"BREMTRACKBASEDENERGY": F.BREMTRACKBASEDENERGY})
+    vars_brems.update({"INBREM": F.INBREM})
+    vars_brems.update({"INECAL": F.INECAL})
+    vars_brems.update({"PT_WITH_BREM": F.PT_WITH_BREM})
+    vars_brems.update({"P_WITH_BREM": F.P_WITH_BREM})
+
+    #return all functors
+    functors = (vars_common, vars_composite, vars_basic, evt_vars,vars_brems)
+    return functors
+'''
+def get_B_momentum(v2_pvs):
+    PVIS = F.THREEMOMENTUM
+    MVIS = F.MASS
+    EVIS = F.ENERGY
+    # Get the flight direction of the mother
+    Fnorm = F.BPVFDIR(v2_pvs)
+    # Calculate P_vis^perpendicular, as defined in Eq. 5.1 in JHEP(2017)2017:21
+    PVIS_PERP = F.MAGNITUDE @ F.CROSS_PRODUCT.bind(PVIS, Fnorm)
+    # Calculate P_vis^parallel, as defined in Eq. 5.2 in JHEP(2017)2017:21
+    PVIS_PARA = F.DOT_PRODUCT.bind(PVIS, Fnorm)
+    # Extract the known mass of the parent
+    parent_mass = F.PDG_MASS("B0")
+    # Calculate parameter a, as defined in Eq. 5.4 in JHEP(2017)2017:21
+    a = (PVIS_PARA * (parent_mass**2 - MVIS**2 - 2 * PVIS_PERP**2)) / (2 * (PVIS_PARA**2 - EVIS**2))
+    # Calculate r, as defined in Eq. 5.5 in arXiv:1611.08522
+    r = EVIS**2 * (parent_mass**2 - MVIS**2 - 2 * PVIS_PERP**2)**2 / (4 * (PVIS_PARA**2 - EVIS**2)**2) + (EVIS * PVIS_PERP)**2 / (PVIS_PARA**2 - EVIS**2)
+
+    return (PVIS_PARA - a + F.SQRT @ r) * Fnorm
+'''
+def get_fitting_variable(v2_pvs,D0,lep,Epi):
+    B_mass = F.PDG_MASS("B0")
+    B_dis = np.array([F.END_VX-F.BPVX(v2_pvs),F.END_VY-F.BPVY(v2_pvs),F.END_VZ-F.BPVZ(v2_pvs)])
+    B_dis_mag = F.SQRT @ (B_dis[0]**2+B_dis[1]**2+B_dis[2]**2)
+    B_Mod_P = F.ABS @ ((B_mass/F.MASS)*F.PZ/(B_dis[2]/B_dis_mag))
+    B_Mod_E = F.SQRT @ (B_Mod_P**2 + B_mass**2)
+
+    Dst_PX = F.X_COORDINATE @ ((F.FOURMOMENTUM @ D0)+(F.FOURMOMENTUM @ Epi))
+    Dst_PY = F.Y_COORDINATE @ ((F.FOURMOMENTUM @ D0)+(F.FOURMOMENTUM @ Epi))
+    Dst_PZ = F.Z_COORDINATE @ ((F.FOURMOMENTUM @ D0)+(F.FOURMOMENTUM @ Epi))
+    Dst_E = F.E_COORDINATE @ ((F.FOURMOMENTUM @ D0)+(F.FOURMOMENTUM @ Epi))
+
+    B_4P = np.array([B_Mod_P*B_dis[0]/B_dis_mag,B_Mod_P*B_dis[1]/B_dis_mag,B_Mod_P*B_dis[2]/B_dis_mag,B_Mod_E])
+    D_4P = np.array([Dst_PX,Dst_PY,Dst_PZ,Dst_E])
+    lep_4P = np.array([F.PX @ lep,F.PY @ lep,F.PZ @ lep,F.ENERGY @ lep])
+    '''
+    B_P_mike = get_B_momentum(v2_pvs)
+    B_Mod_P_mike = F.MAGNITUDE @ B_P_mike
+    B_E_mike = F.SQRT @ (F.DOT_PRODUCT.bind(B_P_mike, B_P_mike) + F.B_mass**2)
+    B_4P_mike = np.array([F.X_COORDINATE @ B_P_mike,F.Y_COORDINATE @ B_P_mike,F.Z_COORDINATE @ B_P_mike,B_E_mike])    
+    '''
+    vars_fitting = FunctorCollection({})
+    vars_fitting["Mod_P"] = B_Mod_P
+    #vars_fitting["Mod_P_mike"] = B_Mod_P_mike
+    vars_fitting['missing_m2'] = (B_4P[3]-D_4P[3]-lep_4P[3])**2-(B_4P[0]-D_4P[0]-lep_4P[0])**2-(B_4P[1]-D_4P[1]-lep_4P[1])**2-(B_4P[2]-D_4P[2]-lep_4P[2])**2
+    #vars_fitting['missing_m2_mike'] = (B_4P_mike[3]-D_4P[3]-lep_4P[3])**2-(B_4P_mike[0]-D_4P[0]-lep_4P[0])**2-(B_4P_mike[1]-D_4P[1]-lep_4P[1])**2-(B_4P_mike[2]-D_4P[2]-lep_4P[2])**2
+    vars_fitting['q2'] = (B_4P[3]-D_4P[3])**2-(B_4P[0]-D_4P[0])**2-(B_4P[1]-D_4P[1])**2-(B_4P[2]-D_4P[2])**2
+    #vars_fitting['q2_mike'] = (B_4P_mike[3]-D_4P[3])**2-(B_4P_mike[0]-D_4P[0])**2-(B_4P_mike[1]-D_4P[1])**2-(B_4P_mike[2]-D_4P[2])**2
+    B_Beta = B_Mod_P/B_Mod_E
+    B_gamma = 1/F.SQRT @ (1-B_Beta**2)
+
+    B_Lorentz = [[B_gamma,-1*B_gamma*B_4P[0]/B_4P[3],-1*B_gamma*B_4P[1]/B_4P[3],-1*B_gamma*B_4P[2]/B_4P[3]],[-1*B_gamma*B_4P[0]/B_4P[3],1+(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[0]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)],[-1*B_gamma*B_4P[1]/B_4P[3],(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[1]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)],[-1*B_gamma*B_4P[2]/B_4P[3],(B_gamma-1)*((B_4P[0]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[1]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta),(B_gamma-1)*((B_4P[2]/B_4P[3])/B_Beta)*((B_4P[2]/B_4P[3])/B_Beta)]]
+    vars_fitting['lep_E_Brest'] = (B_Lorentz[0][0]*lep_4P[3]+B_Lorentz[0][1]*lep_4P[0]+B_Lorentz[0][2]*lep_4P[1]+B_Lorentz[0][3]*lep_4P[2])
+    '''
+    B_Beta_mike = B_Mod_P_mike/B_E_mike
+    B_gamma_mike = 1/F.SQRT @ (1-B_Beta_mike**2)
+
+    B_Lorentz = [[B_gamma_mike,-1*B_gamma_mike*B_4P_mike[0]/B_4P_mike[3],-1*B_gamma_mike*B_4P_mike[1]/B_4P_mike[3],-1*B_gamma_mike*B_4P_mike[2]/B_4P_mike[3]],[-1*B_gamma_mike*B_4P_mike[0]/B_4P_mike[3],1+(B_gamma_mike-1)*((B_4P_mike[0]/B_4P_mike[3])/B_Beta_mike)*((B_4P_mike[0]/B_4P_mike[3])/B_Beta_mike),(B_gamma_mike-1)*((B_4P_mike[0]/B_4P_mike[3])/B_Beta_mike)*((B_4P_mike[1]/B_4P_mike[3])/B_Beta_mike),(B_gamma_mike-1)*((B_4P_mike[0]/B_4P_mike[3])/B_Beta_mike)*((B_4P_mike[2]/B_4P_mike[3])/B_Beta_mike)],[-1*B_gamma_mike*B_4P_mike[1]/B_4P_mike[3],(B_gamma_mike-1)*((B_4P_mike[0]/B_4P_mike[3])/B_Beta_mike)*((B_4P_mike[1]/B_4P_mike[3])/B_Beta_mike),(B_gamma_mike-1)*((B_4P_mike[1]/B_4P_mike[3])/B_Beta_mike)*((B_4P_mike[1]/B_4P_mike[3])/B_Beta_mike),(B_gamma_mike-1)*((B_4P_mike[1]/B_4P_mike[3])/B_Beta_mike)*((B_4P_mike[2]/B_4P_mike[3])/B_Beta_mike)],[-1*B_gamma_mike*B_4P_mike[2]/B_4P_mike[3],(B_gamma_mike-1)*((B_4P_mike[0]/B_4P_mike[3])/B_Beta_mike)*((B_4P_mike[2]/B_4P_mike[3])/B_Beta_mike),(B_gamma_mike-1)*((B_4P_mike[1]/B_4P_mike[3])/B_Beta_mike)*((B_4P_mike[2]/B_4P_mike[3])/B_Beta_mike),(B_gamma_mike-1)*((B_4P_mike[2]/B_4P_mike[3])/B_Beta_mike)*((B_4P_mike[2]/B_4P_mike[3])/B_Beta_mike)]]
+    vars_fitting['lep_E_Brest_mike'] = (B_Lorentz[0][0]*lep_4P[3]+B_Lorentz[0][1]*lep_4P[0]+B_Lorentz[0][2]*lep_4P[1]+B_Lorentz[0][3]*lep_4P[2])
+    '''
+    return(vars_fitting)
+
+def tuple_Bst(Bst,lepton,line, MCTRUTH, v2_pvs, rec_summary):
+    #get functors
+    functors = get_functors(MCTRUTH, v2_pvs, rec_summary)
+    vars_common = functors[0]
+    vars_composite = functors[1]
+    vars_basic = functors[2]
+    evt_vars = functors[3]
+    vars_brems = functors[4]
+
+    #variables for B0 field
+    vars_Bst  = FunctorCollection()
+    B_child   = F.CHILD(1, F.FORWARDARG0)
+    D0_child   = F.CHILD(1, F.CHILD(1,F.FORWARDARG0))
+    Lep_child   = F.CHILD(1, F.CHILD(2,F.FORWARDARG0))
+    Epi_child = F.CHILD(2, F.FORWARDARG0)
+    bpv_pi    = F.BPV(v2_pvs).bind(Epi_child)
+    #diff in vtx chi2 with and without extra particle
+    vars_Bst['DELTA_ENDVERTEX_CHI2']    = (F.CHI2 @ F.ENDVERTEX) - (F.CHI2 @ F.ENDVERTEX.bind(B_child))
+    #IP and IPChi2 of extra particle wrt to B0 end vertex
+    vars_Bst['Epi_IP_WRT_B0ENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_B0ENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ F.FORWARDARG0  , Epi_child)
+    #IP and IPChi2 of extra particle wrt to Bm end vertex
+    vars_Bst['Epi_IP_WRT_BmENDVERTEX']     = F.IP.bind(F.TOLINALG @ F.POSITION @ F.ENDVERTEX @ B_child  , Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_BmENDVERTEX'] = F.IPCHI2.bind(F.ENDVERTEX @ B_child  , Epi_child)
+    #angle between extra particle and Bm
+    vars_Bst['Epi_COSANGLE_Bm']         = F.COSANGLE.bind(F.THREEMOMENTUM @ B_child, F.THREEMOMENTUM @ Epi_child)
+    #diff in fd chi2 with and without extra particle
+    vars_Bst['Delta_BPV_of_Epi_FDCHI2']   = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS) - F.VTX_FDCHI2.bind(bpv_pi, B_child)
+    vars_Bst['BPV_of_Epi_FDCHI2']         = F.VTX_FDCHI2.bind(bpv_pi, F.FORWARDARGS)
+    #IP chi2 of extra particle wrt PV and SV of B0
+    vars_Bst['Epi_IP_WRT_B0BPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_B0BPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ F.FORWARDARG0, Epi_child)
+    #IP chi2 of extra particle wrt PV and SV of Bm
+    vars_Bst['Epi_IP_WRT_BmBPV']         = F.IP.bind(F.TOLINALG @ F.POSITION @ F.BPV(v2_pvs) @ B_child, Epi_child)
+    vars_Bst['Epi_IPCHI2_WRT_BmBPV']     = F.IPCHI2.bind(F.BPV(v2_pvs) @ B_child, Epi_child)
+    #DOCA and DOCACHI2 b/w Lb and extra particle
+    vars_Bst['DOCA12']       = F.DOCA(1, 2)
+    vars_Bst['DOCA12_CHI2_12']  = F.DOCACHI2(1, 2)
+    #vars_Bst['SDOCA12']      = F.SDOCA(1, 2)
+    #vars_Bst['SDOCA_CHI2_12'] = F.SDOCACHI2(1, 2)
+    #DOCACHI2 of extra particle wrt to mother i.e. B0
+    vars_Bst['MTDOCACHI2_1'] = F.MTDOCACHI2(1, v2_pvs)
+    vars_Bst['MTDOCACHI2_2'] = F.MTDOCACHI2(2, v2_pvs)
+    vars_Bst['Delta_M'] = F.ABS @ ((F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))) - (F.MASS @ D0_child))
+    vars_Bst['Dst_M'] = F.MASS @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))
+    vars_Bst['Dst_PX'] = F.X_COORDINATE @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))
+    vars_Bst['Dst_PY'] = F.Y_COORDINATE @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))
+    vars_Bst['Dst_PZ'] = F.Z_COORDINATE @ ((F.FOURMOMENTUM @ D0_child)+(F.FOURMOMENTUM @ Epi_child))
+    #vars_Bst['iso_mva'] = mva_functor_mu_inclusive(v2_pvs)[0]
+    if MCTRUTH != 'None': 
+        vars_Bst += trail_seeker(MCTRUTH)
+    vars_Bst['iso_mva'] = mva_functor_inclusive(v2_pvs)[0]
+    
+
+    #define fields
+    fit_vars = get_fitting_variable(v2_pvs,D0_child,Lep_child,Epi_child)
+    #TIS and TOS
+    Hlt1_decisions = ['Hlt1TrackMVA',
+    'Hlt1TwoTrackMVA',
+    'Hlt1D2KK',
+    'Hlt1D2KPi',
+    'Hlt1D2PiPi',
+    'Hlt1KsToPiPi',
+    'Hlt1TrackMuonMVA',
+    'Hlt1SingleHighPtMuon',
+    'Hlt1TrackElectronMVA',
+    'Hlt1SingleHighPtElectron',
+    'Hlt1DiElectronDisplaced',
+    'Hlt1DiPhotonHighMass',
+    'Hlt1Pi02GammaGamma',
+    'Hlt1DiElectronHighMass_SS',
+    'Hlt1DiElectronHighMass']
+    variables_tistos_hlt1 = FC.HltTisTos(selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=Bst)
+    evt_vars += FC.SelectionInfo(selection_type="Hlt1", trigger_lines=Hlt1_decisions)
+
+    Hlt2_decisions = ['Hlt2SLB_BuToD0MuNu_D0ToKPi',
+    'Hlt2SLB_BuToD0MuNu_D0ToKPi_FakeMuon',
+    'Hlt2SLB_BuToD0ENu_D0ToKPi',
+    'Hlt2SLB_BuToD0ENu_D0ToKPi_FakeElectron',
+    'Hlt2SLB_B0ToDpTauNu_DpToKPiPi_TauToENuNu',
+    'Hlt2SLB_B0ToDpTauNu_DpToKPiPi_TauToMuNuNu',
+    'Hlt2SLB_BuToD0TauNu_D0ToKPi_TauToENuNu',
+    'Hlt2SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',
+    'Hlt2SLB_BuToD0TauNu_D0ToKPi_FakeMuon',
+    'Hlt2SLB_BuToD0TauNu_D0ToKPi_FakeElectron',
+    'Hlt2SLB_myBuToD0ENu_D0ToKPi',
+    'Hlt2Topo2Body',
+    'Hlt2Topo3Body']
+
+    variables_tistos_hlt2 = FC.HltTisTos(selection_type="Hlt2", trigger_lines=Hlt2_decisions, data=Bst)
+    evt_vars += FC.SelectionInfo(selection_type="Hlt2", trigger_lines=Hlt2_decisions)
+
+
+    #define fields
+    fields = {}
+    fields['B0']    = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+    fields['Bm']    = f'[B*0 -> ^(B*- ->  ([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+    fields['D0']    = f'[B*0 ->  (B*- -> ^([D0 -> K- pi+]CC)  {lepton}-)  [pi+]CC]CC'
+    fields['Lep']   = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC) ^{lepton}-)  [pi+]CC]CC'
+    fields['Epi']   = f'[B*0 ->  (B*- ->  ([D0 -> K- pi+]CC)  {lepton}-) ^[pi+]CC]CC'
+    fields['Km']   = f'[B*0 ->  (B*- ->  ([D0 -> ^K- pi+]CC)  {lepton}-) [pi+]CC]CC'
+    fields['pip']   = f'[B*0 ->  (B*- ->  ([D0 -> K- ^pi+]CC)  {lepton}-) [pi+]CC]CC'
+
+    #add variables
+    variables = {}
+    variables["ALL"] = vars_common + variables_tistos_hlt1 + variables_tistos_hlt2
+    variables["B0"]  = vars_composite + vars_Bst + fit_vars
+    variables["Bm"]  = vars_composite
+    variables["D0"]  = vars_composite
+    variables["Lep"] = vars_basic + vars_brems
+    variables["Epi"] = vars_basic
+    variables["Km"] = vars_basic
+    variables["pip"] = vars_basic
+
+    #define tuple
+    my_tuple = Funtuple(
+        name=f"Tuple",
+        tuple_name="DecayTree",
+        fields=fields,
+        variables=variables,
+        event_variables=evt_vars,
+        store_multiple_cand_info=True,
+        inputs=Bst)
+
+    return my_tuple
+
+def get_extra_pions():
+	"""
+	Note this function in DaVinci requires:
+	https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/3203
+	and it's related LHCb, DaVinci and Rec MRs
+	"""
+	long_pions = make_has_rich_long_pions()
+	up_pions = make_has_rich_up_pions()
+	down_pions = make_has_rich_down_pions()
+	return ParticleContainersMerger([long_pions, up_pions, down_pions],
+									name='Pions_combiner')
+
+#def main(options):
+def main(options: Options,line = '', lep='',data_or_mc='mc'):
+
+    #define filer
+    my_filter = create_lines_filter(name="Filter", lines=[line])
+
+    #get data and extra particles
+    Bm = get_particles(f"/Event/Spruce/{line}/Particles")
+    extra_particles = get_extra_pions()
+    #extra_particles = get_particles(f"/Event/Spruce/{line}/{line}_extra_tracks/Particles")
+
+    #get v2_pvs and rec_summary
+    v2_pvs  = get_pvs()
+    rec_summary = get_rec_summary()
+    hadron_candidate_id = 421
+    #make B0 candidate
+    Bst = make_Bst(Bm, extra_particles,lep,hadron_candidate_id,v2_pvs,False)
+    MVA_cut = mva_transform_output(0.1)
+    b_cut  = F.require_all(mva_functor_inclusive(v2_pvs)[0] > MVA_cut) #make a cut
+    Bst_after_cut = ParticleFilter(Input=Bst, Cut=F.FILTER(b_cut), name='Bst_after_cut') #filter the B candidates
+ 
+    if data_or_mc == 'mc':
+        MCTRUTH_Bst = MCTruthAndBkgCat(Bst_after_cut, name='MCTRUTH_Bst')
+        tuple_file = tuple_Bst(Bst_after_cut,lep,line, MCTRUTH_Bst, v2_pvs, rec_summary)
+    elif data_or_mc == 'data':
+        tuple_file = tuple_Bst(Bst_after_cut,lep,line, 'None', v2_pvs, rec_summary)
+    else:
+        raise ValueError(f"Decay channel {decay_channel} not supported")
+    #define algorithms
+    user_algorithms = {}
+    user_algorithms['Alg'] = [my_filter, tuple_file]
+
+    return make_config(options, user_algorithms)
+
+def test(options: Options):
+	return main(options=options, line='Hlt2_Test_line',lep='e',data_or_mc='data')
+
+def MC_SLB_BuToD0ENu_D0ToKPi(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+
+def MC_SLB_BuToDststENu(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+
+def MC_SLB_BdToDststENu(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+
+def MC_SLB_BuToD0MuNu_D0ToKPi(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu',data_or_mc='mc')
+
+def MC_SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+
+def MC_SLB_BuToDststTauNu_TauToENuNu(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+
+def MC_SLB_BdToDststTauNu_TauToENuNu(options: Options):
+	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+
+def MC_SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu',data_or_mc='mc')
+
+def Data_SLB_BuToD0ENu_D0ToKPi(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0ENu_D0ToKPi',lep='e',data_or_mc='data')
+
+def Data_SLB_BuToD0MuNu_D0ToKPi(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu',data_or_mc='data')
+
+def Data_SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu',lep='e',data_or_mc='data')
+
+def Data_SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu',data_or_mc='data')
+
+def Data_SLB_BuToD0ENu_D0ToKPi_FakeElectron(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0ENu_D0ToKPi_FakeElectron',lep='e',data_or_mc='data')
+
+def Data_SLB_BuToD0MuNu_D0ToKPi_FakeMuon(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi_FakeMuon',lep='mu',data_or_mc='data')
+
+def Data_SLB_BuToD0TauNu_D0ToKPi_FakeElectron(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_FakeElectron',lep='e',data_or_mc='data')
+
+def Data_SLB_BuToD0TauNu_D0ToKPi_FakeMuon(options: Options):
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_FakeMuon',lep='mu',data_or_mc='data')
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt1.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt1.py
new file mode 100644
index 0000000000..eeabcc4913
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt1.py
@@ -0,0 +1,18 @@
+###############################################################################
+# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+from Moore import Options
+from Moore.config import run_allen
+from RecoConf.hlt1_allen import allen_gaudi_config as allen_sequence
+
+def main(options: Options):
+    with allen_sequence.bind(sequence="hlt1_pp_matching_no_ut_1000KHz"):
+        return run_allen(options)
+
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py
new file mode 100644
index 0000000000..be2bda5d70
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py
@@ -0,0 +1,155 @@
+###############################################################################
+# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+"""
+Stolen and adapted from Hlt/Hlt2Conf/options/hlt2_pp_expected_24_without_UT.py from v55r7.
+"""
+from Moore import Options,options, run_moore, config
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Hlt2Conf.lines.semileptonic.builders import sl_line_prefilter
+from Hlt2Conf.lines.semileptonic.builders.base_builder import make_candidate
+from Hlt2Conf.lines.semileptonic.builders.charm_hadron_builder import make_d0_tokpi
+from GaudiKernel.SystemOfUnits import MeV, GeV,mm
+from Hlt2Conf.algorithms_thor import ParticleCombiner
+from Hlt2Conf.settings.defaults import get_default_hlt1_filter_code_for_hlt2
+from Hlt2Conf.lines.semileptonic import all_lines as slb_lines  
+from Hlt2Conf.lines.topological_b import all_lines as topo_lines
+from Moore.config import Hlt2Line,register_line_builder
+from Moore.streams import Stream, Streams, DETECTORS
+from RecoConf.event_filters import require_gec
+from RecoConf.global_tools import stateProvider_with_simplified_geom, trackMasterExtrapolator_with_simplified_geom
+from RecoConf.hlt2_global_reco import reconstruction as hlt2_reconstruction, make_light_reco_pr_kf_without_UT
+from RecoConf.reconstruction_objects import reconstruction,make_pvs
+from RecoConf.decoders import default_ft_decoding_version,default_VeloCluster_source
+from RecoConf.hlt2_tracking import (
+    make_TrackBestTrackCreator_tracks,
+    make_PrKalmanFilter_noUT_tracks,
+    make_PrKalmanFilter_Velo_tracks,
+    make_PrKalmanFilter_Seed_tracks,
+)
+from Hlt2Conf.standard_particles import (
+    make_long_electrons_with_brem,
+    make_has_rich_long_pions, 
+    make_has_rich_up_pions, 
+    make_has_rich_down_pions)
+import Functors as F
+from Functors.math import in_range
+import sys
+
+#things to control
+SUFFIX_NAME = '_BToDzl'
+HLT2LINE = f'Hlt2SLB_myBuToD0ENu_D0ToKPi'
+CHARM_MASS = 1864.84 #D0 mass
+CHARM_BUILDER_NAME = 'Dz2KPi_combiner'
+B_BUILDER_NAME     = 'BToDzl_combiner'
+
+def get_charm_cuts():
+    #make loose cuts for D0
+    delta_mass   = 80. #80.0
+    make_d0tokpi_cuts  = {}
+    make_d0tokpi_cuts['comb_m_min']            = (CHARM_MASS - delta_mass) * MeV
+    make_d0tokpi_cuts['comb_m_max']            = (CHARM_MASS + delta_mass) * MeV
+    make_d0tokpi_cuts['comb_docachi2_max']     = 5.
+    make_d0tokpi_cuts['vchi2pdof_max']         = 6   #6 (Now) 6/4 (v55r7 e/taue)
+    make_d0tokpi_cuts['bpvfdchi2_min']         = 25  #25 (Now)
+    make_d0tokpi_cuts['bpvdira_min']           = 0.99  #0.99 (Now) 0.99/0.999 (v55r7 e/taue)
+    make_d0tokpi_cuts['comb_pt_min']           = None #None (Now) None/2000 * MeV (v55r7 e/taue)
+    make_d0tokpi_cuts['comb_pt_any_min']       = None #None (Now) None/800 * MeV (v55r7 e/taue)
+    make_d0tokpi_cuts['comb_pt_sum_min']       = None #None (Now) None/2.5 * GeV (v55r7 e/taue)
+    make_d0tokpi_cuts['comb_doca_max']         = None #None (Now) None/0.1 mm (v55r7 e/taue)
+    make_d0tokpi_cuts['daughter_pt_min']       = 600 * MeV #600 * MeV (Now) 750 * MeV (v55r7)
+    make_d0tokpi_cuts['daughter_mipchi2_min']  = 9. #10. (Now) 10./9. (v55r7 e/taue)
+    make_d0tokpi_cuts['kaon_pid']              = (F.PID_K > 0.) #(F.PID_K > 0.) (Now) (F.PID_K > 4.) (v55r7) 
+    make_d0tokpi_cuts['pion_pid']              = (F.PID_K < 2.)
+    return make_d0tokpi_cuts
+
+def get_electron_cuts():
+    #make loose cuts for electron and tauonic muon
+    make_electron_cuts = {}
+    make_electron_cuts["p_min"]           = 3. * GeV #3. * GeV (Now) 5. *GeV (v55r7)
+    make_electron_cuts["pt_min"]          = 300. * MeV #300. * MeV (Now) 500. * MeV (v55r7)
+    make_electron_cuts["mipchi2_min"]     = 9. #9. (Now) 9./16. (v55r7 e/taue) 
+    make_electron_cuts["mip_min"]         = None #0.
+    make_electron_cuts["pid"]             = (F.PID_E > 0.) 
+    make_electron_cuts["make_particles"]  = make_long_electrons_with_brem  #does not require in calo
+    return make_electron_cuts
+
+def make_b():
+    make_d0tokpi_cuts = get_charm_cuts()
+    make_electron_cuts= get_electron_cuts()
+    pvs = make_pvs()
+    with make_candidate.bind(p_min=15. * GeV): 
+        dzs = make_d0_tokpi(**make_d0tokpi_cuts, name = CHARM_BUILDER_NAME)
+    electrons = make_candidate(**make_electron_cuts, name = "Electron_maker")
+
+    cut_vertex = F.require_all(F.CHI2DOF<9,F.BPVDIRA(pvs) >0.999,in_range(0 * MeV, F.MASS, 10000 * MeV))
+
+    rs_btodze  =  ParticleCombiner(
+        Inputs=[dzs, electrons],
+        name=f'rs_{B_BUILDER_NAME}_e',
+        DecayDescriptor='[B- -> D0 e-]cc',
+        CombinationCut=F.ALL,
+        CompositeCut=cut_vertex)
+
+    ws_btodze  =  ParticleCombiner(
+        Inputs=[dzs, electrons],
+        name=f'ws_{B_BUILDER_NAME}_e',
+        DecayDescriptor='[B+ -> D0 e+]cc',
+        CombinationCut=F.ALL,
+        CompositeCut=cut_vertex)
+
+    return ParticleContainersMerger([rs_btodze,ws_btodze])
+
+@register_line_builder(slb_lines)
+def hlt2_mybutod0enu_d0tokpi_line(name=HLT2LINE,prescale=1):
+    Bcands = make_b()
+    return Hlt2Line(name=name, prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
+
+def pass_through_line(name="Hlt2Passthrough"):
+    """Return a HLT2 line that performs no selection but runs and persists the reconstruction
+    """
+    return Hlt2Line(name=name, prescale=1, algs=[], persistreco=True)
+
+from Hlt2Conf.lines.topological_b import *
+
+def _make_lines():
+    ret = []     
+    for line_dict in [slb_lines]: 
+        for line_name, builder in line_dict.items() : 
+            if "D0ToKPi" in line_name and "TauToPiPiPi" not in line_name and "Bc" not in line_name: 
+                print(line_name)
+                ret.append(builder())
+    ret += [twobody_line(),threebody_line(),pass_through_line()]
+    return ret   
+
+def make_streams():
+    streams = [
+        Stream(lines=_make_lines(), routing_bit=98, detectors=DETECTORS)
+    ]
+    return Streams(streams=streams)
+
+public_tools = [
+    trackMasterExtrapolator_with_simplified_geom(),
+    stateProvider_with_simplified_geom(),
+]
+
+def main(options: Options):
+    # NOTE: the TBTC does not apply a chi2 cut because it is applied by the PrKF
+    with reconstruction.bind(from_file=False),\
+         hlt2_reconstruction.bind(make_reconstruction=make_light_reco_pr_kf_without_UT),\
+         require_gec.bind(skipUT=True),\
+         default_VeloCluster_source.bind(bank_type="VPRetinaCluster"),\
+         make_TrackBestTrackCreator_tracks.bind(max_ghost_prob=0.7, max_chi2ndof=sys.float_info.max),\
+         make_PrKalmanFilter_Velo_tracks.bind(max_chi2ndof=5.),\
+         make_PrKalmanFilter_noUT_tracks.bind(max_chi2ndof=4.),\
+         make_PrKalmanFilter_Seed_tracks.bind(max_chi2ndof=6.),\
+         get_default_hlt1_filter_code_for_hlt2.bind(code=r"Hlt1(?!PassthroughLargeEvent).*Decision"):
+        return run_moore(options, make_streams, public_tools=[])
+
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/MC_Matcher.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/MC_Matcher.py
new file mode 100644
index 0000000000..e3b279805b
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/MC_Matcher.py
@@ -0,0 +1,26 @@
+from FunTuple import FunctorCollection
+import Functors as F
+def trail_seeker(MCTRUTH):
+	mcMatch = lambda decay_descriptor: (F.HAS_VALUE @ MCTRUTH(F.FIND_MCDECAY(decay_descriptor)))
+	mcMatch_both = lambda decay_descriptor1,decay_descriptor2: (F.HAS_VALUE @ MCTRUTH(F.FIND_MCDECAY(decay_descriptor1))+F.HAS_VALUE @ MCTRUTH(F.FIND_MCDECAY(decay_descriptor2)))
+	
+	variables = FunctorCollection({
+		'IS_Dtaunu':mcMatch_both("[B0 -> D*(2010)- tau+ nu_tau]CC","[B~0 -> D*(2010)- tau+ nu_tau]CC"),
+		'IS_Denu':mcMatch_both("[B0 -> D*(2010)- e+ nu_e]CC","[B~0 -> D*(2010)- e+ nu_e]CC"),	
+		'IS_Dstar_2460enu':mcMatch_both("[B0 -> D*(2640)- e+ nu_e]CC","[B~0 -> D*(2640)- e+ nu_e]CC"),
+		'IS_D_2Senu':mcMatch_both("[B0 -> D(2S)- e+ nu_e]CC","[B~0 -> D(2S)- e+ nu_e]CC"),
+		'IS_Dstar_2460_2enu':mcMatch_both("[B0 -> D*_2(2460)- e+ nu_e]CC","[B~0 -> D*_2(2460)- e+ nu_e]CC"),
+		'IS_D_2460_1enu':mcMatch_both("[B0 -> D_1(2420)- e+ nu_e]CC","[B~0 -> D_1(2420)- e+ nu_e]CC"),
+		'IS_Dstar_0taunu':mcMatch_both("[B0 -> D*_0- tau+ nu_tau]CC","[B~0 -> D*_0- tau+ nu_tau]CC"),
+		'IS_D_H_1taunu':mcMatch_both("[B0 -> D_1(H)- tau+ nu_tau]CC","[B~0 -> D_1(H)- tau+ nu_tau]CC"),
+		'IS_D_2420_1taunu':mcMatch_both("[B0 -> D_1(2420)- tau+ nu_tau]CC","[B~0 -> D_1(2420)- tau+ nu_tau]CC"),
+		'IS_Dstar_2460_2taunu':mcMatch_both("[B0 -> D*_2(2460)- tau+ nu_tau]CC","[B~0 -> D*_2(2460)- tau+ nu_tau]CC"),
+		'IS_Dstar0_2640enu':mcMatch("[B- -> D*(2640)0 e- nu_e~]CC"),	
+		'IS_D0_2Senu':mcMatch("[B- -> D(2S)0 e- nu_e~]CC"),	
+		'IS_Dstar0_2460_2enu':mcMatch("[B- -> D*_2(2460)0 e- nu_e~]CC"),	
+		'IS_D0_2460_1enu':mcMatch("[B- -> D_1(2420)0 e- nu_e~]CC"),	
+		'IS_D0_H_1taunu':mcMatch("[B- -> D_1(H)0 tau- nu_tau~]CC"),	
+		'IS_D0_2420_1taunu':mcMatch("[B- -> D_1(2420)0 tau- nu_tau~]CC"),	
+		'IS_Dstar0_2460_2taunu':mcMatch("[B- -> D*_2(2460)0 tau- nu_tau~]CC"),	
+		})
+	return(variables)
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/Spruce.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Spruce.py
new file mode 100644
index 0000000000..964714aba8
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Spruce.py
@@ -0,0 +1,58 @@
+###############################################################################
+# (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+#Example follows from hlt2_with_hlt1_decision.py
+from Moore import Options,options, run_moore, config
+from Hlt2Conf.lines.semileptonic.builders import sl_line_prefilter
+from Moore.config import SpruceLine,register_line_builder
+from .Hlt2 import make_b
+from Moore.streams import DETECTORS, Stream, Streams
+from PyConf.application import configure_input, configure, default_raw_event
+from RecoConf.global_tools import stateProvider_with_simplified_geom
+from RecoConf.reconstruction_objects import reconstruction
+from PyConf.reading import reconstruction as reco_spruce, upfront_reconstruction as upfront_spruce
+from RecoConf.decoders import default_ft_decoding_version
+from Hlt2Conf.lines.semileptonic.spruce_semileptonic import spruce_butod0munu_d0tokpi_line,spruce_butod0taunu_d0tokpi_tautomununu_line
+from Hlt2Conf.lines.semileptonic.HbToHcTauNu_TauToLNuNu import make_butod0taunu_d0tokpi_tautolnunu
+from Hlt2Conf.lines.semileptonic.HbToHcLNu import make_butod0lnu_d0tokpi
+from Moore.persistence.hlt2_tistos import list_of_full_stream_lines
+from Hlt2Conf.lines.semileptonic import all_lines as slb_lines
+from Hlt2Conf.lines.topological_b import all_lines as topo_lines
+from Hlt2Conf.lines.semileptonic import sprucing_lines as slb_sprucing_lines
+def lines_for_tistos():
+    """
+    Nikole Comment : 
+    This TISTOS part is only needed for exclusive Sprucing 
+    and it saves the candidates of the FULL HLT2 lines that fired for each event. 
+    You need to make sure its only FULL HLT2 lines in the lines_for_tistos 
+    and they are the ones you care about ie. RD inclusive lines
+    """
+    return [linename for line_dict in [slb_lines,topo_lines] for linename in line_dict.keys()]
+
+@register_line_builder(slb_sprucing_lines)
+def spruce_mybutod0enu_d0tokpi_line(name='SpruceSLB_myBuToD0ENu_D0ToKPi',prescale=1):
+    Bcands = make_b()
+    return SpruceLine(name=name,  hlt2_filter_code=[
+    f"{name.replace('Spruce','Hlt2')}Decision",
+    "Hlt2Topo2BodyDecision", "Hlt2Topo3BodyDecision"]
+    ,prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
+
+def make_full_streams():
+    lines = [builder() for builder in slb_sprucing_lines.values()]
+    streams = [Stream(lines=lines, detectors=[])]
+    return Streams(streams=streams)
+
+def main(options: Options):
+    public_tools = [stateProvider_with_simplified_geom()]
+    with reconstruction.bind(from_file=True, spruce=True),\
+      reco_spruce.bind(simulation=True),\
+      upfront_spruce.bind(simulation=True),\
+      list_of_full_stream_lines.bind(lines=lines_for_tistos()):
+        return run_moore(options, make_full_streams, public_tools=public_tools)
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/info.yaml b/SL_l_nu_D0toKpi_Run3_MC_data_v2/info.yaml
new file mode 100644
index 0000000000..7855095923
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/info.yaml
@@ -0,0 +1,156 @@
+defaults:
+  inform:
+    - ching-hua.li@cern.ch
+  wg: SL
+
+{%- set evttype_lines_and_leptons = [
+  ('11584030','SLB_BuToD0ENu_D0ToKPi','b0_dstp_e'),
+  ('11574020','SLB_BuToD0MuNu_D0ToKPi','b0_dstp_muon'),
+  ('11584010','SLB_BuToD0TauNu_D0ToKPi_TauToENuNu','b0_dstp_taue'),
+  ('11574010','SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu','b0_dstp_taumuon'),
+  ('12685400','SLB_BuToDststENu','bp_dstst_e'),
+  ('12883000','SLB_BuToDststTauNu_TauToENuNu','bp_dstst_taue'),
+  ('11686000','SLB_BdToDststENu','b0_dststp_e'),
+  ('11883000','SLB_BdToDststTauNu_TauToENuNu','b0_dststp_taue'),
+] %}
+
+{%- set polarity_variables = [
+  ('MagDown','sim-20231017-vc-md100'),
+  ('MagUp','sim-20231017-vc-mu100'),
+]%}
+{%- for polarity, cond_tag in polarity_variables %}
+  {%- for evttype, line, dk in evttype_lines_and_leptons %}
+HLT1_{{dk}}_{{ polarity }}:
+  application: "Moore/v55r7@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  input:
+    bk_query: "/MC/Dev/Beam6800GeV-expected-2024-{{polarity}}-Nu7.6-25ns-Pythia8/Sim10c/{{evttype}}/DIGI"
+    dq_flags:
+      - OK
+    n_test_lfns: 1
+  output: hlt1.dst
+  options:
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data_v2.Hlt1:main
+    extra_options:
+      input_raw_format: 0.3
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      output_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      scheduler_legacy_mode: False
+      compression:
+        algorithm: ZSTD
+        level: 1
+        max_buffer_size: 1048576
+      #evt_max: 1000 
+
+HLT2_{{dk}}_{{ polarity }}:
+  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  input:
+    job_name: HLT1_{{dk}}_{{ polarity }}
+  output: hlt2.dst
+  options:
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data_v2.Hlt2:main
+    extra_options:
+      input_raw_format: 0.5
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      output_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      scheduler_legacy_mode: False
+      output_manifest_file: "HLT2.tck.json" 
+      compression:
+        algorithm: ZSTD
+        level: 1
+        max_buffer_size: 1048576
+      #evt_max: 1000
+SPRUCE_{{dk}}_{{ polarity }}:
+  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  input:
+    job_name: HLT2_{{dk}}_{{ polarity }}
+  output: spruce.dst
+  options:
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data_v2.Spruce:main
+    extra_options:
+      input_raw_format: 0.5
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      output_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      scheduler_legacy_mode: False
+      input_process: "Hlt2"
+      input_manifest_file: "HLT2.tck.json"
+      output_manifest_file: "SPRUCE.tck.json" 
+      compression:
+        algorithm: ZSTD
+        level: 1
+        max_buffer_size: 1048576
+      #evt_max: 1000
+DV_{{dk}}_{{ polarity }}:
+  application: "DaVinci/v64r8@x86_64_v2-el9-clang16-opt"
+  input:
+    job_name: SPRUCE_{{dk}}_{{ polarity }}
+  output: NTuple.root
+  options:
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data_v2.DV:MC_{{line}}
+    extra_options:
+      input_raw_format: 0.5
+      conddb_tag: {{cond_tag}}
+      dddb_tag: dddb-20231017
+      input_type: ROOT
+      simulation: True
+      data_type: "Upgrade"
+      geometry_version: run3/trunk
+      conditions_version: master
+      input_process: "Spruce"
+      input_manifest_file: "SPRUCE.tck.json"
+      #evt_max: 1000
+
+  {%- endfor %}
+{%- endfor %}
+
+
+{%- set lines_and_decays = [
+  ('SLB_BuToD0ENu_D0ToKPi','b0_dstp_e'),
+  ('SLB_BuToD0MuNu_D0ToKPi','b0_dstp_muon'),
+  ('SLB_BuToD0TauNu_D0ToKPi_TauToENuNu','b0_dstp_taue'),
+  ('SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu','b0_dstp_taumuon'),
+  ('SLB_BuToD0ENu_D0ToKPi_FakeElectron','b0_dstp_e_fake'),
+  ('SLB_BuToD0MuNu_D0ToKPi_FakeMuon','b0_dstp_muon_fake'),
+  ('SLB_BuToD0TauNu_D0ToKPi_FakeElectron','b0_dstp_taue_fake'),
+  ('SLB_BuToD0TauNu_D0ToKPi_FakeMuon','b0_dstp_taumuon_fake'),
+] %}
+
+{%- for spruce_line, decay in lines_and_decays %}
+data_{{decay}}:
+  application: "DaVinci/v64r5"
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-MagDown-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
+    dq_flags:
+      - UNCHECKED
+      - OK
+    keep_running: true
+    n_test_lfns: 1 
+  output: DATA.ROOT
+  options:
+    entrypoint: SL_l_nu_D0toKpi_Run3_MC_data_v2.DV:Data_{{spruce_line}}
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT # ROOT for SprucingPass, RAW for RAW data (Hlt2 output)
+      simulation: False
+      #data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce" # Spruce for SprucingPass, "Hlt2" for RAW data (Hlt2 output)
+      input_stream: "sl" # for streamed data
+      #evt_max: 1000
+{%- endfor %}
+
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py
new file mode 100755
index 0000000000..f075d47825
--- /dev/null
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py
@@ -0,0 +1,350 @@
+###############################################################################
+# (c) Copyright 2024 CERN for the benefit of the LHCb Collaboration           #
+#                                                                             #
+# This software is distributed under the terms of the GNU General Public      #
+# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
+#                                                                             #
+# In applying this licence, CERN does not waive the privileges and immunities #
+# granted to it by virtue of its status as an Intergovernmental Organization  #
+# or submit itself to any jurisdiction.                                       #
+###############################################################################
+import Functors as F
+from Hlt2Conf.algorithms_thor import ParticleCombiner
+from Hlt2Conf.algorithms_thor import ParticleContainersMerger
+from Hlt2Conf.algorithms_thor import ParticleFilter
+from RecoConf.reconstruction_objects import make_pvs
+import Functors.math as fmath
+import math,re,os
+from dataclasses import dataclass
+from PyConf.Algorithms import ThOrParticleSelection
+from SelAlgorithms.monitoring import monitor, histogram_1d
+from Hlt2Conf.standard_particles import make_has_rich_long_pions
+from Hlt2Conf.standard_particles import make_has_rich_up_pions
+from Hlt2Conf.standard_particles import make_has_rich_down_pions
+from DaVinciTools import SubstitutePID
+
+#Multiplying by this number will convert log_e to log_10
+#we multiply by log10(e) rather than dividing by ln(10)
+#since multiplication is faster
+LOG10_E = math.log10(math.e)
+#toggle for printing debug messages
+#set to False for proper productions
+DEBUG = False
+
+
+@dataclass
+class MVAinput:
+    """Struct for storing MVA input variables"""
+    name: str  # The name of the var (as per the model)
+    number: int  # The number of the var
+    functor: F.grammar.FunctorBase  # The functor to calculate that variable
+    x_range: (float, float)  # axis range for input var monitoring histos
+
+
+def mva_functor_inclusive(v2_pvs,
+                          make_histos: (bool, str) = (False, ""),
+                          useNumbers: bool = False):
+    """
+    Compute the output of the MVA classifier (xGBoost) for charged track isolation.
+    Higher values of MVA classifier output indicate that the charged track is less isolated
+    and is more likely to be associated to be coming from the same decay vertex as the B0.
+    For more details: Checkout the presentation https://indico.cern.ch/event/1234758/#sc-1-4-ml-based-charged-isolat
+
+    Args:
+        v2_pvs (list): TES location of v2 PVs
+        make_histos (tuple): tuple of bool (do you want the input vars to be monitored) and a ParticleContainersMerger (the B*-pion combinations)
+        useNumbers (bool): decision of whether to use the numbers or names of vars in the MVA functor
+    """
+    #get the children of the two-body combination (B0-extraparticle)
+    Bstar_p_child = F.CHILD(1, F.FORWARDARGS)
+    ExtraParticle_child = F.CHILD(2, F.FORWARDARGS)
+
+    #define the input variables for mva
+    mva_input_vars = []  #FunctorCollection()
+    #define Impact parameter chi2 of the extra particle wrt to the BPV associated to the two-body combination (B0-extraparticle)
+    mva_input_vars.append(
+        MVAinput("Epi_BPV_IPCHI2", 0,
+                 F.BPVIPCHI2(v2_pvs).bind(ExtraParticle_child), (0, 20)))  # PV
+    #define PT of two body combination (B0-extraparticle). Here is transformed to be less peaky
+    mva_input_vars.append(
+        MVAinput("Epi_PT", 1,
+                 fmath.log(F.PT.bind(ExtraParticle_child)) * LOG10_E, (1, 5)))
+    #define opening angle between B0 and extra particle. Here is transformed to be less peaky
+    cos_angle = F.COSANGLE.bind(F.THREEMOMENTUM @ Bstar_p_child,
+                                F.THREEMOMENTUM @ ExtraParticle_child)
+    mva_input_vars.append(
+        MVAinput("Sb_Epi_COSANGLE_Lb", 2, 1. - fmath.pow(1. - cos_angle, 0.2),
+                 (0, 1)))
+    #define DIRA of the two body combination (B0-extraparticle)
+    mva_input_vars.append(
+        MVAinput("Sb_BPV_DIRA_TF", 8, fmath.pow(1. - F.BPVDIRA(v2_pvs), 0.2),
+                 (0, 1.2)))
+    #define magnitude of PV distance i.e. distance between PV and vertex of two-body combination (B0-extraparticle)
+    # NB: the sign of the magnitude deterimined by the by the difference in z-coordinate of PV and vertex of two-body combination
+    mva_input_vars.append(
+        MVAinput("PVdis", 3,
+                 (F.MAGNITUDE @ (F.ENDVERTEX_POS - F.BPV_POS(v2_pvs))) *
+                 fmath.sign(F.END_VZ - F.BPVZ(v2_pvs)), (-50, 100)))
+    #* F.MAGNITUDE @ (F.ENDVERTEX_POS - F.BPV_POS(v2_pvs))
+    #define magnitude of SV distance i.e. distance between two-body combination (B0-extraparticle) vertex and the vertex
+    # without the extra particle included. The sign of the magnitude is determined by the difference in z-coordinate of both vertices
+    mva_input_vars.append(
+        MVAinput("SVdis", 4,
+                 (F.MAGNITUDE
+                  @ (F.ENDVERTEX_POS.bind(Bstar_p_child) - F.ENDVERTEX_POS)) *
+                 fmath.sign(F.END_VZ - F.END_VZ.bind(Bstar_p_child)),
+                 (-50, 50)))
+    #define DeltaR i.e. the difference in radius of B0 and extra particle in the rapidity-azimuth plane
+    delta_eta = F.ETA.bind(Bstar_p_child) - F.ETA.bind(ExtraParticle_child)
+    delta_phi = F.PHI.bind(Bstar_p_child) - F.PHI.bind(ExtraParticle_child)
+    delta_phi = fmath.where(delta_phi > math.pi, delta_phi - 2 * math.pi,
+                            delta_phi)
+    delta_phi = fmath.where(delta_phi < -math.pi, delta_phi + 2 * math.pi,
+                            delta_phi)
+    mva_input_vars.append(
+        MVAinput(
+            "DeltaREpi", 5,
+            fmath.pow(
+                fmath.sqrt(
+                    fmath.pow(delta_eta, 2.) + fmath.pow(delta_phi, 2.)), 0.2),
+            (0, 1.5)))
+
+    mva_input_vars.append(
+        MVAinput("Sb_MAX_DOCACHI2", 6,
+                 fmath.log(F.MAXSDOCACHI2) * LOG10_E, (-2.6, 7.5)))
+    mva_input_vars.append(
+        MVAinput(
+            "Sb_Epi_IPCHI2_WRT_LbENDVERTEX", 7,
+            fmath.log(
+                F.IPCHI2.bind(F.ENDVERTEX @ Bstar_p_child,
+                              ExtraParticle_child)) * LOG10_E, (-2, 6)))  # SV
+
+    #define the mva classifier
+    mva = F.MVA(
+        MVAType='TMVA',
+        Config={
+            #'XMLFile':'paramfile://data/xgboost_model_cocktail_inclusive_220724.xml',
+            'XMLFile':
+            #f"file://{os.environ['ANALYSIS_PRODUCTIONS_BASE']}/SL_l_nu_D0toKpi_Run3_MC_data_v2/xgboost_model_cocktail_inclusive_220724.xml",
+            "file:///eos/lhcb/wg/semileptonic/RDst_taue/xgboost_model_cocktail_inclusive_220724.xml",
+            'Name':'BDT',
+        },
+        Inputs={(f"f[{var.number}]" if useNumbers else var.name): var.functor
+                for var in mva_input_vars})
+    input_monitoring = make_input_monitoring(
+        mva_input_vars, make_histos) if make_histos[0] else []
+    return (mva, input_monitoring)
+
+
+def make_input_monitoring(mva_input_vars: [MVAinput],
+                          make_histos) -> [histogram_1d]:
+    input_monitoring = []
+
+    for var in mva_input_vars:
+        input_monitoring.append(
+            histogram_1d(
+                functor=var.functor,
+                label=var.name,
+                name=f"/{make_histos[1]}/iso_{var.name}",
+                title=f"isolation MVA input: {var.name}",
+                bins=100,
+                range=var.x_range))
+
+    return input_monitoring
+
+
+def mva_transform_output(xgboost_style_input: float) -> float:
+    """
+    We've converted our input from xgboost-style to TMVA-style but this gives a transformation on the cut variables
+    This function converts from an xgboost-style cut to the corresponding TMVA-style
+    taken from: https://github.com/jpata/mlglue/blob/master/mlglue/tree.py#L400-L409
+    This takes the domain from [0,1] and transforms it from [-1,1] in a strange (nonlinear) way
+    """
+    TMVA_style_output = -math.log(1. / xgboost_style_input - 1.)
+    TMVA_style_output = 2. / (1. + math.exp(-2. * TMVA_style_output)) - 1.
+
+    return TMVA_style_output
+
+
+def combine_iso_pions(BstarPlus,
+                      extra_particles,
+                      line_name,
+                      v2_pvs,
+                      apply_fiducial_cut: bool = False):
+    """
+    Make two body combination of B0 and extra particles.
+
+    Args:
+        B0 (list): TES location of B0 particles
+        extra_particles (list): TES location of extra particles in the event.
+          Pion id is assigned to the extra particle.
+
+    Returns:
+        list: TES location of two body combination of B0 and extra_particles
+    """
+    fiducial_cut = F.ALL
+    if apply_fiducial_cut:
+        #fiducial cut on pv distance
+        pv_dist_min = -3.  #mm
+        fiducial_cut_pv_dist = (F.MAGNITUDE @ (F.ENDVERTEX_POS - F.BPV_POS(
+            v2_pvs))) * fmath.sign(F.END_VZ - F.BPVZ(v2_pvs)) > pv_dist_min
+
+        #fiducial cut on the log IPchi2 w.r.t. SV
+        #See p11 : https://indico.cern.ch/event/1405184/contributions/5907467/attachments/2835541/4955107/preCuts_11_04_2024.pdf
+        log_ipchi2_wrtSV_max = 5
+        Bstar_p_child = F.CHILD(1, F.FORWARDARGS)
+        ExtraParticle_child = F.CHILD(2, F.FORWARDARGS)
+        fiducial_cut_sv_ipchi2 = fmath.log(
+            F.IPCHI2.bind(
+                F.ENDVERTEX @ Bstar_p_child,
+                ExtraParticle_child)) * LOG10_E < log_ipchi2_wrtSV_max
+
+        fiducial_cut = F.require_all(fiducial_cut_pv_dist,
+                                     fiducial_cut_sv_ipchi2)
+
+    #first combiner: B0 pi+
+    descriptor_1 = "[B*0 -> B*+ pi-]cc"
+    comb_1 = ParticleCombiner(
+        Inputs=[BstarPlus, extra_particles],
+        name=f'SbCombiner_onetrack_1_{line_name}',
+        DecayDescriptor=descriptor_1,
+        CombinationCut=F.ALL,
+        CompositeCut=fiducial_cut,
+        ParticleCombiner=
+        "ParticleVertexFitter",  #NB: for neutrals need to use different combiner e.g. ParticleAdder
+    )
+    #second combiner: B0 pi-
+    descriptor_2 = "[B*0 -> B*+ pi+]cc"
+    comb_2 = ParticleCombiner(
+        Inputs=[BstarPlus, extra_particles],
+        name=f'SbCombiner_onetrack_2_{line_name}',
+        DecayDescriptor=descriptor_2,
+        CombinationCut=F.ALL,
+        CompositeCut=fiducial_cut,
+        ParticleCombiner="ParticleVertexFitter",
+    )
+    #merge two combiners
+    comb = ParticleContainersMerger([comb_1, comb_2],
+                                    name=f'bst_combiner_{line_name}')
+    return comb
+
+
+def get_extra_pions():
+    long_pions = make_has_rich_long_pions()
+    up_pions = make_has_rich_up_pions()
+    down_pions = make_has_rich_down_pions()
+    return ParticleContainersMerger([long_pions, up_pions, down_pions],
+                                    name='Pions_combiner')
+
+
+def extract_parent_name(line_name: str) -> (str, str):
+    #First do some pruning
+    #e.g. SpruceSLB_BcToJpsiTauNu_JpsiToMuMu_FakeElectron -> JpsiTauNu
+    parent_string = line_name.split('_')[1].split('To')[0]
+    #remove any 'Fake' stuff
+    parent_string = re.sub(r'Fake.*$', '', parent_string)
+
+    #define dicts to convert from our naming convention to
+    Bcand_dict = {
+        "Bu": "B+",
+        "B0": "B0",
+        "Bs": "B_s0",
+        "Bc": "B_c+",
+        "Lb": "Lambda_b0",
+        "Xib0": "Xi_b0",
+        "Xibminus": "Xi_b-",
+        "Omegab": "Omega_b-",
+    }
+    anti_Bcand_dict = {
+        "Bu": "B-",
+        "B0": "B~0",
+        "Bs": "B_s~0",
+        "Bc": "B_c-",
+        "Lb": "Lambda_b~0",
+        "Xib0": "Xi_b~0",
+        "Xibminus": "Xi_b~+",
+        "Omegab": "Omega_b~+",
+    }
+    #throw an error if the parent is not in the dict
+    if parent_string not in Bcand_dict:
+        raise ValueError(
+            f"ERROR: Couldn't automatically determine parent for line: {line_name}"
+        )
+
+    return Bcand_dict[parent_string], anti_Bcand_dict[parent_string]
+
+
+def prepare_MVA(
+        line_name: str,
+        line_output: ParticleCombiner,
+        *,  #All further options must be given as keyword arguments
+        mva_min: float = None,
+        parent: str = "",
+        anti_parent: str = "",
+        mva_used: str = "inclusive") -> (ThOrParticleSelection, [monitor]):
+
+    new_parent_name = 'B*+'
+    anti_new_parent_name = 'B*-'
+
+    if not parent and not anti_parent:
+        parent_name, anti_parent_name = extract_parent_name(line_name)
+    else:
+        parent_name = parent
+        anti_parent_name = anti_parent
+
+    # Yes, we really do need all those brackets
+    substitutions = [
+        f"{parent_name}{{{{{new_parent_name}}}}}",
+        f"{anti_parent_name}{{{{{anti_new_parent_name}}}}}"
+    ]
+    if DEBUG: print(f"{substitutions = }")
+    from Gaudi.Configuration import INFO, ALL
+    output_level = ALL if DEBUG else INFO
+    Bst_p = SubstitutePID(
+        name=f'PIDSubstitute_{line_name}',
+        input_particles=line_output,
+        substitutions=substitutions,
+        output_level=output_level).Particles
+
+    v2_pvs = make_pvs()
+    pions = get_extra_pions()
+    Bst_z = combine_iso_pions(
+        Bst_p, pions, line_name,
+        v2_pvs)  # vertex = B + each extra track - vertex 2
+
+    #Only the inclusive training is being maintained now, no other models are available
+    if mva_used == "inclusive":
+        mva_getter = mva_functor_inclusive
+        if mva_min is None: mva_min = 0.05  # default mu MVA cut
+    else:
+        raise ValueError(
+            f"ERROR: in {__file__}, mva requested must be the inclusive training, no other models are currently maintainted, this has gone wrong for line: {line_name}"
+        )
+    MVA_functor, input_monitoring = mva_getter(
+        v2_pvs, make_histos=(True, line_name))
+    MVA_cut = mva_transform_output(mva_min)
+    MVA_cut_functor = MVA_functor > MVA_cut
+    if DEBUG: print(f"for line {line_name : <56}\t MVA cut: {MVA_cut}")
+    # We'll monitor all the combinations from the MVA, not just those that pass
+    monitoring_histo = histogram_1d(
+        functor=MVA_functor,
+        label="MVA output",
+        name=f"/{line_name}/iso_MVA",
+        title=f"isolation MVA (cut at {MVA_cut} in sprucing)",
+        bins=200,
+        range=(-1, 1))
+
+    # However we'll only keep the subset that pass
+    Bst_z_subset = ParticleFilter(
+        Bst_z, F.FILTER(MVA_cut_functor), name=f"filter_isoPions_{line_name}"
+    )  # B + extra track combos passing the MVA cuts
+
+    monitoring_histos = monitor(
+        data=Bst_z, histograms=input_monitoring + [monitoring_histo])
+
+    extra_track_cut = (F.IS_ABS_ID('pi+'))
+    code_extra_track = F.FILTER(extra_track_cut) @ F.GET_CHILDREN()
+    return (ThOrParticleSelection(
+        name=f"extra_track_selection_{line_name}",
+        InputParticles=Bst_z_subset,
+        Functor=code_extra_track).OutputSelection, [monitoring_histos])
-- 
GitLab


From 7ce8e3044b9d635eec14382d877195184148e2d4 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Wed, 14 Aug 2024 16:44:46 +0200
Subject: [PATCH 52/57] Try old xml file to estimate the output size

---
 SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py
index f075d47825..32214b9183 100755
--- a/SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py
@@ -97,10 +97,16 @@ def mva_functor_inclusive(v2_pvs,
     #define DeltaR i.e. the difference in radius of B0 and extra particle in the rapidity-azimuth plane
     delta_eta = F.ETA.bind(Bstar_p_child) - F.ETA.bind(ExtraParticle_child)
     delta_phi = F.PHI.bind(Bstar_p_child) - F.PHI.bind(ExtraParticle_child)
+    '''
     delta_phi = fmath.where(delta_phi > math.pi, delta_phi - 2 * math.pi,
                             delta_phi)
     delta_phi = fmath.where(delta_phi < -math.pi, delta_phi + 2 * math.pi,
                             delta_phi)
+    '''
+    delta_phi = fmath.where(delta_phi > math.pi, delta_phi - math.pi,
+                            delta_phi)
+    delta_phi = fmath.where(delta_phi < -math.pi, delta_phi + math.pi,
+                            delta_phi)
     mva_input_vars.append(
         MVAinput(
             "DeltaREpi", 5,
@@ -124,9 +130,10 @@ def mva_functor_inclusive(v2_pvs,
         MVAType='TMVA',
         Config={
             #'XMLFile':'paramfile://data/xgboost_model_cocktail_inclusive_220724.xml',
-            'XMLFile':
+            #'XMLFile':
             #f"file://{os.environ['ANALYSIS_PRODUCTIONS_BASE']}/SL_l_nu_D0toKpi_Run3_MC_data_v2/xgboost_model_cocktail_inclusive_220724.xml",
-            "file:///eos/lhcb/wg/semileptonic/RDst_taue/xgboost_model_cocktail_inclusive_220724.xml",
+            #"file:///eos/lhcb/wg/semileptonic/RDst_taue/xgboost_model_cocktail_inclusive_220724.xml",
+            'XMLFile': 'paramfile://data/xgboost_model_cocktail_inclusive.xml',
             'Name':'BDT',
         },
         Inputs={(f"f[{var.number}]" if useNumbers else var.name): var.functor
-- 
GitLab


From 57e59c70eaef8e562f6dd0acf2d5b1ee169b6cc2 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Tue, 20 Aug 2024 11:48:34 +0200
Subject: [PATCH 53/57] 2024 MC data with UT

---
 SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py     |  17 +--
 SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt1.py   |  14 ++-
 SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py   | 123 +++-------------------
 SL_l_nu_D0toKpi_Run3_MC_data_v2/Spruce.py |  42 +++++---
 SL_l_nu_D0toKpi_Run3_MC_data_v2/info.yaml |  12 +--
 5 files changed, 64 insertions(+), 144 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
index 116e9fac67..3ab50fad30 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
@@ -82,6 +82,7 @@ def get_functors(MCTRUTH, v2_pvs, rec_summary):
     vars_common['BPV_IPCHI2']     = F.BPVIPCHI2(v2_pvs)
     vars_common['BPV_CHI2']       = F.CHI2 @ F.BPV(v2_pvs)
     vars_common['BPV_CHI2DOF']    = F.CHI2DOF @ F.BPV(v2_pvs)
+    vars_common['CHI2DOF']        = F.VALUE_OR(Value=F.NaN) @ F.CHI2DOF
     #particle id, key, truekey. The trueid is stored in MCHierarchy
     vars_common['ID']            = F.PARTICLE_ID
     vars_common['KEY']           = F.OBJECT_KEY
@@ -425,8 +426,8 @@ def main(options: Options,line = '', lep='',data_or_mc='mc'):
 
     #get data and extra particles
     Bm = get_particles(f"/Event/Spruce/{line}/Particles")
-    extra_particles = get_extra_pions()
-    #extra_particles = get_particles(f"/Event/Spruce/{line}/{line}_extra_tracks/Particles")
+    #extra_particles = get_extra_pions()
+    extra_particles = get_particles(f"/Event/Spruce/{line}/{line}_extra_tracks/Particles")
 
     #get v2_pvs and rec_summary
     v2_pvs  = get_pvs()
@@ -455,25 +456,25 @@ def test(options: Options):
 	return main(options=options, line='Hlt2_Test_line',lep='e',data_or_mc='data')
 
 def MC_SLB_BuToD0ENu_D0ToKPi(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+	return main(options=options, line='SpruceSLB_BuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
 
 def MC_SLB_BuToDststENu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+	return main(options=options, line='SpruceSLB_BuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
 
 def MC_SLB_BdToDststENu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+	return main(options=options, line='SpruceSLB_BuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
 
 def MC_SLB_BuToD0MuNu_D0ToKPi(options: Options):
 	return main(options=options, line='SpruceSLB_BuToD0MuNu_D0ToKPi',lep='mu',data_or_mc='mc')
 
 def MC_SLB_BuToD0TauNu_D0ToKPi_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu',lep='e',data_or_mc='mc')
 
 def MC_SLB_BuToDststTauNu_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu',lep='e',data_or_mc='mc')
 
 def MC_SLB_BdToDststTauNu_TauToENuNu(options: Options):
-	return main(options=options, line='SpruceSLB_myBuToD0ENu_D0ToKPi',lep='e',data_or_mc='mc')
+	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToENuNu',lep='e',data_or_mc='mc')
 
 def MC_SLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu(options: Options):
 	return main(options=options, line='SpruceSLB_BuToD0TauNu_D0ToKPi_TauToMuNuNu',lep='mu',data_or_mc='mc')
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt1.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt1.py
index eeabcc4913..abab8e2f12 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt1.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt1.py
@@ -9,10 +9,16 @@
 # or submit itself to any jurisdiction.                                       #
 ###############################################################################
 from Moore import Options
-from Moore.config import run_allen
-from RecoConf.hlt1_allen import allen_gaudi_config as allen_sequence
+from PyConf.application import configure_input, configure
 
 def main(options: Options):
-    with allen_sequence.bind(sequence="hlt1_pp_matching_no_ut_1000KHz"):
-        return run_allen(options)
+    """
+    Configures algorithm running of HLT1 via Moore to be passed to Analysis Productions.
+    """
 
+    config = configure_input(options)
+    from Moore.production import hlt1
+    hlt1(options, "--sequence=hlt1_pp_matching_no_ut_1000KHz", "--flagging")
+    config["Gaudi::IODataManager/IODataManager"].AgeLimit = 0
+    
+    return config
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py
index be2bda5d70..59510e0eca 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py
@@ -12,105 +12,13 @@
 Stolen and adapted from Hlt/Hlt2Conf/options/hlt2_pp_expected_24_without_UT.py from v55r7.
 """
 from Moore import Options,options, run_moore, config
-from Hlt2Conf.algorithms_thor import ParticleContainersMerger
-from Hlt2Conf.lines.semileptonic.builders import sl_line_prefilter
-from Hlt2Conf.lines.semileptonic.builders.base_builder import make_candidate
-from Hlt2Conf.lines.semileptonic.builders.charm_hadron_builder import make_d0_tokpi
-from GaudiKernel.SystemOfUnits import MeV, GeV,mm
-from Hlt2Conf.algorithms_thor import ParticleCombiner
-from Hlt2Conf.settings.defaults import get_default_hlt1_filter_code_for_hlt2
-from Hlt2Conf.lines.semileptonic import all_lines as slb_lines  
-from Hlt2Conf.lines.topological_b import all_lines as topo_lines
-from Moore.config import Hlt2Line,register_line_builder
+from Hlt2Conf.settings.hlt2_binds import config_pp_2024
+from Moore.config import Hlt2Line
 from Moore.streams import Stream, Streams, DETECTORS
-from RecoConf.event_filters import require_gec
 from RecoConf.global_tools import stateProvider_with_simplified_geom, trackMasterExtrapolator_with_simplified_geom
-from RecoConf.hlt2_global_reco import reconstruction as hlt2_reconstruction, make_light_reco_pr_kf_without_UT
-from RecoConf.reconstruction_objects import reconstruction,make_pvs
-from RecoConf.decoders import default_ft_decoding_version,default_VeloCluster_source
-from RecoConf.hlt2_tracking import (
-    make_TrackBestTrackCreator_tracks,
-    make_PrKalmanFilter_noUT_tracks,
-    make_PrKalmanFilter_Velo_tracks,
-    make_PrKalmanFilter_Seed_tracks,
-)
-from Hlt2Conf.standard_particles import (
-    make_long_electrons_with_brem,
-    make_has_rich_long_pions, 
-    make_has_rich_up_pions, 
-    make_has_rich_down_pions)
-import Functors as F
-from Functors.math import in_range
-import sys
-
-#things to control
-SUFFIX_NAME = '_BToDzl'
-HLT2LINE = f'Hlt2SLB_myBuToD0ENu_D0ToKPi'
-CHARM_MASS = 1864.84 #D0 mass
-CHARM_BUILDER_NAME = 'Dz2KPi_combiner'
-B_BUILDER_NAME     = 'BToDzl_combiner'
-
-def get_charm_cuts():
-    #make loose cuts for D0
-    delta_mass   = 80. #80.0
-    make_d0tokpi_cuts  = {}
-    make_d0tokpi_cuts['comb_m_min']            = (CHARM_MASS - delta_mass) * MeV
-    make_d0tokpi_cuts['comb_m_max']            = (CHARM_MASS + delta_mass) * MeV
-    make_d0tokpi_cuts['comb_docachi2_max']     = 5.
-    make_d0tokpi_cuts['vchi2pdof_max']         = 6   #6 (Now) 6/4 (v55r7 e/taue)
-    make_d0tokpi_cuts['bpvfdchi2_min']         = 25  #25 (Now)
-    make_d0tokpi_cuts['bpvdira_min']           = 0.99  #0.99 (Now) 0.99/0.999 (v55r7 e/taue)
-    make_d0tokpi_cuts['comb_pt_min']           = None #None (Now) None/2000 * MeV (v55r7 e/taue)
-    make_d0tokpi_cuts['comb_pt_any_min']       = None #None (Now) None/800 * MeV (v55r7 e/taue)
-    make_d0tokpi_cuts['comb_pt_sum_min']       = None #None (Now) None/2.5 * GeV (v55r7 e/taue)
-    make_d0tokpi_cuts['comb_doca_max']         = None #None (Now) None/0.1 mm (v55r7 e/taue)
-    make_d0tokpi_cuts['daughter_pt_min']       = 600 * MeV #600 * MeV (Now) 750 * MeV (v55r7)
-    make_d0tokpi_cuts['daughter_mipchi2_min']  = 9. #10. (Now) 10./9. (v55r7 e/taue)
-    make_d0tokpi_cuts['kaon_pid']              = (F.PID_K > 0.) #(F.PID_K > 0.) (Now) (F.PID_K > 4.) (v55r7) 
-    make_d0tokpi_cuts['pion_pid']              = (F.PID_K < 2.)
-    return make_d0tokpi_cuts
-
-def get_electron_cuts():
-    #make loose cuts for electron and tauonic muon
-    make_electron_cuts = {}
-    make_electron_cuts["p_min"]           = 3. * GeV #3. * GeV (Now) 5. *GeV (v55r7)
-    make_electron_cuts["pt_min"]          = 300. * MeV #300. * MeV (Now) 500. * MeV (v55r7)
-    make_electron_cuts["mipchi2_min"]     = 9. #9. (Now) 9./16. (v55r7 e/taue) 
-    make_electron_cuts["mip_min"]         = None #0.
-    make_electron_cuts["pid"]             = (F.PID_E > 0.) 
-    make_electron_cuts["make_particles"]  = make_long_electrons_with_brem  #does not require in calo
-    return make_electron_cuts
-
-def make_b():
-    make_d0tokpi_cuts = get_charm_cuts()
-    make_electron_cuts= get_electron_cuts()
-    pvs = make_pvs()
-    with make_candidate.bind(p_min=15. * GeV): 
-        dzs = make_d0_tokpi(**make_d0tokpi_cuts, name = CHARM_BUILDER_NAME)
-    electrons = make_candidate(**make_electron_cuts, name = "Electron_maker")
-
-    cut_vertex = F.require_all(F.CHI2DOF<9,F.BPVDIRA(pvs) >0.999,in_range(0 * MeV, F.MASS, 10000 * MeV))
-
-    rs_btodze  =  ParticleCombiner(
-        Inputs=[dzs, electrons],
-        name=f'rs_{B_BUILDER_NAME}_e',
-        DecayDescriptor='[B- -> D0 e-]cc',
-        CombinationCut=F.ALL,
-        CompositeCut=cut_vertex)
-
-    ws_btodze  =  ParticleCombiner(
-        Inputs=[dzs, electrons],
-        name=f'ws_{B_BUILDER_NAME}_e',
-        DecayDescriptor='[B+ -> D0 e+]cc',
-        CombinationCut=F.ALL,
-        CompositeCut=cut_vertex)
-
-    return ParticleContainersMerger([rs_btodze,ws_btodze])
-
-@register_line_builder(slb_lines)
-def hlt2_mybutod0enu_d0tokpi_line(name=HLT2LINE,prescale=1):
-    Bcands = make_b()
-    return Hlt2Line(name=name, prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
+from RecoConf.reconstruction_objects import reconstruction
+from PyConf.Tools import TrackMasterExtrapolator, TrackMasterFitter
+from Hlt2Conf.lines.semileptonic import all_lines as slb_lines  
 
 def pass_through_line(name="Hlt2Passthrough"):
     """Return a HLT2 line that performs no selection but runs and persists the reconstruction
@@ -135,21 +43,18 @@ def make_streams():
     ]
     return Streams(streams=streams)
 
+TrackMasterExtrapolator.global_bind(
+    ApplyMultScattCorr=False,
+    ApplyEnergyLossCorr=False,
+    ApplyElectronEnergyLossCorr=False,
+)
+TrackMasterFitter.global_bind(ApplyMaterialCorrections=False)
+
 public_tools = [
     trackMasterExtrapolator_with_simplified_geom(),
     stateProvider_with_simplified_geom(),
 ]
 
 def main(options: Options):
-    # NOTE: the TBTC does not apply a chi2 cut because it is applied by the PrKF
-    with reconstruction.bind(from_file=False),\
-         hlt2_reconstruction.bind(make_reconstruction=make_light_reco_pr_kf_without_UT),\
-         require_gec.bind(skipUT=True),\
-         default_VeloCluster_source.bind(bank_type="VPRetinaCluster"),\
-         make_TrackBestTrackCreator_tracks.bind(max_ghost_prob=0.7, max_chi2ndof=sys.float_info.max),\
-         make_PrKalmanFilter_Velo_tracks.bind(max_chi2ndof=5.),\
-         make_PrKalmanFilter_noUT_tracks.bind(max_chi2ndof=4.),\
-         make_PrKalmanFilter_Seed_tracks.bind(max_chi2ndof=6.),\
-         get_default_hlt1_filter_code_for_hlt2.bind(code=r"Hlt1(?!PassthroughLargeEvent).*Decision"):
-        return run_moore(options, make_streams, public_tools=[])
-
+    with reconstruction.bind( from_file = False) , config_pp_2024() :   
+        return run_moore(options, make_streams, public_tools=public_tools)
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/Spruce.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Spruce.py
index 964714aba8..85806e3912 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data_v2/Spruce.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Spruce.py
@@ -10,22 +10,21 @@
 ###############################################################################
 #Example follows from hlt2_with_hlt1_decision.py
 from Moore import Options,options, run_moore, config
-from Hlt2Conf.lines.semileptonic.builders import sl_line_prefilter
+from Moore.lines import optimize_controlflow
 from Moore.config import SpruceLine,register_line_builder
-from .Hlt2 import make_b
 from Moore.streams import DETECTORS, Stream, Streams
 from PyConf.application import configure_input, configure, default_raw_event
-from RecoConf.global_tools import stateProvider_with_simplified_geom
+from RecoConf.global_tools import stateProvider_with_simplified_geom,trackMasterExtrapolator_with_simplified_geom
+from PyConf.Algorithms import VeloRetinaClusterTrackingSIMD
 from RecoConf.reconstruction_objects import reconstruction
+from RecoConf.legacy_rec_hlt1_tracking import (make_VeloClusterTrackingSIMD, make_RetinaClusters)
 from PyConf.reading import reconstruction as reco_spruce, upfront_reconstruction as upfront_spruce
-from RecoConf.decoders import default_ft_decoding_version
-from Hlt2Conf.lines.semileptonic.spruce_semileptonic import spruce_butod0munu_d0tokpi_line,spruce_butod0taunu_d0tokpi_tautomununu_line
-from Hlt2Conf.lines.semileptonic.HbToHcTauNu_TauToLNuNu import make_butod0taunu_d0tokpi_tautolnunu
-from Hlt2Conf.lines.semileptonic.HbToHcLNu import make_butod0lnu_d0tokpi
+from RecoConf.decoders import default_ft_decoding_version,default_VeloCluster_source
 from Moore.persistence.hlt2_tistos import list_of_full_stream_lines
 from Hlt2Conf.lines.semileptonic import all_lines as slb_lines
 from Hlt2Conf.lines.topological_b import all_lines as topo_lines
 from Hlt2Conf.lines.semileptonic import sprucing_lines as slb_sprucing_lines
+from Moore.persistence.hlt2_tistos import list_of_full_stream_lines
 def lines_for_tistos():
     """
     Nikole Comment : 
@@ -36,23 +35,32 @@ def lines_for_tistos():
     """
     return [linename for line_dict in [slb_lines,topo_lines] for linename in line_dict.keys()]
 
-@register_line_builder(slb_sprucing_lines)
-def spruce_mybutod0enu_d0tokpi_line(name='SpruceSLB_myBuToD0ENu_D0ToKPi',prescale=1):
-    Bcands = make_b()
-    return SpruceLine(name=name,  hlt2_filter_code=[
-    f"{name.replace('Spruce','Hlt2')}Decision",
-    "Hlt2Topo2BodyDecision", "Hlt2Topo3BodyDecision"]
-    ,prescale=prescale,persistreco=True, algs=sl_line_prefilter() + [Bcands])
-
 def make_full_streams():
+    '''
+    lines = []
+    for line_dict in [slb_sprucing_lines]:
+        for line_name, builder in line_dict.items() : 
+            if "D0ToKPi" in line_name and "TauToPiPiPi" not in line_name and "Bc" not in line_name: 
+                print(line_name)
+                lines.append(builder())
+    '''
     lines = [builder() for builder in slb_sprucing_lines.values()]
     streams = [Stream(lines=lines, detectors=[])]
     return Streams(streams=streams)
 
 def main(options: Options):
-    public_tools = [stateProvider_with_simplified_geom()]
+    default_VeloCluster_source.global_bind(bank_type="VPRetinaCluster")
+    make_VeloClusterTrackingSIMD.global_bind(
+        algorithm=VeloRetinaClusterTrackingSIMD)
+
+    public_tools = [
+    trackMasterExtrapolator_with_simplified_geom(),
+    stateProvider_with_simplified_geom()
+    ]
     with reconstruction.bind(from_file=True, spruce=True),\
       reco_spruce.bind(simulation=True),\
       upfront_spruce.bind(simulation=True),\
-      list_of_full_stream_lines.bind(lines=lines_for_tistos()):
+      list_of_full_stream_lines.bind(lines=lines_for_tistos()),\
+      optimize_controlflow.bind(optimization="default"):
         return run_moore(options, make_full_streams, public_tools=public_tools)
+
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/info.yaml b/SL_l_nu_D0toKpi_Run3_MC_data_v2/info.yaml
index 7855095923..95c0f05c4b 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data_v2/info.yaml
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/info.yaml
@@ -21,7 +21,7 @@ defaults:
 {%- for polarity, cond_tag in polarity_variables %}
   {%- for evttype, line, dk in evttype_lines_and_leptons %}
 HLT1_{{dk}}_{{ polarity }}:
-  application: "Moore/v55r7@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  application: "Moore/v55r11@x86_64_v3-el9-gcc13+detdesc-opt+g"
   #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     bk_query: "/MC/Dev/Beam6800GeV-expected-2024-{{polarity}}-Nu7.6-25ns-Pythia8/Sim10c/{{evttype}}/DIGI"
@@ -44,10 +44,10 @@ HLT1_{{dk}}_{{ polarity }}:
         algorithm: ZSTD
         level: 1
         max_buffer_size: 1048576
-      #evt_max: 1000 
+      #evt_max: 100 
 
 HLT2_{{dk}}_{{ polarity }}:
-  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  application: "Moore/v55r11@x86_64_v3-el9-gcc13+detdesc-opt+g"
   #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     job_name: HLT1_{{dk}}_{{ polarity }}
@@ -70,7 +70,7 @@ HLT2_{{dk}}_{{ polarity }}:
         max_buffer_size: 1048576
       #evt_max: 1000
 SPRUCE_{{dk}}_{{ polarity }}:
-  application: "Moore/v55r7p3@x86_64_v3-el9-gcc13+detdesc-opt+g"
+  application: "Moore/v55r11@x86_64_v3-el9-gcc13+detdesc-opt+g"
   #application: "Moore/v55r8@x86_64_v3-el9-gcc13+detdesc-opt+g"
   input:
     job_name: HLT2_{{dk}}_{{ polarity }}
@@ -131,9 +131,9 @@ DV_{{dk}}_{{ polarity }}:
 
 {%- for spruce_line, decay in lines_and_decays %}
 data_{{decay}}:
-  application: "DaVinci/v64r5"
+  application: "DaVinci/v64r8@x86_64_v2-el9-clang16-opt"
   input:
-    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-MagDown-Excl-UT/Real Data/Sprucing24c1/90000000/SL.DST"
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-MagDown/Real Data/Sprucing24c2/90000000/SL.DST"
     dq_flags:
       - UNCHECKED
       - OK
-- 
GitLab


From 6df0886db3e819390bb2d4672ff186d06d245e37 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Wed, 21 Aug 2024 09:54:38 +0200
Subject: [PATCH 54/57] Update Hlt2.py

---
 SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py
index 59510e0eca..031cb0529e 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/Hlt2.py
@@ -43,13 +43,6 @@ def make_streams():
     ]
     return Streams(streams=streams)
 
-TrackMasterExtrapolator.global_bind(
-    ApplyMultScattCorr=False,
-    ApplyEnergyLossCorr=False,
-    ApplyElectronEnergyLossCorr=False,
-)
-TrackMasterFitter.global_bind(ApplyMaterialCorrections=False)
-
 public_tools = [
     trackMasterExtrapolator_with_simplified_geom(),
     stateProvider_with_simplified_geom(),
-- 
GitLab


From 34ae8c746385c665d1c4c51d1906c69563d81f76 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Fri, 23 Aug 2024 12:22:32 +0200
Subject: [PATCH 55/57] Update DV.py

---
 SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
index 3ab50fad30..86a0588fad 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
@@ -42,13 +42,16 @@ def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = Tru
         substitutions=["B-{{B*-}}","B+{{B*+}}"],
         output_level=INFO).Particles
 
+    MVA_cut = mva_transform_output(0.1)
+    cut_composite = F.require_all(mva_functor_inclusive(v2_pvs)[0] > MVA_cut)
+
     #combine to make [B*0 -> B*- pi+]cc
     Bst_1 = ParticleCombiner(
         Inputs=[Bstm, pions],
         name=f'Bst_1_{lepton}',
         DecayDescriptor='[B*0 -> B*- pi+]cc',
         CombinationCut=F.ALL,
-        CompositeCut=F.ALL,
+        CompositeCut=cut_composite,
         ParticleCombiner="ParticleVertexFitter",
         PrimaryVertices=v2_pvs
         #OutputLevel=1
@@ -59,7 +62,7 @@ def make_Bst(B, pions,lepton, hadron_candidate_id,v2_pvs,do_truth_matching = Tru
         name=f'Bst_2_{lepton}',
         DecayDescriptor='[B*0 -> B*- pi-]cc',
         CombinationCut=F.ALL,
-        CompositeCut=F.ALL,
+        CompositeCut=cut_composite,
         ParticleCombiner="ParticleVertexFitter",
         PrimaryVertices=v2_pvs
         #OutputLevel=1
@@ -435,15 +438,15 @@ def main(options: Options,line = '', lep='',data_or_mc='mc'):
     hadron_candidate_id = 421
     #make B0 candidate
     Bst = make_Bst(Bm, extra_particles,lep,hadron_candidate_id,v2_pvs,False)
-    MVA_cut = mva_transform_output(0.1)
-    b_cut  = F.require_all(mva_functor_inclusive(v2_pvs)[0] > MVA_cut) #make a cut
-    Bst_after_cut = ParticleFilter(Input=Bst, Cut=F.FILTER(b_cut), name='Bst_after_cut') #filter the B candidates
+    #MVA_cut = mva_transform_output(0.1)
+    #b_cut  = F.require_all(mva_functor_inclusive(v2_pvs)[0] > MVA_cut) #make a cut
+    #Bst_after_cut = ParticleFilter(Input=Bst, Cut=F.FILTER(b_cut), name='Bst_after_cut') #filter the B candidates
  
     if data_or_mc == 'mc':
-        MCTRUTH_Bst = MCTruthAndBkgCat(Bst_after_cut, name='MCTRUTH_Bst')
-        tuple_file = tuple_Bst(Bst_after_cut,lep,line, MCTRUTH_Bst, v2_pvs, rec_summary)
+        MCTRUTH_Bst = MCTruthAndBkgCat(Bst, name='MCTRUTH_Bst')
+        tuple_file = tuple_Bst(Bst,lep,line, MCTRUTH_Bst, v2_pvs, rec_summary)
     elif data_or_mc == 'data':
-        tuple_file = tuple_Bst(Bst_after_cut,lep,line, 'None', v2_pvs, rec_summary)
+        tuple_file = tuple_Bst(Bst,lep,line, 'None', v2_pvs, rec_summary)
     else:
         raise ValueError(f"Decay channel {decay_channel} not supported")
     #define algorithms
-- 
GitLab


From 29008329a15fab247d7d30606cbba70f9de60627 Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 26 Aug 2024 00:12:43 +0200
Subject: [PATCH 56/57] Update DV.py

---
 SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
index 86a0588fad..43b3646deb 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
@@ -13,8 +13,7 @@ from Hlt2Conf.algorithms_thor import ParticleContainersMerger
 from Functors.grammar import Functor
 from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
 import numpy as np
-#from Hlt2Conf.lines.semileptonic.isolationMVA import mva_transform_output,mva_functor_mu_inclusive
-from .isolationMVA import mva_functor_inclusive,mva_transform_output
+from Hlt2Conf.lines.semileptonic.isolationMVA import mva_functor_inclusive,mva_transform_output
 from .MC_Matcher import trail_seeker
 from DaVinciTools import SubstitutePID
 from Gaudi.Configuration import INFO
-- 
GitLab


From 43f58d0cf21c9d30435be7681ee7326c7869c3cc Mon Sep 17 00:00:00 2001
From: Ching-Hua Li <ching-hua.li@cern.ch>
Date: Mon, 26 Aug 2024 01:06:47 +0200
Subject: [PATCH 57/57] Update DV.py and isolationMVA.py

---
 SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py           | 2 +-
 SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py | 7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
index 43b3646deb..3caf5c0e4a 100644
--- a/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/DV.py
@@ -13,7 +13,7 @@ from Hlt2Conf.algorithms_thor import ParticleContainersMerger
 from Functors.grammar import Functor
 from Hlt2Conf.standard_particles import make_has_rich_long_pions,make_has_rich_up_pions,make_has_rich_down_pions
 import numpy as np
-from Hlt2Conf.lines.semileptonic.isolationMVA import mva_functor_inclusive,mva_transform_output
+from .isolationMVA import mva_functor_inclusive,mva_transform_output
 from .MC_Matcher import trail_seeker
 from DaVinciTools import SubstitutePID
 from Gaudi.Configuration import INFO
diff --git a/SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py b/SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py
index 32214b9183..87b3f568e9 100755
--- a/SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py
+++ b/SL_l_nu_D0toKpi_Run3_MC_data_v2/isolationMVA.py
@@ -97,7 +97,7 @@ def mva_functor_inclusive(v2_pvs,
     #define DeltaR i.e. the difference in radius of B0 and extra particle in the rapidity-azimuth plane
     delta_eta = F.ETA.bind(Bstar_p_child) - F.ETA.bind(ExtraParticle_child)
     delta_phi = F.PHI.bind(Bstar_p_child) - F.PHI.bind(ExtraParticle_child)
-    '''
+
     delta_phi = fmath.where(delta_phi > math.pi, delta_phi - 2 * math.pi,
                             delta_phi)
     delta_phi = fmath.where(delta_phi < -math.pi, delta_phi + 2 * math.pi,
@@ -107,6 +107,7 @@ def mva_functor_inclusive(v2_pvs,
                             delta_phi)
     delta_phi = fmath.where(delta_phi < -math.pi, delta_phi + math.pi,
                             delta_phi)
+    '''
     mva_input_vars.append(
         MVAinput(
             "DeltaREpi", 5,
@@ -129,11 +130,11 @@ def mva_functor_inclusive(v2_pvs,
     mva = F.MVA(
         MVAType='TMVA',
         Config={
-            #'XMLFile':'paramfile://data/xgboost_model_cocktail_inclusive_220724.xml',
+            'XMLFile':'paramfile://data/xgboost_model_cocktail_inclusive_220724.xml',
             #'XMLFile':
             #f"file://{os.environ['ANALYSIS_PRODUCTIONS_BASE']}/SL_l_nu_D0toKpi_Run3_MC_data_v2/xgboost_model_cocktail_inclusive_220724.xml",
             #"file:///eos/lhcb/wg/semileptonic/RDst_taue/xgboost_model_cocktail_inclusive_220724.xml",
-            'XMLFile': 'paramfile://data/xgboost_model_cocktail_inclusive.xml',
+            #'XMLFile': 'paramfile://data/xgboost_model_cocktail_inclusive.xml',
             'Name':'BDT',
         },
         Inputs={(f"f[{var.number}]" if useNumbers else var.name): var.functor
-- 
GitLab