From ef34f862576aa2eba49e1851ee39c4b23242ec98 Mon Sep 17 00:00:00 2001
From: yangj <yangjiaqi23@mails.ucas.ac.cn>
Date: Tue, 19 Nov 2024 16:45:19 +0800
Subject: [PATCH 1/3] Lb2Lc3Pi

---
 Lb2Lc3Pi/Lb2Lc3Pi.py | 241 +++++++++++++++++++++++++++++++++++++++++++
 Lb2Lc3Pi/info.yaml   |  41 ++++++++
 2 files changed, 282 insertions(+)
 create mode 100644 Lb2Lc3Pi/Lb2Lc3Pi.py
 create mode 100644 Lb2Lc3Pi/info.yaml

diff --git a/Lb2Lc3Pi/Lb2Lc3Pi.py b/Lb2Lc3Pi/Lb2Lc3Pi.py
new file mode 100644
index 0000000000..69d7114e43
--- /dev/null
+++ b/Lb2Lc3Pi/Lb2Lc3Pi.py
@@ -0,0 +1,241 @@
+import Functors as F
+import FunTuple.functorcollections as FC
+from FunTuple import  FunctorCollection, FunTuple_Particles as Funtuple
+from PyConf.reading import get_particles, get_pvs, get_rec_summary, get_odin
+from GaudiKernel.SystemOfUnits import GeV
+from Hlt2Conf.algorithms_thor import ParticleFilter
+from DaVinci.algorithms import create_lines_filter
+from DaVinci import Options, make_config
+from DaVinciMCTools import MCTruthAndBkgCat
+from DecayTreeFitter import DecayTreeFitter
+from Hlt2Conf.flavourTagging import run2_all_taggers
+# specific for the B2OC SigmaNet
+import Functors.math as fmath
+import os
+
+
+def main(options: Options):
+    line_name = "SpruceB2OC_LbToLcpPiPiPi_LcpToPKPi"
+    line_data = get_particles(f"/Event/Spruce/{line_name}/Particles")
+    my_filter = create_lines_filter("Hlt2Line_Filter",
+                                    lines=[f"{line_name}"])
+    Hlt1_decisions = [
+        "Hlt1TrackMVADecision",
+        "Hlt1TwoTrackMVADecision",
+    ]
+    Hlt2_decisions = [
+                      'Hlt2Topo2BodyDecision',
+                      'Hlt2Topo3BodyDecision',]
+
+    fields = {
+        'Lb': '[Lambda_b0 -> (Lambda_c+ -> p+ K- pi+) pi- pi+ pi-]CC',
+        'LbPi1': '[Lambda_b0 -> (Lambda_c+ -> p+ K- pi+) ^pi- pi+ pi-]CC',
+        'LbPi2': '[Lambda_b0 -> (Lambda_c+ -> p+ K- pi+) pi- ^pi+ pi-]CC',
+        'LbPi3': '[Lambda_b0 -> (Lambda_c+ -> p+ K- pi+) pi- pi+ ^pi-]CC',
+        'Lc': '[Lambda_b0 -> ^(Lambda_c+ -> p+ K- pi+) pi- pi+ pi-]CC',
+        'LcP': '[Lambda_b0 -> (Lambda_c+ -> ^p+ K- pi+) pi- pi+ pi-]CC',
+        'LcK': '[Lambda_b0 -> (Lambda_c+ -> p+ ^K- pi+) pi- pi+ pi-]CC',
+        'LcPi': '[Lambda_b0 -> (Lambda_c+ -> p+ K- ^pi+) pi- pi+ pi-]CC',
+    }
+
+    pvs = get_pvs()
+
+    DTF_MassFitConsLc = DecayTreeFitter(
+        name="DTF_MassFitConsLc",
+        input_particles=line_data,
+        mass_constraints=["Lambda_c+"])
+
+    DTF_LifetimeFit = DecayTreeFitter(
+        name="DTF_LifetimeFit", input_particles=line_data, input_pvs=pvs)
+
+
+    # all_tagging = run2_all_taggers(line_data)
+
+    # define helper functors
+    get_child = F.CHILD(1, F.FORWARDARG0) # change here the index of the child
+    get_SV =  F.ENDVERTEX @ F.FORWARDARG0
+    get_SV_pos = F.TOLINALG @ F.POSITION @ get_SV # only if composite (i.e. has vertex)
+    get_child_endvtx_pos = F.ENDVERTEX_POS  @ get_child
+    get_fdvec_child = get_child_endvtx_pos - get_SV_pos
+
+    # define observables
+    IP_wrt_SV = F.IP.bind(get_SV_pos , get_child)
+    IPCHI2_wrt_SV = F.IPCHI2.bind(get_SV , get_child) # only if child is composite (i.e. has vertex)
+    FD_wrt_SV = F.MAGNITUDE @ get_fdvec_child
+    FDCHI2_wrt_SV = F.VTX_FDCHI2.bind(get_SV, get_child)
+
+    B_variables = FunctorCollection(
+        {
+        "ID": F.PARTICLE_ID,
+        "PT": F.PT,
+        "ETA": F.ETA,
+        "P": F.P,
+        "SUMPT": F.SUM(F.PT),
+        "MASS": F.MASS,
+        "BPVDIRA": F.BPVDIRA(pvs),
+        "CHI2DOF": F.CHI2DOF,
+        "BPVIPCHI2": F.BPVIPCHI2(pvs),
+        "BPVIP": F.BPVIP(pvs),
+        "BPVFDCHI2": F.BPVFDCHI2(pvs),
+        "BPVLTIME": F.BPVLTIME(pvs),
+        "BPVFD": F.BPVFD(pvs),
+        "BPVCHI2DOF": F.CHI2DOF @ F.BPV(pvs),
+        "IPCHI2_OWNPV": F.BPVIPCHI2(pvs),
+        "ENDVERTEX_CHI2": F.CHI2DOF,
+        "FDCHI2_OWNPV": F.BPVFDCHI2(pvs),
+        "DIRA_OWNPV": F.BPVDIRA(pvs),
+        "CHILD1_IPwrtSV": IP_wrt_SV,
+        "CHILD1_IPCHI2wrtSV": IPCHI2_wrt_SV,
+        "CHILD1_FDwrtSV": FD_wrt_SV,
+        "CHILD1_FDCHI2wrtSV": FDCHI2_wrt_SV,
+        "DTF_MassFitConsLc_MASS": DTF_MassFitConsLc(F.MASS),
+        "DTF_MassFitConsLc_CHI2DOF": DTF_MassFitConsLc(F.CHI2DOF), # track or vertex chi2/ndf
+        "DTF_MassFitConsLc_P": DTF_MassFitConsLc(F.P),
+        "DTF_LifetimeFit_MASS": DTF_LifetimeFit(F.MASS),
+        "DTF_LifetimeFit_CHI2DOF": DTF_LifetimeFit(F.CHI2DOF), # track or vertex chi2/ndf
+        "DTF_LifetimeFit_CTAU": DTF_LifetimeFit.CTAU,
+        "DTF_LifetimeFit_CTAUERR": DTF_LifetimeFit.CTAUERR,
+        "PX": F.PX,
+        "PY": F.PY,
+        "PZ": F.PZ,
+        "BPVX": F.BPVX(pvs),
+        "BPVY": F.BPVY(pvs),
+        "BPVZ": F.BPVZ(pvs),
+        "END_VX": F.END_VX,
+        "END_VY": F.END_VY,
+        "END_VZ": F.END_VZ,
+        "END_VCHI2DOF": F.CHI2DOF @ F.ENDVERTEX,
+        }
+    )
+    B_variables+=FC.HltTisTos(selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=line_data)
+    
+
+    C_variables = FunctorCollection(
+        {
+            "ID": F.PARTICLE_ID,
+            "PT": F.PT,
+            "ETA": F.ETA,
+            "P": F.P,
+            "SUMPT": F.SUM(F.PT),
+            "MASS": F.MASS,
+            "DOCA12": F.DOCA(1, 2),
+            "DOCA13": F.DOCA(1, 3),
+            "DOCA23": F.DOCA(2, 3),
+            "BPVDIRA": F.BPVDIRA(pvs),
+            "CHI2DOF": F.CHI2DOF,
+            "BPVIP": F.BPVIP(pvs),
+            "BPVIPCHI2": F.BPVIPCHI2(pvs),
+            "BPVFD": F.BPVFD(pvs),
+            "BPVFDCHI2": F.BPVFDCHI2(pvs),
+            "MINIPCHI2": F.MINIPCHI2(pvs),
+            "IPCHI2_OWNPV": F.BPVIPCHI2(pvs),
+            "ENDVERTEX_CHI2": F.CHI2DOF,
+            "FDCHI2_OWNPV": F.BPVFDCHI2(pvs),
+            "PX": F.PX,
+            "PY": F.PY,
+            "PZ": F.PZ,
+            "BPVX": F.BPVX(pvs),
+            "BPVY": F.BPVY(pvs),
+            "BPVZ": F.BPVZ(pvs),
+            "END_VX": F.END_VX,
+            "END_VY": F.END_VY,
+            "END_VZ": F.END_VZ,
+            "END_VCHI2DOF": F.CHI2DOF @ F.ENDVERTEX,
+        }
+    )
+
+    fs_variables = FunctorCollection(
+        {
+            "ID": F.PARTICLE_ID,
+            "PT": F.PT,
+            "ETA": F.ETA,
+            "PHI": F.PHI,
+            "P": F.P,
+            "MASS": F.MASS,
+            "CHI2DOF": F.CHI2DOF,
+            "MINIPCHI2": F.MINIPCHI2(pvs),
+            "BPVIPCHI2": F.BPVIPCHI2(pvs),
+            "IPCHI2_OWNPV": F.BPVIPCHI2(pvs),
+            "PX": F.PX,
+            "PY": F.PY,
+            "PZ": F.PZ,
+            "hasRICH": F.PPHASRICH() @ F.PROTOPARTICLE(),
+            "PIDK": F.PID_K,
+            "PIDp": F.PID_P,
+            "PIDe": F.PID_E,
+            "PIDmu": F.PID_MU,
+            "isMuon": F.ISMUON,
+            "TRACK_GhostProb": F.GHOSTPROB,
+            "ProbNNp": F.PROBNN_P,
+            "ProbNNk": F.PROBNN_K,
+            "ProbNNpi": F.PROBNN_PI,
+            "NHITS": F.VALUE_OR(-1) @ F.NHITS @ F.TRACK,
+            "NVPHITS": F.VALUE_OR(-1) @ F.NVPHITS @ F.TRACK, # VeloPixel hits
+            "NUTHITS": F.VALUE_OR(-1) @ F.NUTHITS @ F.TRACK, # UpstreamTracker hits
+            "NFTHITS": F.VALUE_OR(-1) @ F.NFTHITS @ F.TRACK, # ForwardTracker hits
+            "TRACKHASVELO": F.VALUE_OR(-1) @ F.TRACKHASVELO @ F.TRACK,
+        }
+    )
+
+    variables = {
+        "Lb": B_variables,
+        "LbPi1": fs_variables,
+        "LbPi2": fs_variables,
+        "LbPi3": fs_variables,
+        "Lc": C_variables,
+        "LcP": fs_variables,
+        "LcK": fs_variables,
+        "LcPi": fs_variables,
+    }
+
+    if options.simulation:
+        # get configured "MCTruthAndBkgCatAlg" algorithm for HLT2 output
+        mctruth = MCTruthAndBkgCat(line_data)
+        # add helper lambda that configures a functor to get truth information
+        MCTRUTH = lambda func: F.MAP_INPUT(Functor=func, Relations=mctruth.MCAssocTable)
+        trueid_bkgcat_info = {
+            # Important note: specify an invalid value for integer functors if there exists no truth info.
+            #                 The invalid value for floating point functors is set to nan.
+            "TRUEID": F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID),
+            "TRUEKEY": F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY),
+            #
+            "TRUEPT": MCTRUTH(F.PT),
+            "TRUEPX": MCTRUTH(F.PX),
+            "TRUEPY": MCTRUTH(F.PY),
+            "TRUEPZ": MCTRUTH(F.PZ),
+            "TRUEENERGY": MCTRUTH(F.ENERGY),
+            "TRUEP": MCTRUTH(F.P),
+            "TRUEFOURMOMENTUM": MCTRUTH(F.FOURMOMENTUM),
+            "BKGCAT": F.BKGCAT(Relations=mctruth.BkgCatTable),
+        }
+        for field in variables.keys():
+            variables[field] += FunctorCollection(trueid_bkgcat_info)
+
+
+    odin = get_odin()
+    rec_summary = get_rec_summary()
+    # define event level variables
+    evt_variables = FunctorCollection({
+	"RUNNUMBER": F.RUNNUMBER(odin),
+	"EVENTNUMBER": F.EVENTNUMBER(odin),
+    "nVPClusters" : F.VALUE_OR(-1) @ F.RECSUMMARY_INFO( rec_summary, "nVPClusters"),
+    "nFTClusters" : F.VALUE_OR(-1) @ F.RECSUMMARY_INFO( rec_summary, "nFTClusters"),
+	"nPVs": F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs"),
+	"nLongTracks": F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks"),
+    "nVeloTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_summary,"nVeloTracks"),
+    })
+    evt_variables+=FC.SelectionInfo(selection_type="Hlt1", trigger_lines=Hlt1_decisions)
+    evt_variables+=FC.SelectionInfo(selection_type="Hlt2", trigger_lines=Hlt2_decisions)
+
+    # define FunTuple instance
+    my_tuple = Funtuple(
+        name="Tuple",
+        tuple_name="DecayTree",
+        fields=fields,
+        variables=variables,
+        event_variables=evt_variables,
+        inputs=line_data,
+        store_multiple_cand_info=True,
+    )
+
+    return make_config(options, [my_filter, my_tuple])
\ No newline at end of file
diff --git a/Lb2Lc3Pi/info.yaml b/Lb2Lc3Pi/info.yaml
new file mode 100644
index 0000000000..bb44a70191
--- /dev/null
+++ b/Lb2Lc3Pi/info.yaml
@@ -0,0 +1,41 @@
+defaults:
+  inform:
+    - jiaqi.yang@cern.ch
+  wg: B2OC
+
+ {%- set datasets = [
+ ('2024Data', 'MagUp', '24c2'),
+ ('2024Data', 'MagUp', '24c3'),
+ ('2024Data', 'MagUp', '24c4'),
+ ('2024Data', 'MagDown', '24c2'),
+ ('2024Data', 'MagDown', '24c3'),
+ ('2024Data', 'MagDown', '24c4'),
+('2024Data', 'MagDown-Excl-UT', '24c1'),
+ ('2024Data', 'MagDown-Excl-UT', '24c2'),
+ ('2024Data', 'MagUp-Excl-UT', '24c1'),
+ ('2024Data', 'MagUp-Excl-UT', '24c2'),
+]%}
+
+  {%- for evttype, polarity, campain in datasets %}
+Lb2Lc3Pi_{{ evttype }}_{{ polarity }}_{{ campain }}:
+  application: DaVinci/v64r9
+  input:
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-{{ polarity }}/Real Data/Sprucing{{ campain }}/94000000/B2OC.DST"
+    dq_flags:
+      - OK
+      - UNCHECKED
+    keep_running: true
+    n_test_lfns: 1
+  output: DATA.ROOT
+  options:
+    entrypoint: Lb2Lc3Pi.Lb2Lc3Pi:main
+    extra_options:
+      input_raw_format: 0.5
+      input_type: ROOT
+      simulation: False
+      data_type: "Upgrade"
+      geometry_version: run3/2024.Q1.2-v00.00
+      conditions_version: master
+      input_process: "Spruce"
+      input_stream: "b2oc"
+{%- endfor %}
-- 
GitLab


From 13593fb6d3c5f98ea42528b8c9b7079d39d7c892 Mon Sep 17 00:00:00 2001
From: yangj <yangjiaqi23@mails.ucas.ac.cn>
Date: Fri, 22 Nov 2024 20:20:42 +0800
Subject: [PATCH 2/3] Update code

---
 Lb2Lc3Pi/Lb2Lc3Pi.py | 512 +++++++++++++++++++++++++------------------
 1 file changed, 296 insertions(+), 216 deletions(-)

diff --git a/Lb2Lc3Pi/Lb2Lc3Pi.py b/Lb2Lc3Pi/Lb2Lc3Pi.py
index 69d7114e43..431f7d253b 100644
--- a/Lb2Lc3Pi/Lb2Lc3Pi.py
+++ b/Lb2Lc3Pi/Lb2Lc3Pi.py
@@ -1,31 +1,271 @@
 import Functors as F
-import FunTuple.functorcollections as FC
-from FunTuple import  FunctorCollection, FunTuple_Particles as Funtuple
-from PyConf.reading import get_particles, get_pvs, get_rec_summary, get_odin
-from GaudiKernel.SystemOfUnits import GeV
-from Hlt2Conf.algorithms_thor import ParticleFilter
-from DaVinci.algorithms import create_lines_filter
-from DaVinci import Options, make_config
-from DaVinciMCTools import MCTruthAndBkgCat
-from DecayTreeFitter import DecayTreeFitter
-from Hlt2Conf.flavourTagging import run2_all_taggers
-# specific for the B2OC SigmaNet
 import Functors.math as fmath
-import os
+from DaVinci import Options, make_config
+from DaVinci.algorithms import create_lines_filter
+from PyConf.reading import get_particles, get_pvs
+from Functors.math import log
+from FunTuple import FunctorCollection, FunTuple_Particles as FunTuple
+from PyConf.application import metainfo_repos
+from FunTuple.functorcollections import DecayTreeFitterResults, Kinematics, ParticleID, EventInfo, HltTisTos, SelectionInfo
 
 
-def main(options: Options):
-    line_name = "SpruceB2OC_LbToLcpPiPiPi_LcpToPKPi"
-    line_data = get_particles(f"/Event/Spruce/{line_name}/Particles")
-    my_filter = create_lines_filter("Hlt2Line_Filter",
-                                    lines=[f"{line_name}"])
-    Hlt1_decisions = [
-        "Hlt1TrackMVADecision",
-        "Hlt1TwoTrackMVADecision",
-    ]
-    Hlt2_decisions = [
-                      'Hlt2Topo2BodyDecision',
-                      'Hlt2Topo3BodyDecision',]
+
+Hlt1_decisions = [
+    "Hlt1TrackMVA",
+    "Hlt1TwoTrackMVA",
+    "Hlt1TwoTrackMVACharmXSec",
+    "Hlt1TwoTrackKs",
+    "Hlt1KsToPiPi",
+    "Hlt1GECPassthrough"
+    'Hlt1D2KK',
+    'Hlt1D2KPi',
+    'Hlt1D2PiPi',
+    'Hlt1DiMuonHighMass',
+    'Hlt1DiMuonLowMass',
+    'Hlt1DiMuonSoft',
+    'Hlt1LowPtMuon',
+    'Hlt1LowPtDiMuon',
+    'Hlt1SingleHighPtMuon',
+    'Hlt1TrackMuonMVA'
+]
+
+Hlt2_decisions = [
+    "Hlt2Topo2Body","Hlt2Topo3Body","Hlt2Topo4Body"
+]
+
+
+def make_tistos_hlt1(data):
+    return HltTisTos(
+        selection_type="Hlt1",
+        trigger_lines=[
+            f"{x}Decision" for x in Hlt1_decisions if "GECPassthrough" not in x
+        ],
+        data=data,
+    )
+
+
+# Only for Sprucing -- needs to be reconfigured
+def make_tistos_hlt2(data):
+    return HltTisTos(
+        selection_type="Hlt2",
+        trigger_lines=[f"{x}Decision" for x in Hlt2_decisions],
+        data=data,
+    )
+
+
+def make_comp_variables(data):
+    v2_pvs = get_pvs()
+
+    variables = FunctorCollection({
+        "MAX_PT":
+        F.MAX(F.PT),
+        "MIN_PT":
+        F.MIN(F.PT),
+        "SUM_PT":
+        F.SUM(F.PT),
+        "MAX_P":
+        F.MAX(F.P),
+        "MIN_P":
+        F.MIN(F.P),
+        "BPVDIRA":
+        F.BPVDIRA(v2_pvs),
+        "BPVFDIR":
+        F.BPVFDIR(v2_pvs),
+        "CHI2VXNDOF":
+        F.CHI2DOF,
+        "BPVFDCHI2":
+        F.BPVFDCHI2(v2_pvs),
+        "BPVFD":
+        F.BPVFD(v2_pvs),
+        "BPVFDVEC":
+        F.BPVFDVEC(v2_pvs),
+        "BPVVDRHO":
+        F.BPVVDRHO(v2_pvs),
+        "BPVVDX":
+        F.BPVVDX(v2_pvs),
+        "BPVVDY":
+        F.BPVVDY(v2_pvs),
+        "BPVVDZ":
+        F.BPVVDZ(v2_pvs),
+        "BPVDLS":
+        F.BPVDLS(v2_pvs),
+        "BPVIPCHI2":
+        F.BPVIPCHI2(v2_pvs),
+        "BPVCORRM":
+        F.BPVCORRM(v2_pvs),
+        "BPVCORRMERR":
+        F.BPVCORRMERR(v2_pvs),
+        "BPVIP":
+        F.BPVIP(v2_pvs),
+        "LOGBPVIPCHI2":
+        log(F.BPVIPCHI2(v2_pvs)),
+        "BPVLTIME":
+        F.BPVLTIME(v2_pvs),
+        "MAX_BPVIPCHI2":
+        F.MAX(F.BPVIPCHI2(v2_pvs)),
+        "MIN_BPVIPCHI2":
+        F.MIN(F.BPVIPCHI2(v2_pvs)),
+        "MAXDOCACHI2":
+        F.MAXDOCACHI2,
+        "MAXDOCA":
+        F.MAXDOCA,
+        "MAXSDOCACHI2":
+        F.MAXSDOCACHI2,
+        "MAXSDOCA":
+        F.MAXSDOCA,
+        "MM12":
+        F.SUBCOMB(Functor=F.MASS, Indices=(1, 2)),
+        "MM13":
+        F.SUBCOMB(Functor=F.MASS, Indices=(1, 3)),
+        "ETA":
+        F.ETA,
+        "PHI":
+        F.PHI,
+        "END_VX":
+        F.END_VX,
+        "END_VY":
+        F.END_VY,
+        "END_VZ":
+        F.END_VZ,
+        "BPVX":
+        F.BPVX(v2_pvs),
+        "BPVY":
+        F.BPVY(v2_pvs),
+        "BPVZ":
+        F.BPVZ(v2_pvs),
+    })
+
+    variables += Kinematics()
+    variables += ParticleID(extra_info=True)
+    variables += make_tistos_hlt1(data)
+    variables += make_tistos_hlt2(data) #-- Only for Sprucing
+
+    return variables
+
+
+def make_basic_variables(data):
+    v2_pvs = get_pvs()
+
+    variables = FunctorCollection({
+        "TRCHI2DOF":
+        F.CHI2DOF,
+        "TRGHOSTPROB":
+        F.GHOSTPROB,
+        "BPVIPCHI2":
+        F.BPVIPCHI2(v2_pvs),
+        "PIDK":
+        F.PID_K,
+        "PIDe":
+        F.PID_E,
+        "PIDmu":
+        F.PID_MU,
+        "PIDp":
+        F.PID_P,
+        "ISMUON":
+        F.ISMUON,
+        "BPVIP":
+        F.BPVIP(v2_pvs),
+        "ETA":
+        F.ETA,
+        "PHI":
+        F.PHI,
+        #some track-related variables
+        "NDOF":
+        F.VALUE_OR(-1) @ F.NDOF @ F.TRACK,
+        "NFTHITS":
+        F.VALUE_OR(-1) @ F.NFTHITS @ F.TRACK,
+        "NHITS":
+        F.VALUE_OR(-1) @ F.NHITS @ F.TRACK,
+        "NUTHITS":
+        F.VALUE_OR(-1) @ F.NUTHITS @ F.TRACK,
+        "NVPHITS":
+        F.VALUE_OR(-1) @ F.NVPHITS @ F.TRACK,
+        "TRACKHASVELO":
+        F.VALUE_OR(-1) @ F.TRACKHASVELO @ F.TRACK,
+        "TRACKHISTORY":
+        F.VALUE_OR(-1) @ F.TRACKHISTORY @ F.TRACK,
+        "TRACKPT":
+        F.TRACK_PT,
+        "ISMUON":
+        F.ISMUON,
+        "INMUON":
+        F.INMUON,
+        "INECAL":
+        F.INECAL,
+        "INHCAL":
+        F.INHCAL,
+    })
+
+    variables += Kinematics()
+    variables += ParticleID(extra_info=True)
+    variables += make_tistos_hlt1(data)
+
+    return variables
+
+
+def make_hlt2_event_variables(line_name, line_data):
+    v2_pvs = get_pvs()
+
+    evt_variables = EventInfo()
+    evt_variables += SelectionInfo(
+        selection_type="Hlt1", trigger_lines=Hlt1_decisions)
+    evt_variables += SelectionInfo(
+        selection_type="Hlt2", trigger_lines=Hlt2_decisions)
+    evt_variables += FunctorCollection({
+        "NPV": F.SIZE(v2_pvs),
+        "ALLPVX[NPVs]": F.ALLPVX(v2_pvs),
+        "ALLPVY[NPVs]": F.ALLPVY(v2_pvs),
+        "ALLPVZ[NPVs]": F.ALLPVZ(v2_pvs),
+    })
+    return evt_variables
+
+
+def DecayTreeFitter(data,
+                    pv_fit=True,
+                    mass_fit=False,
+                    prefix="DTF",
+                    mass_constraints=[]):
+    from DecayTreeFitter import DecayTreeFitter
+    pvs = get_pvs()
+    variables = FunctorCollection()
+    variables += Kinematics()
+    if pv_fit:
+        DTF = DecayTreeFitter(
+            name='PV_Fit_{hash}',
+            input_particles=data,
+            input_pvs=pvs,
+        )
+        variables += DecayTreeFitterResults(
+            DTF=DTF,
+            prefix=prefix + "_PV_",
+            decay_origin=True,
+            with_lifetime=True,
+            with_kinematics=True)
+
+    if mass_fit:
+        DTFM_excl = DecayTreeFitter(
+            name='PVandMass_Fit_{hash}',
+            input_particles=data,
+            input_pvs=pvs,
+            mass_constraints=mass_constraints)
+        variables += DecayTreeFitterResults(
+            DTF=DTFM_excl,
+            prefix=prefix + "_PVandMass_",
+            decay_origin=True,
+            with_lifetime=True,
+            with_kinematics=True)
+
+    return variables
+
+def SpruceB2OC_LbToLcpPiPiPi_LcpToPKPi_Tuple():
+
+    ###################################################
+
+    spruce_line = "SpruceB2OC_LbToLcpPiPiPi_LcpToPKPi"
+
+    input_data = get_particles(f"/Event/Spruce/{spruce_line}/Particles")
+
+    evt_vars = make_hlt2_event_variables(spruce_line, line_data=input_data)
 
     fields = {
         'Lb': '[Lambda_b0 -> (Lambda_c+ -> p+ K- pi+) pi- pi+ pi-]CC',
@@ -38,204 +278,44 @@ def main(options: Options):
         'LcPi': '[Lambda_b0 -> (Lambda_c+ -> p+ K- ^pi+) pi- pi+ pi-]CC',
     }
 
-    pvs = get_pvs()
-
-    DTF_MassFitConsLc = DecayTreeFitter(
-        name="DTF_MassFitConsLc",
-        input_particles=line_data,
-        mass_constraints=["Lambda_c+"])
-
-    DTF_LifetimeFit = DecayTreeFitter(
-        name="DTF_LifetimeFit", input_particles=line_data, input_pvs=pvs)
-
-
-    # all_tagging = run2_all_taggers(line_data)
-
-    # define helper functors
-    get_child = F.CHILD(1, F.FORWARDARG0) # change here the index of the child
-    get_SV =  F.ENDVERTEX @ F.FORWARDARG0
-    get_SV_pos = F.TOLINALG @ F.POSITION @ get_SV # only if composite (i.e. has vertex)
-    get_child_endvtx_pos = F.ENDVERTEX_POS  @ get_child
-    get_fdvec_child = get_child_endvtx_pos - get_SV_pos
-
-    # define observables
-    IP_wrt_SV = F.IP.bind(get_SV_pos , get_child)
-    IPCHI2_wrt_SV = F.IPCHI2.bind(get_SV , get_child) # only if child is composite (i.e. has vertex)
-    FD_wrt_SV = F.MAGNITUDE @ get_fdvec_child
-    FDCHI2_wrt_SV = F.VTX_FDCHI2.bind(get_SV, get_child)
-
-    B_variables = FunctorCollection(
-        {
-        "ID": F.PARTICLE_ID,
-        "PT": F.PT,
-        "ETA": F.ETA,
-        "P": F.P,
-        "SUMPT": F.SUM(F.PT),
-        "MASS": F.MASS,
-        "BPVDIRA": F.BPVDIRA(pvs),
-        "CHI2DOF": F.CHI2DOF,
-        "BPVIPCHI2": F.BPVIPCHI2(pvs),
-        "BPVIP": F.BPVIP(pvs),
-        "BPVFDCHI2": F.BPVFDCHI2(pvs),
-        "BPVLTIME": F.BPVLTIME(pvs),
-        "BPVFD": F.BPVFD(pvs),
-        "BPVCHI2DOF": F.CHI2DOF @ F.BPV(pvs),
-        "IPCHI2_OWNPV": F.BPVIPCHI2(pvs),
-        "ENDVERTEX_CHI2": F.CHI2DOF,
-        "FDCHI2_OWNPV": F.BPVFDCHI2(pvs),
-        "DIRA_OWNPV": F.BPVDIRA(pvs),
-        "CHILD1_IPwrtSV": IP_wrt_SV,
-        "CHILD1_IPCHI2wrtSV": IPCHI2_wrt_SV,
-        "CHILD1_FDwrtSV": FD_wrt_SV,
-        "CHILD1_FDCHI2wrtSV": FDCHI2_wrt_SV,
-        "DTF_MassFitConsLc_MASS": DTF_MassFitConsLc(F.MASS),
-        "DTF_MassFitConsLc_CHI2DOF": DTF_MassFitConsLc(F.CHI2DOF), # track or vertex chi2/ndf
-        "DTF_MassFitConsLc_P": DTF_MassFitConsLc(F.P),
-        "DTF_LifetimeFit_MASS": DTF_LifetimeFit(F.MASS),
-        "DTF_LifetimeFit_CHI2DOF": DTF_LifetimeFit(F.CHI2DOF), # track or vertex chi2/ndf
-        "DTF_LifetimeFit_CTAU": DTF_LifetimeFit.CTAU,
-        "DTF_LifetimeFit_CTAUERR": DTF_LifetimeFit.CTAUERR,
-        "PX": F.PX,
-        "PY": F.PY,
-        "PZ": F.PZ,
-        "BPVX": F.BPVX(pvs),
-        "BPVY": F.BPVY(pvs),
-        "BPVZ": F.BPVZ(pvs),
-        "END_VX": F.END_VX,
-        "END_VY": F.END_VY,
-        "END_VZ": F.END_VZ,
-        "END_VCHI2DOF": F.CHI2DOF @ F.ENDVERTEX,
-        }
-    )
-    B_variables+=FC.HltTisTos(selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=line_data)
-    
-
-    C_variables = FunctorCollection(
-        {
-            "ID": F.PARTICLE_ID,
-            "PT": F.PT,
-            "ETA": F.ETA,
-            "P": F.P,
-            "SUMPT": F.SUM(F.PT),
-            "MASS": F.MASS,
-            "DOCA12": F.DOCA(1, 2),
-            "DOCA13": F.DOCA(1, 3),
-            "DOCA23": F.DOCA(2, 3),
-            "BPVDIRA": F.BPVDIRA(pvs),
-            "CHI2DOF": F.CHI2DOF,
-            "BPVIP": F.BPVIP(pvs),
-            "BPVIPCHI2": F.BPVIPCHI2(pvs),
-            "BPVFD": F.BPVFD(pvs),
-            "BPVFDCHI2": F.BPVFDCHI2(pvs),
-            "MINIPCHI2": F.MINIPCHI2(pvs),
-            "IPCHI2_OWNPV": F.BPVIPCHI2(pvs),
-            "ENDVERTEX_CHI2": F.CHI2DOF,
-            "FDCHI2_OWNPV": F.BPVFDCHI2(pvs),
-            "PX": F.PX,
-            "PY": F.PY,
-            "PZ": F.PZ,
-            "BPVX": F.BPVX(pvs),
-            "BPVY": F.BPVY(pvs),
-            "BPVZ": F.BPVZ(pvs),
-            "END_VX": F.END_VX,
-            "END_VY": F.END_VY,
-            "END_VZ": F.END_VZ,
-            "END_VCHI2DOF": F.CHI2DOF @ F.ENDVERTEX,
-        }
-    )
-
-    fs_variables = FunctorCollection(
-        {
-            "ID": F.PARTICLE_ID,
-            "PT": F.PT,
-            "ETA": F.ETA,
-            "PHI": F.PHI,
-            "P": F.P,
-            "MASS": F.MASS,
-            "CHI2DOF": F.CHI2DOF,
-            "MINIPCHI2": F.MINIPCHI2(pvs),
-            "BPVIPCHI2": F.BPVIPCHI2(pvs),
-            "IPCHI2_OWNPV": F.BPVIPCHI2(pvs),
-            "PX": F.PX,
-            "PY": F.PY,
-            "PZ": F.PZ,
-            "hasRICH": F.PPHASRICH() @ F.PROTOPARTICLE(),
-            "PIDK": F.PID_K,
-            "PIDp": F.PID_P,
-            "PIDe": F.PID_E,
-            "PIDmu": F.PID_MU,
-            "isMuon": F.ISMUON,
-            "TRACK_GhostProb": F.GHOSTPROB,
-            "ProbNNp": F.PROBNN_P,
-            "ProbNNk": F.PROBNN_K,
-            "ProbNNpi": F.PROBNN_PI,
-            "NHITS": F.VALUE_OR(-1) @ F.NHITS @ F.TRACK,
-            "NVPHITS": F.VALUE_OR(-1) @ F.NVPHITS @ F.TRACK, # VeloPixel hits
-            "NUTHITS": F.VALUE_OR(-1) @ F.NUTHITS @ F.TRACK, # UpstreamTracker hits
-            "NFTHITS": F.VALUE_OR(-1) @ F.NFTHITS @ F.TRACK, # ForwardTracker hits
-            "TRACKHASVELO": F.VALUE_OR(-1) @ F.TRACKHASVELO @ F.TRACK,
-        }
-    )
 
     variables = {
-        "Lb": B_variables,
-        "LbPi1": fs_variables,
-        "LbPi2": fs_variables,
-        "LbPi3": fs_variables,
-        "Lc": C_variables,
-        "LcP": fs_variables,
-        "LcK": fs_variables,
-        "LcPi": fs_variables,
+        "Lb":make_comp_variables(input_data) + DecayTreeFitter(input_data),
+        "LbPi1":make_basic_variables(input_data),
+        "LbPi2":make_basic_variables(input_data),
+        "LbPi3":make_basic_variables(input_data),
+        "Lc":make_comp_variables(input_data),
+        "LcP": make_basic_variables(input_data),
+        "LcK": make_basic_variables(input_data),
+        "LcPi": make_basic_variables(input_data),
     }
 
-    if options.simulation:
-        # get configured "MCTruthAndBkgCatAlg" algorithm for HLT2 output
-        mctruth = MCTruthAndBkgCat(line_data)
-        # add helper lambda that configures a functor to get truth information
-        MCTRUTH = lambda func: F.MAP_INPUT(Functor=func, Relations=mctruth.MCAssocTable)
-        trueid_bkgcat_info = {
-            # Important note: specify an invalid value for integer functors if there exists no truth info.
-            #                 The invalid value for floating point functors is set to nan.
-            "TRUEID": F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID),
-            "TRUEKEY": F.VALUE_OR(-1) @ MCTRUTH(F.OBJECT_KEY),
-            #
-            "TRUEPT": MCTRUTH(F.PT),
-            "TRUEPX": MCTRUTH(F.PX),
-            "TRUEPY": MCTRUTH(F.PY),
-            "TRUEPZ": MCTRUTH(F.PZ),
-            "TRUEENERGY": MCTRUTH(F.ENERGY),
-            "TRUEP": MCTRUTH(F.P),
-            "TRUEFOURMOMENTUM": MCTRUTH(F.FOURMOMENTUM),
-            "BKGCAT": F.BKGCAT(Relations=mctruth.BkgCatTable),
-        }
-        for field in variables.keys():
-            variables[field] += FunctorCollection(trueid_bkgcat_info)
-
-
-    odin = get_odin()
-    rec_summary = get_rec_summary()
-    # define event level variables
-    evt_variables = FunctorCollection({
-	"RUNNUMBER": F.RUNNUMBER(odin),
-	"EVENTNUMBER": F.EVENTNUMBER(odin),
-    "nVPClusters" : F.VALUE_OR(-1) @ F.RECSUMMARY_INFO( rec_summary, "nVPClusters"),
-    "nFTClusters" : F.VALUE_OR(-1) @ F.RECSUMMARY_INFO( rec_summary, "nFTClusters"),
-	"nPVs": F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nPVs"),
-	"nLongTracks": F.VALUE_OR(-1) @ F.RECSUMMARY_INFO(rec_summary, "nLongTracks"),
-    "nVeloTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_summary,"nVeloTracks"),
-    })
-    evt_variables+=FC.SelectionInfo(selection_type="Hlt1", trigger_lines=Hlt1_decisions)
-    evt_variables+=FC.SelectionInfo(selection_type="Hlt2", trigger_lines=Hlt2_decisions)
-
-    # define FunTuple instance
-    my_tuple = Funtuple(
+    my_tuple = FunTuple(
         name="Tuple",
         tuple_name="DecayTree",
+        inputs=input_data,
         fields=fields,
         variables=variables,
-        event_variables=evt_variables,
-        inputs=line_data,
-        store_multiple_cand_info=True,
-    )
+        event_variables=evt_vars)
+
+    my_filter = create_lines_filter(
+        name=f"HDRFilter_{spruce_line}", lines=[f'{spruce_line}'])
+
+    ###################################################
+
+    user_algorithms = {}
+    user_algorithms.update({"LbToLcpPiPiPi": [my_filter, my_tuple]})
+
+    return user_algorithms
+
+
+
+### CONFIG definition ###
+
+
+def main(options: Options):
+
+    all_user_algorithms = {}
+    all_user_algorithms.update(SpruceB2OC_LbToLcpPiPiPi_LcpToPKPi_Tuple())
 
-    return make_config(options, [my_filter, my_tuple])
\ No newline at end of file
+    return make_config(options, all_user_algorithms)
-- 
GitLab


From 8ea6f2758293c2baee2e9027d88aea61e58617cb Mon Sep 17 00:00:00 2001
From: yangj <yangjiaqi23@mails.ucas.ac.cn>
Date: Fri, 22 Nov 2024 22:38:57 +0800
Subject: [PATCH 3/3] Update info.yaml

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

diff --git a/Lb2Lc3Pi/info.yaml b/Lb2Lc3Pi/info.yaml
index bb44a70191..60163a1eba 100644
--- a/Lb2Lc3Pi/info.yaml
+++ b/Lb2Lc3Pi/info.yaml
@@ -20,7 +20,7 @@ defaults:
 Lb2Lc3Pi_{{ evttype }}_{{ polarity }}_{{ campain }}:
   application: DaVinci/v64r9
   input:
-    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-{{ polarity }}/Real Data/Sprucing{{ campain }}/94000000/B2OC.DST"
+    bk_query: "/LHCb/Collision24/Beam6800GeV-VeloClosed-{{ polarity }}/Real Data/Sprucing{{ campain }}/90000000/B2OC.DST"
     dq_flags:
       - OK
       - UNCHECKED
-- 
GitLab